Entering Passive Mode

2006-11 - カテゴリ 'COM' の記事
< 1 2 3 >

レジストリへの登録

ハードリンク

COM サーバをレジストリに登録し、
実際にアイコンが表示されるかどうか試してみよう。

レジストリへの登録内容は昨日書いたとおりだが、
登録は COM クラス単位で行うので、
複数の COM クラスを提供するサーバの場合、
その数だけ登録する必要がある。

本来はプログラムから登録を行うのだが、
この時点ではまだ動作確認だけでよいので、
レジストリへの登録や登録解除は、
レジストリファイルを使うことにしよう。

スレッディングモデル

インプロセスサーバの DLL が完成しても、
そのままでは COM 基盤はその存在を知る事ができない。
そこで、COM 基盤からサーバを呼び出せるように、
レジストリに情報を登録する必要がある。

COM クラスの情報は、HKEY_CLASSES_ROOT\CLSID の配下の、
{クラス ID} のキーに格納する。
キーのデフォルト値には、クラスの説明文字列を入れる。
これは人間が利用するための情報であり、必須ではない。

インプロセスサーバを登録する場合は、
更に InProcServer32 というサブキーを作成し
キーのデフォルト値に、DLL のファイル名を入れる。
これで、COM クラスと提供サーバの関連付けが行われるのだ。

DllGetClassObject の実装

さて、やっと DllGetClassObject を実装する準備が整った。

現時点で公開するクラスは HardLinkIconID だけであり、
DllGetClassObject は CLSID_HardLinkIconID に対応して、
HardLinkIconIDClass クラスオブジェクトを返すことになる。

今回はクラスオブジェクトを static として確保しておき、
常にそれを返すようにすることにしよう。
ま、単純なシングルトンということで。

========== library.cpp ==========

クラス ID の割り当て

guidgen

クラスオブジェクトが完成した。
これをクライアントに公開するためには、
クラスに一意のクラス ID を割り当てる必要がある。

これは、guidgen などのコマンドを使えば生成できる。
プログラム的に作成したい場合は、
CoCreateGuid API を呼び出しても取得できる。

guidgen を使った場合は、生成した ID を
C++ のソースに書ける形でクリップボードにコピーできる。

多重継承の問題点

HardLinkIconID のインスタンスの作成ができないのは、
HardLinkIconID の定義が完全でないため、
具象クラスになることができないのが理由である。

では、何が不足しているのか。

HardLinkIconID は、IShellIconOverlayIdentifier と、
Object の 2 つを継承した、多重継承クラスである。
IShellIconOverlayIdentifier は IUnknown を、
Object も IUnknown を継承しているので、
HardLinkIconID の逆継承木を書くと以下のようになる。

HardLinkIconIDClass クラス

HardLinkIconID クラスをクライアントに公開するためには、
専用のクラスオブジェクトを作成する必要がある。

クラスオブジェクトには、IClassFactory を実装する。
パフォーマンスを考え、クラスオブジェクトは
簡単なシングルトンとして作成し、
1 つのインスタンスが常に存在するようにしておこう。

そのため、クラスオブジェクトに対しては、
参照カウンタを使った生存管理は必要ない。
そのため、Object クラスは継承させないことにする。

DllCanUnloadNow への対応

DllCanUnloadNow に対応するには、
サーバ単位でインスタンスの参照を数えておく必要がある。

参照の確認には、AddRef と Release が使われるが、
これはインスタンス自身の生存期間の管理だけでなく、
それを含むサーバの生存期間の管理も必要となるのだ。

そのためには、サーバのロックカウントを用意し、
AddRef, Release で増減してやる必要がある。
ここでは、単純にグローバル変数としておこう。
例によって、global.hpp に宣言しておく。

IClassFactory インタフェース

クラスオブジェクトは、その一般的な機能を提供するために、
IClassFactory インタフェースを実装することが推奨される。

IClassFactory の定義を以下に示す。

class IClassFactory : public IUnknown {

public:

    virtual HRESULT STDMETHODCALLTYPE CreateInstance(
            /* [in] */ IUnknown* pUnkOuter,
            /* [in] */ REFIID riid,
            /* [out] */ void** ppvObject) = 0;

サーバから見たインスタンスの作成

インプロセスサーバがクラスを提供するためには、
DLL に DllGetClassObject 関数を実装する必要がある。
この関数は以下のようなプロトタイプを持っている。

STDAPI DllGetClassObject(
        /* [in] */ REFCLSID rclsid,
        /* [in] */ REFIID riid,
        /* [out] */ void** ppvObject);

rclsid はクラスの ID、riid はインタフェースの ID、
そして、ppvObject にはクラスのインスタンスを返す。

クライアントから見たインスタンスの作成

これまでは、COM クラスの実装や利用について書いていたが、
肝心のインスタンスの作成に関しては説明していなかった。

COM クライアントが COM クラスを利用するためには、
既存のインスタンスを取得するか、
新しいインスタンスを作成する必要がある。
一般的には後者の方が良く使われる。

COM はクライアントサーバシステムであるため、
クライアントがクラスのインスタンスを作成する際には、
C++ 固有の new 演算子を使うことはできない。

< 1 2 3 >
このページのトップへ戻る
© 2008 Project Loafer/Project Fireball and all blog writers. Powered by Nucleus CMS