【问题标题】:Late Binding COM objects with C++Builder使用 C++Builder 后期绑定 COM 对象
【发布时间】:2012-07-25 02:11:40
【问题描述】:

我们正在与来自 C++Builder 2010 应用程序的一些第 3 方 COM 对象进行交互。

目前我们导入类型库并生成组件包装器,然后能够以相当自然的方式进行方法调用和访问属性。

object->myProperty = 42;
object->doSomething(666);

但是,COM 对象的接口(仍在扩展和开发中)的更改导致我们自己的应用程序失败,因为某些方法 GUID 似乎变得无效 - 即使对接口的唯一更改已经增加了一种新方法)。

已建议将后期绑定作为解决此问题的一种方式。我认为这需要更改我们的代码rather like this:

object.OlePropertySet("myProperty", 42);
object.OlePrcedure("doSomething", 666);

显然这读和写起来很痛苦,所以我们不得不编写包装类。

当我们导入类型库时,有没有办法让后期绑定包装器自动生成?而且,如果是这样,它们是否足够聪明,只在创建对象时执行一次文本绑定,而不是在每个方法调用时执行一次?

【问题讨论】:

    标签: c++ com c++builder late-binding


    【解决方案1】:

    当您为支持后期绑定的 COM 对象导入 TypeLibrary 时(当它实现 IDispatch 接口时),导入器可以为静态绑定和后期绑定生成单独的包装类(不是组件)。

    向现有接口添加新方法不应使您的代码无效。方法没有 GUID。但是,对于基于IDispatch 的接口,它的方法确实具有与之关联的DISPID 值,并且这些DISPID 值可以从一个版本更改为另一个版本。尽管一旦接口定义被锁定,任何受人尊敬的 COM 开发人员都不应该这样做。

    【讨论】:

    • 谢谢,你能举个例子说明我如何使用(或选择)后期绑定类吗?我目前正在使用 <libfile>_OCX.hpp 标头中的 T 对象。
    • 我认为 C++ 和 C++Builder 缺乏 Delphi 所具有的复杂的后期绑定特性,而这是 Delphi 编译器的一个特性。 (声明变体,调用 CreateOleObject,调用方法。)相反,您必须以艰难的方式去做。在C++中查找“OLE自动化”示例,技术和编码风格是相同的。
    • C++Builder 中的VariantOleVariant 类支持后期绑定操作,类似于Delphi 编译器本身支持的操作,就像Roddy 展示的那样,即:Delphi 中的object.myProperty := 42; 变为@987654329 C++ 中的@,Delphi 中的object.doSomething(666); 变成C++ 中的object.OleProcedure("doSomething", 666);,等等
    • @RemyLebeau - 使用IxxxDisp 包装器添加了一个答案,它提供了基于 DISPID 的绑定。
    【解决方案2】:

    在对 TLIBIMP 生成的代码和标头进行深入调查后,结果证明这相当容易。

    如果您的类型库有一个类Foo,那么在导入类型库后,您通常会使用自动生成的智能指针类IFooPtr

    {
      IFooPtr f;
      ...
      f->myMethod(1,2);
    }
    

    您应该注意,此时绑定是静态的 - 也就是说,它们不仅取决于对象的 GUID 和方法的 DISPID,还取决于 DLL 中 VTable 的确切布局。任何影响 vtable 的更改 - 例如,向 Foo 的基类添加额外的方法将导致方法调用失败。

    要使用动态绑定,您可以使用IFooDisp 类而不是IFooPtr。同样,这些是智能包装器,自动处理对象生命周期。请注意,对于这些类,您应该使用 . 运算符来访问方法,而不是间接 -> 运算符。使用间接运算符将调用方法,但通过静态绑定。

    {
      IFooDisp f;
      ...
      f.myMethod(1,2);
    }
    

    通过使用这些基于IDispatch 的包装器,方法将由它们的 DISPID 分派,即使对象 vtable 布局已更改。我认为这些类还提供了一种通过函数名而不是 DISPID 进行调度的方法,但尚未确认详细信息。

    【讨论】:

    • 注意:接口一旦发布就会被“冻结”,即给定的 IID 对应于给定的 vtable,故事结束。因此客户端使用 vtable 绑定是安全的。如果您想添加新成员,您应该从该接口派生。
    • 另外(无论如何对于 DAX),f.myMethod 使用带有硬编码 DISPID 的 IDispatch::Invokef->myMethod 使用 vtable。
    • @MattMcNabb 感谢 DAX 提示。 BCB2010 不使用这个,尽管 AFAIK。而且,是的,在理想世界中,界面会被冻结。可悲的是,我似乎没有居住。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    • 1970-01-01
    • 1970-01-01
    • 2011-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多