2006 年 11 月 10 日 23 時 56 分

シェルエクステンションと COM サーバ


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


シェルエクステンションは、以前に取り上げたが、
そのときは、C# を使って高水準のプログラミングを行った。
今回は C++ を使い、COM の低水準の実装を考えることにしよう。

以前は、COM の解説をすっ飛ばして実装に行ったが、
今回はゆっくりと進めることにする。

シェルエクステンションは、主に DLL として実装され、
COM の規約に基づいてオブジェクトを提供する。
エクスプローラは、それを利用する側となる。

これは、高水準言語におけるフレームワークや
クラスライブラリに似ているが、少し違う。

クラスライブラリのプログラムコードは、
それを利用するプログラムと一緒にロードされる。
結果的に同じプロセス内のコードとして実行されるため、
利用するプログラムの一部であるかのように振舞う。

COM は、クラスライブラリと同じような使い方もできるが、
分散環境でも利用できるような能力も持っているため、
本質的には、COM オブジェクトを提供する側をサーバ、
COM オブジェクトを利用する側をクライアントとする、
クライアントサーバシステムとして考える。

COM のクライアントとサーバは広い概念を含んでいる。
ネットワークで結ばれた異なるコンピュータとは限らない。
これらは同じコンピュータ上で動作する、
異なるプロセスでも構わないし、
クラスライブラリのように、同じプロセス内で動作する、
別々のコードでも構わないのである。

サーバ側となるプログラムを「COM サーバ」と呼ぶが、
別のコンピュータにある COM サーバは「リモートサーバ」、
同じコンピュータ上の別のプロセスとして動作する
COM サーバは「ローカルサーバ」、
利用するクライアントと同じプロセスで動作する
COM サーバは「インプロセスサーバ」と区分している。

ローカルサーバは実行可能な EXE である。
リモートサーバは、遠隔コンピュータに存在する
ローカルサーバとなるため、同じく実行可能な EXE となる。
インプロセスサーバはプロセスにロード可能な DLL となる。

COM は、これらの違いを吸収する機能を持っているため、
クライアントからはその差を考えずに、
ほとんど同じように利用することができる。

とはいえ、基本的にプロセス間通信やコンピュータ間通信は、
プロセス内の通信(直接呼び出し)よりもコストがかかり、
実行には、それ相応のオーバヘッドが伴う。

シェルエクステンションは、頻繁に利用されるため、
インプロセスサーバとして実装するのが一般的である。

COM を使う場合、クライアントはサーバに接続し、
サーバにオブジェクトの生成を要求する。
要求を受け取ったサーバはオブジェクトを生成する。

ここでサーバが作成したインスタンスは、
クライアントには直接渡されず、常にサーバ側に存在する。
その代わり、インスタンスを操作するための、
インタフェース型のポインタが作成され、
それがクライアントに返却される。

これが、インプロセスサーバであれば、
インスタンスの場所は常にプロセスの内部なので、
単純なインスタンスの生成のシナリオであるが、
異なるプロセスや異なるコンピュータの場合は特別で、
このインタフェースポインタは、プロセスの外にある
インスタンスを操作することができる特殊なものとなる。

クライアントは、インタフェースポインタを経由して、
メソッドやプロパティ(メソッドの特殊形)の呼び出しを行う。
COM の基盤は、これら呼び出しをサーバに転送し、
サーバ側に存在するインスタンスのメソッドが実行される。

メソッドの実行が「サーバ側で行われる」のがポイントだ。
クライアントとサーバが異なるプロセスの場合、
サーバ側プロセス内で実行されることになるし、
クライアントとサーバが異なるコンピュータ上にあれば
サーバ側コンピュータで実行されることになる。

つまり、別のコンピュータ上で動作するクライアントから、
遠隔操作を行うことができるのである。

遠隔地にあるコンピュータにあるローカルサーバ
(リモートサーバ)との通信に使う COM 基盤を、
Distributed COM (DCOM) と呼ぶのだが、
この呼び出し手法を RPC (Remote Procedure Call)と呼ぶ。
直訳すると、「遠隔手続き呼び出し」だ。

OS が DCOM 機能を実装している場合、
遠隔地にあるサーバ機能を呼び出すことができるのだ。
これが、COM の持つ大きなメリットである。

例えば、VBA の CreateObject 関数の 2 番目の引数に、
別のコンピュータ名や IP アドレス等を指定すると、
指定したコンピュータ上にインスタンスが作成されるし、
Windows の「コンピュータの管理」機能は、
別のコンピュータを操作できるようになっている。

さて、インスタンスはサーバ側に存在するのだが、
その寿命を管理するのもサーバの仕事となっている。

サーバは、クライアントの要求があれば、
必要な数だけインタフェースポインタを作成するが、
それらポインタが全て解放された時に、
サーバはインスタンスを破棄する事もできる。

逆に、性能を求められるようなサーバの場合、
インスタンスをプールするような実装も構わない。
それらは、全てサーバ側が考えることになっている。

それによって、クライアントは単純に考えることができる。
必要に応じてサーバにインタフェースポインタを要求し、
インタフェースポインタを使い終わったら解放するだけだ。
インスタンスの削除のことなどは考える必要がない。

明日よりシェルエクステンションの DLL を作っていくが、
インプロセスサーバも COM サーバであるので、
インタフェースポインタの生成や、
インスタンスの寿命管理などのサーバ機能が必要だ。

インプロセスサーバは、上に述べたような、
プロセス間通信やコンピュータ間通信を使わないため、
他の種類の COM サーバより実装が楽であり、
COM サーバの基本動作を学ぶにはもってこいである。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.