3

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を取得し、各メソッドの2つのバージョンを使用します。「raw」バージョンと、よりわかりやすいラッパーを非表示にするバージョンです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;
  }
}

ここで、私を超えたものに行き着きます。基本的に同じ機能を公開しているが、異なる2つの追加クラスです。

template <class T /* IFoo*/ >
class TCOMIFooT : public TComInterface<IFoo>, public TComInterfaceBase<IUnknown>
{
... again, two versions of each method are provided.
}
typedef TCOMIFooT<IFoo> TCOMIFoo;

template<class T>
class IFooDispT : public TAutoDriver<IFoo>
{
... again, two more versions of each method are provided.
}
typedef IFooDispT<IFoo> IFooDisp;

そしてそれはさらに悪化します:xxx_OCX.hファイルでこの追加のクラスを見つけます:-

class PACKAGE TFoo : public Oleserver::TOleServer
{
  IFooPtr m_DefaultIntf;
  _di_IUnknown __fastcall GetDunk();
public:
  ... this tim, just one version of each method
}

したがって、タイプFooのオブジェクトの場合、それを表すために4つの異なるクラスがあるようです。どのクラスをいつ使用する必要がありますか?

  IFooPtr f;
  IFooDisp f;
  TCOMIFoo f;
  TFoo *f;

そして最後に、私はどちらかを介してIFooDisp f;呼び出すことができるようです-それらは同じように機能しますか、それとも微妙な違いがありますか?Bar()f->Bar()f.Bar()

4

1 に答える 1

3

したがって、Foo型のオブジェクトの場合、それを表すために4つの異なるクラスがあるようです。

TComInterfaceCComPtrは、ATLやクラスと同様に、インターフェイスポインタの参照カウントを管理するためのラッパークラスですCComQIPtrAddRef()このように、Release()手動で呼び出す必要はありません。

ラッパーは基本的にはのTCOMIFootypedefですが、同じファイルで作成された派生クラスでTComInterface<IFoo>も使用されます。TCoClassCreator

TAutoDriverIDispatch処理および遅延バインディング(名前でメンバーをバインドするために必要)のラッパークラスです。

TOleServerは、COMオブジェクトをVCLコンポーネントとして公開するためのラッパークラスです。特に、設計時に、、、およびオブジェクトにTForm配置TFrameできます。TDataModule

どれをいつ使用する必要がありますか?

コードでラッパーを使用TAutoDriverしたことはなく、設計時にCOMオブジェクトを使用しません(COMオブジェクトがインストールされていない場合、ラッパーを使用すると実行時のエラー処理を実行できません)。IFooPtrほとんどのコードでは、またはに固執しTCOMIFooます。これらは基本的に同じものです。

そして最後に、IFooDispfの場合。f-> Bar()とf.Bar()のいずれかを介してBar()を呼び出すことができるようです-それらは同じように機能しますか、それとも微妙な違いがありますか?

微妙な違いがあります。

f->Bar()メソッドを直接呼び出すためIFoo::Bar()、独自のHRESULTチェックを行う必要があります。これにより、エラーが発生した場合の対処方法を決定できます。

f.Bar()ラッパーIFooDisp::Bar()メソッドを呼び出します。ラッパーメソッドはメソッドを呼び出してIFoo::Bar()チェックHRESULTを行い、エラーが発生した場合は例外を発生させます。

一般に、演算子を介して呼び出されるメソッドは->すべてrawインターフェースを直接呼び出し、.演算子を介して呼び出されるメソッドはラッパーメソッドを呼び出します。

もう1つの微妙な違いはBar()、インターフェイスポインタが返された場合です。演算子を使用する->と、結果のポインターを頼りに独自の参照を行う必要があります。例:

ISomeIntf i;
if (SUCCEEDED(f->Bar(&i)))
{
    ...
    i->Release();
}

TComInterface変数を使用して受信しない限り、次のようになります。

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

代わりに演算子を使用する.と、ラッパーは通常TComInterface、生のインターフェイスポインターの代わりにを返します。これは、インターフェイスがチェーンされている場合、...を返すインターフェイスを返すインターフェイスを取得する場合などに特に便利です。演算子の使用->はより柔軟ですが、演算子を使用するほどクリーンではありません.。例:

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();
于 2012-12-21T00:13:23.153 に答える