通过interop将字符串数组从C#传递给C ++

时间:2014-05-28 03:07:15

标签: c# c++ string com interop

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

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

C#interop接口定义:

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#应用​​程序中解决这个问题。有人能给我指路吗?我非常感激。

2 个答案:

答案 0 :(得分:0)

方法签名不应该是

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

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

C#中的数组行为与C / C ++中的数组不同;你不能只是传递对第一个元素的引用,并希望能够使用指针算法访问其余的元素。

编辑:您可能不需要ref关键字。

答案 1 :(得分:0)

您可能需要编组为适当的类型,以便在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导入通常用于调用win api