DLLとEXEの違いでも説明したように、
Apartmentを超えた通信を行う場合はCOMが仲介し、
プロセス超えの呼び出しや、
複数スレッドによる同時呼び出し問題の解決を行っています。
このとき、COMはproxyとstubを使っています。
proxyとstubは、通常のCOMと同じように、DLLサーバとして実装します。
通常のCOMでは、coclassごとに持つCLSIDを与えて作成します。
proxyやstubの場合はinterfaceごとに実装されているため、
IIDからCLSIDを特定したうえで、そのcoclassを作成します。
通常のCOMサーバでは、次のレジストリエントリを作成し、ここに必要な情報を登録します。
64bitアプリケーションでは、
32bitの設定はHKEY_CLASSES_ROOT\ではなくHKEY_CLASSES_ROOT\Wow6432Node\に見えます。
HKEY_CLASSES_ROOT\CLSID\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
<名前なし> <コクラス名>
AppID {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
InprocServer32\
<名前なし> <読み込むべきdllの名前>
ThreadingModel 対応するApartmentの種類
LocalServer32\
<名前なし> <実行すべきexeの名前>
ProgID\
<名前なし> <ProgID名>
HKEY_CLASSES_ROOT\AppID\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
DllSurrogate <空、または実行ファイルのパス>
proxyとstubの場合は、CLSIDとIIDの対応付けのために、
通常のCOMサーバに加えて、レジストリに次のエントリを登録します。
呼び出し側がSTAとは限りませんので、ThreadingModelはbothにする必要があります。
常にDLLサーバとして使われるため、DllSurrogateは使いません。
HKEY_CLASSES_ROOT\Interface\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
<名前なし> <インターフェース名>
ProxyStubClsId32\
<名前なし> {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
CoCreateInstance()やQueryInterface()が呼び出され、
proxy/stub通信が必要なインターフェースがCOMシステムに要求されると、
COMシステムはIIDから作成すべきコクラスのCLSIDを特定し、
そのコクラスを作成します。コクラスはDLLサーバでなければなりません。
proxyとstubを提供するDLLサーバは、
IClassFactoryではなくIPSFactoryBufferと呼ばれるインターフェースを実装します。
IPSFactoryBufferは、
proxy(IRpcProxyBuffer)やstub(IRpcStubBuffer)を作成するためのインターフェースです。
proxyはメソッド呼び出しをCOM提供のバッファに変換する機能、
stubはCOM提供のバッファに書かれた内容をメソッド呼び出しに変換する機能を実装します。
COMシステムは、proxyやstubとの通信用データのやりとりに使うIRpcChannelBufferを用意し、
Apartment間の通信はCOMシステムが行います。
用意すべきもの
インターフェースに対するproxyやstubは、
システムに用意されていれば自分で用意する必要はありません。
例えば、オートメーション(IDispatch)を使っているなら、
Apartment間の通信はシステムに実装されたIDispatchが使われます。
しかし、自分で定義したインターフェースでは、
COMシステムはメソッド呼び出しをApartment間の通信に変換する方法を知りません。
この場合、proxyとstubは自分で用意する必要があります。
proxyとstubのDLLサーバを自分で実装するのは大変です。
しかし、midlコンパイラには、引数に制限はあるものの、
インターフェースを定義した.idlファイルから、
ThreadingModelがbothのproxyとstubを自動生成する機能があります。
C++のインターフェースを使いたい場合は、
midlの機能でproxyとstubを生成させると良いでしょう。
目次
COM/ActiveXの解説ページ 目次
仕組み
インターフェースの定義
ビルド