通过互操作将字符串数组从c#传递到c++

本文关键字:c++ 数组 互操作 字符串 | 更新日期: 2023-09-27 18:05:23

我有一个用c++编写的COM组件,我想通过互操作在我的c#应用程序中调用它的接口。

我要调用的接口定义如下:

c#互操作接口定义:
void ICertainInterface.Func(int cnt, ref string colors)

c++定义:

ICertainInterface : IUnknown
{
    virtual HRESULT Func(long cnt, BSTR * colors) = 0;
}

这对我来说很清楚,接口是我的应用程序期望的具有特定长度的BSTR数组。第二个参数BSTR * colors应该代表字符串数组中的第一个字符串地址。

下面是我用来从c#应用程序中调用接口的代码:
ICertainInterface obj = GetInterface();
string[] strArray = new string[4];
strArray[0] = "aaa";
strArray[1] = "bbb";
strArray[2] = "ccc";
strArray[3] = "ddd";
obj.Func(4, ref strArray[0]);

一旦我运行应用程序,错误给出"试图读写受保护的内存"。如果数组大小仅为1,则不会发生这种情况。在我看来,因为字符串数组是c#中的托管数据。所以内存分配是不可预测的,一旦我传递strArray[0]作为对c++接口的引用,接口将把它作为数组的起始地址,并假设add by 4将获得下一个元素的地址,但这在c#内存分配中不能以相同的方式进行。

我从网上搜索了一些帖子,似乎大多数接口用户"ref string[]"作为指向c#数组的指针,但不像这个"ref string",我只能引用数组中的第一个元素(我甚至不知道它是否是正确的方法,因为在c++中,第一个元素地址相当于数组地址。

进一步,我在excel VBA代码中做了相同的测试,调用相同的接口:

Dim msColor(4) As String
msColor(0) = "aaa"
msColor(1) = "bbb"
msColor(2) = "ccc"
msColor(3) = "ddd"
Dim obj as ICertainInterface 
Set obj = GetInterface();
Call obj.Func(4, msColor(0))

这个VBA代码工作完美,没有任何错误。

现在我完全不知道如何在我的c#应用程序中修复这个问题。谁能给我指条路吗?非常感谢。

通过互操作将字符串数组从c#传递到c++

方法签名不应该是

void ICertainInterface.Func(int cnt, ref string[] colors)

…不是传递数组中的第一个元素,而是传递整个数组?

c#中的

数组不像C/c++中的数组;不能只传递对第一个元素的引用,就期望能够使用指针算术方法访问其余元素。

编辑:你可能也不需要ref关键字在那里。

为了在CLR和非CLR进程之间传递,您可能需要封送为适当的类型这是正确的签名

所以如果你想传递一个字符串,那么

void ICertainInterface.Func(int cnt,[MarshalAs(UnmanagedType.BStr)] ref string colors)

或者如果是数组,那么

void ICertainInterface.Func(int cnt,[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_BSTR)] ref string[] colors)

我根据你的代码做了这个解决方案。如果上面的解决方案不适合你,那么你可以尝试找到适合你的应用程序的合适的数组类型/子类型http://msdn.microsoft.com/en-us/library/z6cfh6e6(v=vs.110).aspx和字符串类型http://msdn.microsoft.com/en-us/library/s9ts558h(v=vs.110).aspx

使用DllImport属性的例子

如果你想传递一个字符串,那么

[DllImport("yourLib.dll", EntryPoint = "Func")]
public static extern void ICertainInterface.Func(int cnt,[MarshalAs(UnmanagedType.BStr)] ref string colors)

如果是数组,则

[DllImport("yourLib.dll", EntryPoint = "Func")]
public static extern void ICertainInterface.Func(int cnt,[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_BSTR)] ref string[] colors)

这可能会帮助你实现相同的,Dll导入通常用于调用winapi