資料公開: わんくまT93 COM入門

2014/12/06 わんくま同盟東京勉強会 #93 で
「COM入門」 というタイトルでセッションを行いました

資料&サンプルコード
http://1drv.ms/1v3MecF

セッションで話し忘れてたこと等

  • GUIDはIID,CLSIDを表現するために生まれた
  • インターフェイスの実態は一定の条件を満たしたメモリブロック
    C++の継承じゃなくても条件を満たした方法であれば実装可能
    (純粋抽象クラスからの派生=仮想関数テーブルとほぼ同じ構造)
カテゴリー: その他, C++, COM, 勉強会 | タグ: , , , | コメントする

COMメモ12 COMライブラリの初期化

初期化 CoInitialize(void* reserved);
終了 CoUninitialize();

カテゴリー: その他, C++, COM | タグ: , , , , | コメントする

COMメモ11 DLLに必要な関数

  • STDAPI DllGetClassObject(婚stCLSID& clsid, const IiD& iid, void **ppv)
    • CLSIDを引数にとりクラスファクトリへのインターフェイスを返す。
  • STDAPI DllCanUnloadNow()
    • DLLをアンロードできる状態かを問い合わせる。
    • コンポーネントのコンストラクタ、デストラクタで参照カウントの操作を行いコンポーネントが使用されていないときのみUnloadできるようにする。
  • STDAPI DllRegisterServer()
    • COM登録用のコマンド? “REGSERVER32.EXE DLL名” 実行時に呼び出される
    • レジストリ関係のAPIを使ってコンポーネントをレジストリに登録するコードを記述する。
  • STDAPI DllUnregisterServer()
    • COM登録解除用コマンド “REGSERVER32.EXE /u DLL名” で呼び出される
    • レジストリからCOMコンポーネントを削除するコードを記述する
カテゴリー: その他, C++, COM | タグ: , , , , , , , | コメントする

COMメモ10 インスタンス生成まとめ

1. クライアント COMライブラリ関数 CoCreateInstance() 実行開始
2. COMライブラリ関数 CoGetClassObject()実行開始
3. CoGetClassObject() CLSIDをキーにレジストリからDLLを探してロード
3. CoGetClassObject() DLL内関数 DllGetClassObject()実行開始
4. DllGetClassObject() 内でCLSIDに応じたクラスファクトリインスタンスを作成
5. DllGetClassObject() 作成したクラスファクトリをIClassFactoryへのポインタとして返し終了
6. CoGetClassObject() IClassFactoryへのポインタを返し終了
7. CoCreateInstance() IClassFactory::CreateInstance()を呼び出す
8. IClassFactory::CreateInstance() コンポーネントのインスタンスを作成
9.IClassFactory::CreateInstance() コンポーネントをインターフェイスへのポインタとして返して終了
10.IClassFactory::Release() クラスファクトリを解放
11.CoCreateInstance() インターフェイスへのポインタを返し終了
12. インスタンス生成完了
※ CoCreateInstance()を使わずに直接CoGetClassObject()を使ってもよい。

カテゴリー: その他, C++, COM | タグ: , , , , , , , | コメントする

COMメモ9 インスタンスの生成

// Ole32.dll   Objbase.h
   HRESULT __stdcall CoCreateInstance(
      const CLSID& rclsid,
      IUnknown* pUnkOuter,
      DWORD dwClsContext,
      const IID& riid,
      void**  * ppv
    );
    CoCreateInstance

  • CLSIDを受け取り対応するコンポーネントのインスタンスを作成、そのインターフェースを返す関数
  • 内部でクラスファクトリ(IClassFactory)を呼び出している
  • CLSID:コンポーネントの識別子、レジストリでCLSIDからDLLのファイルパスを取得できるようになっている。
  • pUnkOuter:実装に集約という手法を用いる場合に使う、使わない場合はNULL
  • ClsContext:コンポーネントの実行場所をフラグで設定 クライアントと同じプロセス(DLL)/別のプロセス(.exe)/別マシン(DCOM)
  • riid 返されるインターフェイスのIID
  • ppv:インターフェイスへのポインタを受け取る変数
    クラスファクトリ

  • 他のコンポーネントを作成するためのコンポーネント
  • IClassFactoryを実装
  • CoGetClassObject(CLSID)でIClassFactoryインターフェイスを取得する。
  • 1CLSIDにつき1クラスファクトリ
  • 対応するコンポーネントを含むDllに自分で実装
interface IClassFactory :IUnknown
{
    HRESULT __stdcall CreateInstance(IUnknown * pUnknownOuter, const IID& iid, void **ppv);
    HRESULT __stdcall LockServer(BOOL block)
}

HRESULT __stdcall CoGetClassObject(
    const CLSID& clsid,
    DWORD dwClsContext,
    COSERVERINFO* pServerInfo,
    const IID& iid,
    void** ppv
    );
    CoGetClassObject

  • CLSIDを受け取り、対応するコンポーネントを生成するクラスファクトリのインターフェイスへのポインタを返す。
  • DLLGetClassObject()を呼び出す。
  • COSERVERINFO:DCOM(≒リモートPC上にコンポーネントがある場合)のアクセス制御に用いる

STDAPI DllGetClassObject(
    const CLSID& clsid,
    const IID& iid,
    void** ppv
    );
    DllGetClassObject

  • CLSIDを受け取り、対応するコンポーネントを生成するクラスファクトリのインターフェイスへのポインタを返す。
  • コンポーネントを含むDLLに自分で実装する。
カテゴリー: その他, C++, COM | タグ: , , , , , , , | コメントする

COMメモ8 参照カウント

  • 取得するインターフェイスが増えると、どのポインタがどのインスタンスなのかわからりずらくなり、解放制御が難しくなる
  • インターフェイスのごとに参照カウントを行うことで安全に使い終わったタイミングで解放できる
  • WinAPIのInterlockedIncrement,InterlockedDecrementで実装されることが多い(スレッドセーフ)
    操作規則

  • インターフェイスを返す関数から戻る前にAddRef
  • インターフェイスを使い終わったらRelease
  • インターフェイスへのポインタへ代入した後はAddRef
カテゴリー: その他, C++, COM | タグ: , , | コメントする

COM メモ7 QueryInterfaceの規則

  • 必ず一定のIUnknownが得られる
    • 非仮想多重継承なのでIUnknownが複数あるけど返すのは常に同じインターフェイス
    • IUnknownのアドレスを比較することで同じコンポーネントかどうか調べることが出来る。
  • 前に取得したことがあるインターフェイスは取得できる
  • 保持しているインターフェイスは取得できる
  • 要求を開始した元のインターフェイスに必ず戻ることができる
  • あるインターフェイスから取得できればどのインターフェイスからも取得できる
カテゴリー: その他, C++, COM | タグ: , , | コメントする