我正在调用一个外部提供的COM DLL,我为此生成了一个COM互操作包装器。为了论证,让我们调用我想要调用IEnumFoo
的接口。
IEnumFoo
具有典型的COM枚举器模式:
HRESULT Next (
ULONG celt,
IFoo** rgelt,
ULONG* pceltFetched
);
其中第一个参数是所需结果的数量,第二个参数是写入结果的缓冲区,最后一个参数描述实际写入的结果数。
当我选择“添加引用”并将Visual Studio指向此DLL时,它会生成一个带有以下签名的COM Interop程序集:
void Next(uint, out IFoo, out uint)
这只允许.NET代码一次请求一个对象,这可能会增加使用这些API的大量开销。
我是否可以使用某种机制来生成Next
的版本,这样我可以提供更多IFoo
个“插槽”,以便让编组人员满意? (我不反对在互操作程序集中编辑IL :))
答案 0 :(得分:4)
适当的签名就像这样:
void Next(
uint celt,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IFoo[] rgelt,
out uint pceltFetched);
根据MSDN,至少,没有机制自动生成它。即使接口的原始IDL已length_is
应用于rgelt
,该信息也会在类型库中丢失。因此,您需要手动编辑互操作程序集。
另一个选择是在主程序集中完全手动定义此特定接口,并忽略生成的互操作版本。请记住,在RCW上进行强制转换时,任何具有匹配GUID的接口(即QueryInterface成功的接口)都可以工作,因此您实际上可以使用多个不同的托管接口来呈现同一COM接口的不同视图。
答案 1 :(得分:2)
不回答您的问题,而是建议尝试不同的方法。我将创建一个C ++ / CLI包装器,通过COM接口枚举非托管代码(从而避免编组开销),然后构建一个托管List
或其他容器,在其中返回对象。
这几乎可以保证比手动调整互操作程序集的IL更容易,您也可以轻松调试它。非托管C ++代码将非常简单,就像围绕它的托管包装器一样。
答案 2 :(得分:1)
如果实现此接口的对象是本机的,那么只需在代码中重新定义接口,确保在接口上使用相同的ComImport和Guid属性。然后获取对象并转换为您的界面。您可以通过该界面进行调用。
请记住:互操作程序集不是魔术,您可以随时手动定义接口。