Com C++;互操作:在UDT中嵌入数组

Com C++;互操作:在UDT中嵌入数组,com,interop,visual-studio-2005,Com,Interop,Visual Studio 2005,我有一个应用程序,它涉及托管(C#)和非托管(C++)代码之间的大量通信。我们使用的是VisualStudio2005(!),我们使用由tlbimp自动生成的互操作程序集 我们很幸运地将简单结构作为函数参数来回传递。由于我们的对象相当简单,我们可以使用IRecordInfo接口将它们打包到安全阵列中。将这些数组作为参数传递给COM方法似乎工作正常 我们希望能够在UDT中嵌入可变长度数组,但这失败得很严重。我想我找不到一份文件来说明某人是如何做到这一点的。我也没有找到文件说这是不可能做到的 1)

我有一个应用程序,它涉及托管(C#)和非托管(C++)代码之间的大量通信。我们使用的是VisualStudio2005(!),我们使用由tlbimp自动生成的互操作程序集

我们很幸运地将简单结构作为函数参数来回传递。由于我们的对象相当简单,我们可以使用IRecordInfo接口将它们打包到安全阵列中。将这些数组作为参数传递给COM方法似乎工作正常

我们希望能够在UDT中嵌入可变长度数组,但这失败得很严重。我想我找不到一份文件来说明某人是如何做到这一点的。我也没有找到文件说这是不可能做到的

1) 天真的方法:只需在托管代码中声明一个safearray:

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复制的。使用该代码创建safearray,然后:

pVal->m3.vt = VT_SAFEARRAY | VT_RECORD;
pval->parray = p;
以奇怪的方式失败。它总是会中断,某些变体会产生OutOFMemoryException。。。奇怪的是,其他人以不同的方式失败。(我不确定这里是否需要pRecInfo指针,但它以同样的方式失败,无论是否存在。)

这方面的谷歌搜索空间受到了严重的污染,我没有提出以下问题:

  • 如何从非托管代码传递UDT/结构
  • 如何传递结构的安全数组?(我们做得很好。)
  • 如何使用p/invoke或客户编组来传递UDT
还有许多答案描述了如何从托管端而不是非托管端定义事物

还有一些微软知识库描述了早期版本的.NET中VT_记录的问题。我不认为这些是密切相关的-VT_记录类型与VARIANT和SAFEARRAY一起工作。(但可能不是UDT编组…)

如果这不起作用,至少知道原因会很好

  • 标记

CLR互操作层是否本机支持VT_记录?我找不到任何参考,无法找到自动生成的互操作程序集的引用。如果UDT的安全数组使用IRecordInfo接口填充了VT_记录,则可以从非托管代码返回到托管代码。我们使用这些作为输出参数,从来没有遇到过任何问题,所以我认为它真的、真的工作并得到支持。据我所知,不支持简单变体中的VT_记录。我对它进行了快速的尝试,并验证了它不适合我们的开发环境。微软关于这一问题的错误报告发布在.NET1.1上,但似乎仍然是真的:错误:COM互操作:没有VT_记录类型的内置支持变体我已经从VT_记录中获得了太多的战斗创伤来回答这个问题,我学会了像很久以前的瘟疫一样避免它们。您可以将任何结构转换为COM接口,使每个字段成为属性。这样从来都不是问题。@HansPassant:你确实可以把任何结构转换成COM接口,但是,真的,拿一个漂亮的、轻量级的POD来给它加上那么多废话是很烦人的。自动生成的互操作程序集的存在只是为了避免这种想法。也就是说,你的观点被采纳了。