1

我想在 MIDL 中声明一个允许返回指针的 COM 接口(如在 中ID3D11Blob)。我知道指针在 COM 中是一个特殊的东西,因为为 RPC 调用生成了存根。我不需要 RPC,但只想从 C# 访问 COM 服务器。问题是:我可以以 C# 存根返回的方式声明接口IntPtr吗?我试图添加[local]以启用void指针,但这还不够。

界面应该类似于 MIDL

[local] void *PeekData(void)

并且在 C# 中

IntPtr PeekData()

这可能吗?如果是这样,怎么做?

在此先感谢,克里斯托夫

编辑:改写问题:为什么是

HRESULT GetData([in, out, size_is(*size)] BYTE data[], [in, out] ULONG *size);

变得

void GetData(ref byte, ref uint)

以及如何避免第一个参数byte在 C# 中成为单个参数?

4

2 回答 2

3

这是错误的,因为您从类型库中导入了 COM 服务器声明。类型库最初旨在支持 COM 的一个子集,最初称为“OLE 自动化”。这限制了可用于方法参数的类型。特别是,不允许使用原始指针。数组必须声明为 SAFEARRAY。这确保调用者始终可以安全地索引数组,安全数组具有额外的元数据,用于描述数组的等级和下限/上限。

[size_is] 属性只有 MIDL 才能理解,它用于为接口创建代理和存根。当需要将数组复制到通过线路发送到存根的互操作数据包中时,了解数组包含多少元素也很重要。

由于类型库不支持这样的声明,因此 [size_is] 属性被剥离并且类型库导入器只能看到 BYTE*。这是模棱两可的,可以是通过引用传递的字节,也可以是指向字节数组的指针。导入器选择前者,因为它没有希望使数组工作,它不知道数组的大小。所以你得到ref byte.

要解决此问题,您必须更改导入库,以便提供正确的方法声明。这需要 [MarshalAs] 属性将 byte[] 参数声明为具有 SizeParamIndex 属性集的 LPArray,以便您可以告诉 CLR 数组大小由size参数确定。有两种基本方法可以解决:

  • 用 ildasm.exe 反编译互操作库,修改 .il 文件并与 ilasm.exe 一起放回原处。您将使用通过 ildasm.exe 查看的示例 C# 声明来了解如何编辑 IL。这是Microsoft 推荐的方法。

  • 使用可以将 IL 反编译回 C# 的良好反编译器。Reflector 和 ILSpy 很受欢迎。将生成的代码复制/粘贴到项目的源文件中并编辑方法,应用 [MarshalAs] 属性。优点是编辑更容易,您不再依赖互操作库。

在任何一种情况下,您都希望确保 COM 服务器是稳定的,因此您不必经常这样做。如果不是,则强烈建议修改服务器本身,请使用安全数组。

于 2013-11-28T13:01:24.510 回答
0

I think I found the solution on http://msdn.microsoft.com/en-gb/library/z6cfh6e6(v=vs.110).aspx#cpcondefaultmarshalingforarraysanchor2: This is the default behaviour for C-style arrays. One can avoid that by using SAFEARRAYs.

于 2013-11-28T12:48:06.267 回答