将委托传递给一个需要int数组指针委托方法的非托管方法

4
我正在开发一款使用未托管dll的C#应用程序,其中一个方法需要将函数指针作为其参数之一。由于我无法访问未托管dll的实际C++源代码,因此我只能依靠我从使用相同dll的C++示例中得到的代码片段。我的问题是,我创建的委托无法传递到未托管方法中。
以下是我尝试使用的DllImport方法,它接受我创建的委托:
[DllImport("pos_tk.dll")]
static internal extern ErrorCode AddSIGHandle([MarshalAs(UnmanagedType.FunctionPtr)] SIG_Callback func);

这是我目前拥有的委托签名:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void SIG_Callback ([MarshalAs(UnmanagedType.LPArray)] ref int[] buf, int rev, object sender);

这是C++示例片段中使用的函数,我基于它创建了我的代理:

void __stdcall point_handle (int *buf, int rev, LPVOID pParam)

现在,在你建议我将委托的ref int[] buf参数更改为ref int buf之前,一旦尝试回调,程序将抛出InvalidVariant错误。代码片段使用大小为revint *buf数组。

使用上面的代码,当尝试回调时,应用程序会抛出AccessViolationException。我的预感是,我应该为ref int[] buf参数使用不同的类型,但我已经尝试了我能想到的所有方法。我还一整天在Google、SO和MSDN上搜索,但没有找到任何线索。

有人有什么想法吗?

最后提一下,这是否与您可以将StringBuilder用作参数的方式类似,通过一个接受char*参数以检索可变长度字符串的非托管方法?

1个回答

4
传递数组总是很麻烦...尝试使用这种签名,它似乎适用:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void point_handle(
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
    int[] buf,
    int rev,
    IntPtr pParam);

编辑:进一步解释,当您拥有一个“C样式”数组(即T*)以及在参数中指定长度时,SizeParamIndex是您的救星;基本上它表示:“嘿,有一个未知长度的数组进来了,但是此索引处的参数将告诉您其中有多少个。使用该参数和类型来帮助编组"


我不得不看两遍。到底是谁把数组大小叫做“rev”?? - Hans Passant
@HansPassant 哈哈,是啊,如果没有他的额外评论,我也猜不到。 - JerKimball
1
这太棒了。非常感谢!另外,我也不知道为什么他们把那个参数称为“rev”。从我查看的C++示例代码中,很明显它是数组的大小,但我没有理由在发布之前不更改它。 - LamdaComplex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接