Com 理解C++;生成器xxx_TLB.h文件

Com 理解C++;生成器xxx_TLB.h文件,com,activex,c++builder,Com,Activex,C++builder,我已经使用c++Builder 2010(组件/导入组件/类型库向导)导入了一个类型库,并试图理解生成的xxx_TLB.b和xxx_OCX.h文件中定义的类和类型。(这个问题的一些背景知识-我正试图让我的COM对象和方法按名称绑定,而不是按DISPID-) 假设库包含一个类Foo,我将获得以下guid const GUID IID_IFoo = {0xF1EC45FE, 0x2540, 0x4188,{ 0xAE, 0x14, 0xD8,0x4F, 0x65, 0x6F,0x7A, 0x00}

我已经使用c++Builder 2010(组件/导入组件/类型库向导)导入了一个类型库,并试图理解生成的xxx_TLB.b和xxx_OCX.h文件中定义的类和类型。(这个问题的一些背景知识-我正试图让我的COM对象和方法按名称绑定,而不是按DISPID-)

假设库包含一个类Foo,我将获得以下guid

const GUID IID_IFoo = {0xF1EC45FE, 0x2540, 0x4188,{ 0xAE, 0x14, 0xD8,0x4F, 0x65, 0x6F,0x7A, 0x00} };
const GUID CLSID_Foo = {0xDD1C416D, 0xD8A2, 0x4BBC,{ 0x8E, 0xA8, 0x1A,0x10, 0x77, 0xA4,0x30, 0x0C} };
这对我来说是有道理的。也会生成FooEvents,但我现在将忽略它。我还得到了以下接口和typedef,每个方法有两个版本——一个是“原始”的,另一个是更友好的包装,隐藏
HRESULTS

interface DECLSPEC_UUID("{F1EC45FE-2540-4188-AE14-D84F656F7A00}") IFoo;
typedef TComInterface<IFoo, &IID_IFoo> IFooPtr;

interface IFoo  : public IDispatch 
{
  virtual HRESULT STDMETHODCALLTYPE get_Bar(BSTR* Value/*[out,retval]*/) = 0; // [201]
  ...
  BSTR __fastcall get_Bar(void)
  {
    BSTR Value = 0;
    OLECHECK(this->get_Bar((BSTR*)&Value));
    return Value;
  }
}
因此,对于Foo类型的对象,我似乎有四个不同的类来表示它-我应该使用哪一个,何时使用

  IFooPtr f;
  IFooDisp f;
  TCOMIFoo f;
  TFoo *f;
最后,对于
IFooDisp f
我似乎可以通过
f->Bar()
f.Bar()
调用
Bar()
——它们的工作原理相同,还是有细微的区别

因此,对于Foo类型的对象,我似乎有四个不同的类来表示它

TComInterface
是一个包装类,用于为您管理接口指针的引用计数,非常类似于ATL的
CComPtr
CComQIPtr
类。这样,您就不必手动调用
AddRef()
Release()

TCOMIFoo
包装器基本上只是
TComInterface
的一个typedef,尽管它也被同一文件中创建的
TCoClassCreator
派生类使用

TAutoDriver
是一个包装类,用于处理
IDispatch
和后期绑定(按名称绑定成员需要)

TOleServer
是一个包装类,用于将COM对象公开为VCL组件,尤其是在设计时可以将其放置在
TForm
TFrame
TDataModule
对象上

我应该使用哪一个,何时使用

  IFooPtr f;
  IFooDisp f;
  TCOMIFoo f;
  TFoo *f;
我从未在代码中使用过
TAutoDriver
wrappers,也没有在设计时使用COM对象(因为如果未安装COM对象,它们不允许您执行运行时错误处理)。对于大多数代码,我会坚持使用
IFooPtr
TCOMIFoo
,它们基本上是一样的

最后,对于IFooDisp f;似乎我可以通过f->Bar()和f.Bar()调用Bar()-它们的工作原理相同,还是有细微的区别

有一个微妙的区别

f->Bar()

f.Bar()

通常,通过
->
操作符调用的任何方法都将直接调用原始接口,通过
操作符调用的任何方法都将调用包装器方法

另一个细微的区别是
Bar()
返回了一个接口指针。使用
->
运算符,您必须对生成的指针进行自己的引用计数,例如:

ISomeIntf i;
if (SUCCEEDED(f->Bar(&i)))
{
    ...
    i->Release();
}
除非您使用
TComInterface
变量来接收它:

TComInterface<ISomeIntf> i; // or ISomeIntfPtr
if (SUCCEEDED(f->Bar(&i)))
{
    ...
    // Release()'d automatically
}
与:

f.SomeIntf.OtherIntf.DoSomething();

似乎您不仅要求使用COM服务器,而且还要求实现它。也许在巫师队迷路了?IFooPtr是使用COM服务器所需要的一切。@HansPassant-Heh。上面的输出完全来自使用导入类型库向导生成的_TLB.h和_OCX.h。我唯一勾选的选项是“生成组件包装”-错了吗?谢谢。这无疑为我指明了正确的方向。对于基于名称的绑定,我将不得不进一步探索TAutoDriver,看看是否能找到一个好的示例。
TComInterface<ISomeIntf> i; // or ISomeIntfPtr
if (SUCCEEDED(f->get_SomeIntf(&i)))
{
    TComInterface<IOtherIntf> j; // or IOtherIntfPtr
    if (SUCCEEDED(i->get_OtherIntf(&j)))
    {
        j->DoSomething();
    }
}
f.SomeIntf.OtherIntf.DoSomething();