Entering Passive Mode

カテゴリ 'COM' の記事
< 1 2 3 4 5 6 7 >

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 演算子を使うことはできない。

DLL の初期化とグローバル変数

昨日未解決にしていた DLL のハンドルは、
どこから取ってくることができるのか。

インプロセスサーバに限らず、一般的な Windows DLL には、
DllMain という初期化用関数がある。
この関数は DLL の実装者が用意するもので、
プロトタイプは以下の通りだ。

BOOL WINAPI DllMain(HINSTANCE hinstDLL,
        DWORD fdwReason, LPVOID lpvReserved);

HardLinkIconID クラス

昨日作ったアイコンを使って、
ハードリンク用のアイコンを表すクラスを作ってみる。

クラス名は「HardLinkIconID」とする。
IUnknown の基準実装は、Object クラスから継承しよう。
まずは、クラスの定義を作成する。

========== HardLinkIconID.hpp ==========

#ifndef hardlinkiconid_hpp_included
#define hardlinkiconid_hpp_included

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