この特集のトップページへ
Chapter 2:COMアーキテクチャの概要

見出し 2.2.4 CClassFactoryクラスの定義
 IClassFactoryインタフェースの定義をCDictionaryCOM.cppファイルに追加したら,次にIClassFactoryインタフェースを継承し,このインタフェースのメソッドを実装するためのCClassFactoryクラスを定義する(List 2-14Fig.2-14)。IClassFactoryインタフェースに宣言されるメソッドはCreateInstanceメソッドとLockServerメソッドの2つであるが,IClassFactoryインタフェースがIUnknownインタフェースを継承しているため,IUnknownインタフェースのメソッドであるQueryInterface,AddRef,Releaseという3つのメソッドも,CClassFactoryクラスを定義する際に宣言する必要がある。

Fig.2-14 CClassFactoryクラス
fig.2-14

●QueryInterfaceメソッドの実装

 CClassFactoryクラスの各メンバ関数を宣言したら,引き続きその実体を実装する。まずは,QueryInterfaceメソッドを実装する(List 2-15)。CClassFactoryクラスに実装するQueryInterfaceメソッドには,IID_IUnknownまたはIID_IClassFactoryというインタフェースIDを指定したときにIClassFactoryインタフェースへのポインタを返すことができるよう,次のような処理を準備する。

   if ( IsEqualIID(riid, IID_IUnknown) ||
        IsEqualIID(riid, IID_IClassFactory) )
           // IClassFactoryインタフェースのアドレスを
           // *ppvObjポインタに設定する
           *ppvObj = static_cast(this);

 そして,これ以外のインタフェースIDを指定したときには,当該インタフェースを見つけられなかったことを示すE_NOINTERFACEというエラーを返す。IID_IUnknownまたはIID_IClassFactoryのインタフェースIDが指定され,かつインタフェースへのアドレスを取得することに成功したら,AddRefメソッドを呼び出し,参照カウントを1つ増やす。以上がCClassFactoryクラスで実装すべきQueryInterfaceメソッドの概要である。

●AddRefメソッドの実装

 CClassFactoryクラスにQueryInterfaceメソッドを実装したら,続いてAddRefメソッドを実装する(List 2-16)。CClassFactoryクラスのAddRefメソッドも,CDictionaryクラスのAddRefメソッドと基本的に何も変わらない。参照カウントを1つ増やし,参照カウントを呼び出し元に返す処理を担うだけである。

●Releaseメソッドの実装

 CClassFactoryクラスのReleaseメソッドも,CDictionaryクラスで実装したReleaseメソッドと同じように実装する(List 2-17)。参照カウントを1つ減らし,参照カウントが0になったらCClassFactoryオブジェクトを破棄するようにすればよい。メソッドを終了するときには,参照カウントを呼び出し元に返すようにする。

●CreateInstanceメソッドの実装

 では,IClassFactoryインタフェースの一番重要なメソッドである,CreateInstanceメソッドを実装してみよう(List 2-18)。CreateInstanceメソッドは,まずCOMオブジェクトを生成し,QueryIntefaceメソッドを呼び出し,指定されたインタフェースIDと一致するインタフェースへのアドレスを取得する。

 C++アプリケーションでは,オブジェクトの生成にnewキーワードを使用する。しかし,COMオブジェクトを生成する場合は,CreateInstanceメソッドを呼び出し,COMオブジェクトを生成する。CreateInstanceメソッドの内部では,次のようにしてCOMオブジェクトを生成している。

   CDictionary *pCDictionary = new CDictionary;

 通常,C++アプリケーションでは,オブジェクトを生成するときに取得した*pCDictionaryポインタを保持しておき,オブジェクトが不要になった段階でこのポインタを使ってオブジェクトを破棄する。しかしCOMでは,参照カウントでCOMオブジェクトを管理しているため,このポインタを保持しておく必要がない。これはコンポーネントが自らを破棄するため,クライアントは明示的にCOMコンポーネントを破棄する必要はないことを意味する。

 COMオブジェクトの生成に成功したら,取得した*pCDictionaryポインタを通じてQueryInterfaceメソッドを呼び出す。QueryInterfaceメソッドでは,生成されたばかりのCOMオブジェクト(ここでは,CDictionaryオブジェクト)へのアドレスをppvObjポインタに返し,さらに参照カウントをインクリメントする。最終的に,CreateInstanceメソッドの第3引数で,呼び出し元にCOMオブジェクトのアドレスが戻されることになる。

●GetClassObject APIの実装

 GetClassObjectは,COM APIとして実装されていて,IClassFactoryインタフェースを継承したCClassFactoryオブジェクトを生成する機能を備えている。このAPIは,ATLやMFCを利用する限り自分で実装する必要はないが,COMアーキテクチャを理解するために必要となるため,ここでは実装してみることにする(List 2-19)。GetClassObject APIは,クラスファクトリを指す*pClassFactoryポインタを通じてQueryInterfaceメソッドを呼び出し,ppvObjポインタにインタフェースへのアドレスを返し,さらに参照カウントをインクリメントする。

 この説明からもわかるとおり,この処理は,先にIClassFactoryインタフェースで実装したCreateInstanceメソッドとよく似ている。自分自身のオブジェクトを生成し,生成に成功したらインタフェースへのアドレスを返し,参照カウントを増やしている。

   // ClassFactoryオブジェクトを生成する
   CClassFactory *pClassFactory = new CClassFactory;
prev Chapter 2 8/9 next