Problem using unmanaged C ++ from C # using dllimport

I am having problems importing an unmanaged C ++ dll into C # [winform]. Can anyone help?

Basically, I'm just trying to create a saferyray 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 get an exception when I call GetStringArr from C #. I'm sure there is something stupid that I do. Can anybody help?

Thanks in advance.

0
c ++ c # dllimport
source share
4 answers

A few problems in your C ++ code. You are returning an array for which the argument must be SAFEARRAY **. You also stuff the array with invalid data, you created an array of strings, but you write VARIANT. Not sure what this intent is, I will save the options 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); 
+1
source share

Some problems on both the C side and the .NET side.

Side C

  • Wrong argument argumentation. Since you are highlighting the SAFEARRAY handle in a function, you need SAFEARRAY **.
  • SAFEARRAY is not filling correctly. You created a SAFEARRAY handle with the base type VT_BSTR, which means that the data items must be BSTR.

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 side of .NET

  • You must specify a calling convention, otherwise you will have problems with the stack.
  • You must install SafeArraySubType
  • You can use out string[] to get a pointer to 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); } 
+1
source share

Do you have access to the source DLL source? If so, you can enable unmanaged debugging in your Managed Projects options and run unmanaged code (preferably the Debug build) to see what happens. If you cannot enable Exceptions in the debugger options and debug to see where your own exception is thrown.

0
source share

I recommend that you add a C ++ / CLI project (assembly) to your C # solution. This will allow you to simultaneously write code that lives on both managed and unmanaged land. This means that your C ++ / CLI code can create instead of List<string^> and add managed strings to it before you return it to C #. :-)

0
source share

All Articles