【问题标题】:What's the proper way of calling COM enumerators in .NET?在 .NET 中调用 COM 枚举器的正确方法是什么?
【发布时间】:2014-04-10 00:57:48
【问题描述】:

我正在调用一个外部提供的 COM DLL,为此我生成了一个 COM 互操作包装器。为了论证起见,让我们调用我要调用的接口IEnumFoo

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

HRESULT Next ( 
   ULONG        celt,
   IFoo**       rgelt,
   ULONG*       pceltFetched
);

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

当我选择“添加引用”并将 Visual Studio 指向此 DLL 时,它会生成具有以下签名的 COM 互操作程序集:

void Next(uint, out IFoo, out uint)

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

是否有某种机制我可以用来生成Next 的版本,它可以让我在上面提供更多IFoo“插槽”,这会让封送器高兴? (我不反对在互操作程序集中手动编辑 IL :))

【问题讨论】:

    标签: c# c++ .net com com-interop


    【解决方案1】:

    正确的签名应该是这样的:

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

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

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

    【讨论】:

    • 我肯定会去编辑 IL,因为在类型库中重新定义一个接口可能是一项艰巨的任务,因为交叉引用“雪球效应”。您最终可能会重新定义整个库。请注意,诸如 mono cecil (mono-project.com/Cecil) 之类的工具对于调整已编译的程序集非常有用。
    • 看起来可行:) (关于“记住:”的评论相同——假设我知道我在做什么:P)
    【解决方案2】:

    不回答您的问题,而是建议尝试不同的方法。我会创建一个 C++/CLI 包装器来枚举非托管代码中的 COM 接口(从而避免编组开销),然后构建一个托管的 List 或其他您返回对象的容器。

    这几乎可以保证比手动调整互操作程序集的 IL 更容易,并且您也可以轻松调试它。非托管 C++ 代码将相当简单,就像围绕它的托管包装器一样。

    【讨论】:

    • 目前在 C++/CLI 中围绕这个库编写 shim 是不可行的。 (虽然这是将来要考虑的事情)
    • @BillyONEal 您不必为整个库执行此操作 - 您可以仅为枚举器编写它。您只需要传递对象实例、枚举器,然后包装器就会返回一个托管列表。对于所有其他任务,您仍然可以使用生成的互操作程序集。
    • 好的,这很有趣(+1)。仍然想寻找一种避免 C++/CLI 的解决方案,但这是一个选择。 (需要弄清楚如何从 C++/CLI 创建一个 .NET COM RCW :) 如果我也走那条路)
    【解决方案3】:

    如果实现此接口的对象是本机对象,则只需在代码中重新定义接口,确保在接口上使用相同的 ComImport 和 Guid 属性。然后将对象转换为您的界面。你可以通过那个接口调用就好了。

    请记住:互操作程序集并不神奇,您始终可以手动定义接口。

    【讨论】:

    • “记住:”子句假定读者对互操作的工作原理有任何真正的了解。这张海报没有:) 谢谢!
    • 或者它可以成为新认识的基础。 ;-)
    猜你喜欢
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多