我有一个应用程序涉及托管(C#)和非托管(C++)代码之间的大量通信。我们使用的是 Visual Studio 2005 (!),并且我们使用 tlbimp 自动生成的互操作程序集。
我们很幸运地将简单的结构体作为函数参数来回传递。由于我们的对象相当简单,我们可以使用 IRecordInfo 接口将它们打包到 SAFEARRAY 中。将这些数组作为参数传递给 COM 方法似乎可以正常工作。
我们希望能够在我们的 UDT 中嵌入可变长度数组,但这很失败。我认为我无法找到一份文档来说明某人是如何做到这一点的。我也没有找到说明无法完成的文档。
1)天真的方法:只需在托管代码中声明一个安全数组:
struct MyUdt {
int member1;
BSTR member2;
SAFEARRAY *m3;
};
C++ 编译器对此很满意,但是生成的 IDL 混淆了 tblimp.exe。它报告它无法转换成员 m3 的签名和成员 tagSAFEARRAY.rgsabound 的签名。这些只是警告,但它们很有意义,生成的程序集不可用。
奇怪的是,使用 LPSAFEARRAY 以不同的方式失败,但出于同样的原因,tblimp 无法处理它。
2)棘手:将其打包成一个变体:
struct MyUdt {
int member1;
BSTR member2;
VARIANT m3;
};
我们有构建 UDT 安全数组的代码,它从来没有给我们带来任何麻烦。它基本上是从 MSDN 复制的。使用该代码创建一个安全数组,然后:
pVal->m3.vt = VT_SAFEARRAY | VT_RECORD;
pval->parray = p;
以奇怪的方式失败。它总是会中断,一些变化会产生 OutOFMemoryException ......奇怪,其他的以不同的方式失败。(我不确定此处是否需要 pRecInfo 指针,但无论是否存在,它都会以同样的方式失败。)
谷歌搜索空间被我没有问的问题的答案严重污染:
- 如何从非托管代码传递 UDT/结构。
- 你如何传递一个 SAFEARRAY 结构?(我们做得很好。)
- 您如何使用 p/invoke 或客户编组来传递 UDT。
许多答案描述了如何从托管方面定义事物,而不是非托管方面。
然后有几个 Microsoft KB 描述了 .NET 早期版本中的 VT_RECORD 问题。我不认为这些是密切相关的——VT_RECORD 类型与 VARIANT 和 SAFEARRAY 一起使用。(但也许不是 UDT 编组......)
如果这永远行不通,那么至少知道为什么会很好。
- 标记