问题
i am having trouble importing c++ unmanaged dll into C# [winform]. Can someone help?
Basically i am just trying to create a safearray of strings in c++ and trying to send it to C#.
Here is my c++ code.
extern "C" __declspec(dllexport) BOOL GetStringArr(SAFEARRAY* arr)
{
SAFEARRAY* myArray;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = 5;
myArray = SafeArrayCreate(VT_BSTR, 1, rgsabound);
VARIANT* pvData = (VARIANT*)(myArray->pvData);
pvData[0].vt = VT_BSTR;
pvData[0].bstrVal = SysAllocString(L"FirstString");
pvData[1].vt = VT_BSTR;
pvData[1].bstrVal = SysAllocString(L"SecondString");
pvData[2].vt = VT_BSTR;
pvData[2].bstrVal = SysAllocString(L"ThirdString");
pvData[3].vt = VT_BSTR;
pvData[3].bstrVal = SysAllocString(L"FourthString");
pvData[4].vt = VT_BSTR;
pvData[4].bstrVal = SysAllocString(L"FifthString");
arr = myArray;
return true;
}
Here is my c# code.
[DllImport("MyData.dll", EntryPoint = "GetStringArr")]
public static extern bool GetStringArr([MarshalAs(UnmanagedType.SafeArray)] out Array strServerList);
i am getting exception when i call GetStringArr from C#. i am sure there is something silly i am doing. Can someone please help?
Thanks in advance.
回答1:
Several problems in your C++ code. You are returning an array, that requires the argument to be SAFEARRAY**. You also are stuffing the array with the wrong data, you created an array of strings but you are writing VARIANTs. Not sure what the intention was, I'll keep variants in the code fix:
extern "C" __declspec(dllexport) BOOL GetStringArr(SAFEARRAY** arr)
{
SAFEARRAY* myArray;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = 5;
myArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
VARIANT* pvData = 0;
SafeArrayAccessData(myArray, (void**)&pvData);
pvData[0].vt = VT_BSTR;
pvData[0].bstrVal = SysAllocString(L"FirstString");
// etc..
SafeArrayUnaccessData(myArray);
*arr = myArray;
return true;
}
C# code:
object[] array;
bool ok = GetStringArr(out array);
[DllImport(@"blah.dll", EntryPoint = "GetStringArr")]
[return: MarshalAs(UnmanagedType.U1)]
public static extern bool GetStringArr([MarshalAs(UnmanagedType.SafeArray)] out object[] strServerList);
回答2:
Some problems on both the C and .NET side of things
On the C side
- Incorrect argument indirection. Since you are allocating the SAFEARRAY descriptor in the function you need a SAFEARRAY**.
- The SAFEARRAY is not being filled correctly. You created the SAFEARRAY descriptor with a base type of VT_BSTR, this means that the data elements should be BSTRs.
C Code
extern "C" __declspec(dllexport)
BOOL GetStringArr(SAFEARRAY** arr)
{
SAFEARRAY* myArray;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = 5;
myArray = SafeArrayCreate(VT_BSTR, 1, rgsabound);
BSTR* pvData = (BSTR*)(myArray->pvData);
pvData[0] = SysAllocString(L"FirstString");
pvData[1] = SysAllocString(L"SecondString");
pvData[2] = SysAllocString(L"ThirdString");
pvData[3] = SysAllocString(L"FourthString");
pvData[4] = SysAllocString(L"FifthString");
*arr = myArray;
return true;
}
On the .NET side
- The Calling convention needs to be specified otherwise you will have stack issues
- You should set the SafeArraySubType
- You can use
out string[]
to get the pointer to the SAFEARRAY
.NET Code
class Program
{
static void Main(string[] args)
{
string[] data;
bool b = GetStringArr(out data);
}
[DllImport("MyData.dll",
CallingConvention = CallingConvention.Cdecl)]
public static extern bool GetStringArr(
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR)]
out string[] strServerList);
}
回答3:
Do you have access to the native DLL's source? If so you can enable unmanaged debugging in your Managed projects options, and step thru the unmanaged code (preferably Debug build) to see what's going on. If nothing else you can enable Exceptions in the debugger options, and debug to see where the native exception gets thrown.
回答4:
I recommend you add a C++/CLI project (assembly) to your C# solution. That will enable you to write code that live in both managed and unmanaged land simultaneously. That means that your C++/CLI code can create a List<string^>
instead and add managed strings to it before you return it to C#. :-)
来源:https://stackoverflow.com/questions/3659139/trouble-using-unmanaged-c-from-c-sharp-using-dllimport