繁体   English   中英

使用dllimport从C#使用非托管C ++时遇到麻烦

[英]trouble using unmanaged c++ from c# using dllimport

我在将C ++非托管DLL导入C#[winform]时遇到问题。 有人可以帮忙吗?

基本上我只是想在c ++中创建一个字符串安全数组,然后尝试将其发送到C#。

这是我的c ++代码。

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;
}

这是我的C#代码。

[DllImport("MyData.dll", EntryPoint = "GetStringArr")]
public static extern bool GetStringArr([MarshalAs(UnmanagedType.SafeArray)] out Array strServerList); 

我从C#调用GetStringArr时遇到异常。 我确定我在做些傻事。 有人可以帮忙吗?

提前致谢。

C ++代码中的几个问题。 您正在返回一个数组,该数组要求参数为SAFEARRAY **。 您还用错误的数据填充了数组,创建了字符串数组,但是正在编写VARIANT。 不知道目的是什么,我将在代码修复中保留变体:

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#代码:

        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); 

C和.NET方面的一些问题

在C端

  1. 不正确的参数间接定向。 由于您要在函数中分配SAFEARRAY描述符,因此需要SAFEARRAY **。
  2. SAFEARRAY未正确填充。 您创建的SAFEARRAY描述符的基本类型为VT_BSTR,这意味着数据元素应为BSTR。

C代码

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; 
}

在.NET方面

  1. 需要指定调用约定,否则您将遇到堆栈问题
  2. 您应该设置SafeArraySubType
  3. 您可以使用out string[]获取指向SAFEARRAY的指针

.NET代码

  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);    
  }

您可以访问本机DLL的源吗? 如果是这样,您可以在“托管项目”选项中启用非托管调试,然后遍历非托管代码(最好是Debug build)以查看发生了什么。 如果没有其他要求,则可以在调试器选项中启用“异常”,然后进行调试以查看将本地异常抛出到何处。

我建议您将C ++ / CLI项目(程序集)添加到C#解决方案中。 这样一来,您就可以同时编写托管和非托管领域中的代码。 这意味着您的C ++ / CLI代码可以代替创建List<string^>并向其中添加托管字符串,然后再将其返回给C#。 :-)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM