在.NET中调用COM枚举器的正确方法是什么?

Bil*_*eal 5 .net c# c++ com com-interop

我正在调用一个外部提供的COM DLL,我已经生成了一个COM互操作包装器.为了争论,让我们调用我想要调用的接口IEnumFoo.

IEnumFoo 具有典型的COM枚举器模式:

HRESULT Next ( 
   ULONG        celt,
   IFoo**       rgelt,
   ULONG*       pceltFetched
);
Run Code Online (Sandbox Code Playgroud)

其中第一个参数是所需结果的数量,第二个参数是写入结果的缓冲区,最后一个参数描述实际写入的结果数.

当我选择"添加引用"并指向此DLL的Visual Studio时,它会生成一个带有以下签名的COM Interop程序集:

void Next(uint, out IFoo, out uint)
Run Code Online (Sandbox Code Playgroud)

这只允许.NET代码一次请求一个对象,这可能会增加使用这些API的大量开销.

是否有一些机制我可以用来生成一个版本,Next允许我提供更多的IFoo"插槽",这将使编组人员高兴?(我不反对在互操作程序集中编辑IL :))

Pav*_*aev 4

正确的签名如下:

void Next(
    uint celt,
    [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IFoo[] rgelt,
    out uint pceltFetched);
Run Code Online (Sandbox Code Playgroud)

至少根据 MSDN 的说法,没有机制可以自动生成它。即使接口的原始 IDL 已length_is应用于rgelt,该信息也会在类型库中丢失。因此,您需要手动编辑互操作程序集。

另一种选择是在主程序集中完全手动定义此特定接口,并忽略生成的互操作版本。请记住,在 RCW 上进行强制转换时,任何具有匹配 GUID 的接口(即 QueryInterface 成功的接口)都可以工作,因此您实际上可以拥有多个不同的托管接口,这些接口呈现同一 COM 接口的不同视图。