trouble using unmanaged c++ from c# using dllimport

故事扮演 提交于 2020-01-25 21:40:41

问题


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

  1. Incorrect argument indirection. Since you are allocating the SAFEARRAY descriptor in the function you need a SAFEARRAY**.
  2. 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

  1. The Calling convention needs to be specified otherwise you will have stack issues
  2. You should set the SafeArraySubType
  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!