giplip
Don Boxのgiplipの利用方法
必須条件:NT4SP3以降
なぜ必要か?
STA間のマーシャリング
FreeThreadMarshallerを実装したBothが内包するSTAオブジェクト
長いAPIとWindowsメッセージのLPARAM
CoMarshalInterThreadInterfaceInStream? を使ってマーシャルしたポインタをWindowsメッセージのLPARAM(WPARAMでも可)に設定して利用予定のスレッドへ送り込む。
もちろん、グローバル変数を利用しても良い。グローバル変数を利用しても、ポインタはアトミックなアクセスができるので、NULLかまたは有効となる。しかし、Windowsメッセージを使えば、利用可能となった状態の通知を兼ねることができる。
マーシャルされたポインタを取得するためにはCoGetInterfaceAndReleaseStreamを呼び出す。グローバル変数を利用する場合の問題点は、スレッドが3個以上の場合他のスレッドによって無効化されたポインタを拾ってしまう可能性がある点である。
利用方法
入手方法
http://www.develop.com/essentialcom/sources/git.htm
使わない方法
上のリンクがリンク切れになったので、入手できなくなった。
直接IGlobalInterfaceTableを使えば良い。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms678517(v=vs.85).aspx
IGlobalInterfaceTableの使い方
IGlobalInterfaceTableの利用方法は以下の手順となる。
- IGlobalInterfaceTableのインスタンスを保持する。
- RegisterInterfaceInGlobalを呼び出してポインタを登録しクッキーを得る。
- GetInterfaceFromGlobalへクッキーを与えてマーシャルされたポインタを得る。
- RevokeInterfaceFromGlobalへクッキーを与えて登録を解除する。
- Releaseする。
グローバル変数(static含む)またはコンポーネントのインスタンス変数に定義する。
IGlobalInterfaceTable GlobalTable(NULL); DWORD FooCookie(0);
FinalConstructで取得するのが望ましい。
HRESULT hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (LPVOID*)&GlobalTable); if (hr != S_OK) { 起きない }
スレッド境界をまたがって利用されるポインタを登録する。
HRESULT STDMETHOD RegisterFoo(IFoo* pFoo) { HRESULT hr = GlobalTable->RegisterInterfaceInGlobal(pFoo, IID_IFoo, &FooCookie); if (hr != S_OK) { IFooがスレッド境界を越えられない場合エラーとなる return hr; } // この例ではINパラメータなのでリリースしてはならないが、 // 自分でインスタンス化したコンポーネントなどであれば // GlobalTableが保持するのでリリースする。 // pFoo->Release(); return S_OK; }
利用時
IFoo* foo(NULL); HRESULT hr = GlobalTable->GetInterfaceFromGlobal(FooCookie, IID_IFoo, (LPVOID*)&foo); if (hr != S_OK) { Regisiterできたポインタは取得可能。つまり起きない } foo->Release(); // 終ったらリリース要
テーブルから削除(すでに元のpFooはリリース済みなので以後利用できなくなる)
GlobalTable->RevokeInterfaceFromGlobal(FooCookie);
利用が終わったらGlobalInterfaceTableをリリースする(終了時(ATLクラスであればFinalReleaseのタイミングが良い)
GlobalTable->Release(); GlobalTable = NULL;
Keyword(s):[IGlobalInterfaceTable]
References: