このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
さて、必要な機能は全て実装したのだが、
一般的なインプロセスサーバとして完成させるには、
あともう少しやるべきことがある。
インプロセスサーバは、DLL をコピーするだけでは動作せず、
サーバに含まれる COM クラスを公開するために、
レジストリに登録する必要があった。
レジストリの登録情報は、DLL のパスに依存しているため、
インプロセスサーバをシステムにインストールする際に、
レジストリファイルを相手に配るのは現実的ではない。
そのため、COM サーバには、登録・登録解除を
自分自身で行うための仕組みが存在する。
インプロセスサーバの場合は、DllRegisterServer と、
DllUnregisterServer の 2 つの関数を実装し、
それぞれで自身の登録と登録解除処理を行う必要がある。
STDAPI DllRegisterServer();
STDAPI DllUnregisterServer();
通常は自身の公開する COM クラスの登録のみを行うが、
DLL が必要とする独自機能のための追加登録や、
ファイルのコピーなどを行っても構わない。
LinkIconOverlays.dll の場合は、
COM クラスとシェル拡張の登録を行うことになる。
レジストリの登録には、Reg~ 系の API を使うのだが、
これら API を使って値をレジストリにアクセスし、
値を登録するためには、意外と手間が掛かる。
そこで、まずはレジストリ用のヘルパ関数を用意しよう。
レジストリに値を登録するためには、
キーを開く⇒値を登録⇒キーを閉じるという工程が必要だ。
値を登録した時点でエラーが発生した場合でも、
開いたキーは閉じる必要があるので、
これを 1 つの関数内に書いていくと見通しが悪くなる。
そこでこれらをまとめて実行する関数を用意し、
例外(HRESULT)処理を書きやすくしておこう。
まあ、C++ の機能を生かしてクラス化したほうが良いのだが、
今回はあえて関数指向で書くことにした。
========== library.cpp ==========
// (…前略…)
// (…DllMain…)
// (…DllGetClassObject…)
// (…DllCanUnloadNow…)
// レジストリに値を登録する
static LONG WriteRegistryStringValue(
HKEY baseKey,
LPCTSTR path,
LPCTSTR name,
LPCTSTR value) {
HKEY key;
// キーを開くか作成
LONG error = RegCreateKeyEx(baseKey, path,
0, NULL, 0, KEY_WRITE, NULL, &key, NULL);
if (error != ERROR_SUCCESS) return error;
if (value != NULL) {
// 値を登録
error = RegSetValueEx(key, name, 0, REG_SZ,
reinterpret_cast<const BYTE*>(value),
(lstrlen(value) + 1) * sizeof (TCHAR));
}
// キーを閉じる
RegCloseKey(key);
return error;
}
========== (library.cpp) ==========
まずは WriteRegistryStringValue というヘルパ関数だ。
これは、library.cpp 内でしか使わない関数なので、
先頭に static を付与し、内部リンケージとしておく。
RegCreateKeyEx は、レジストリキーを開くか作成する。
引数は多いが、ほとんどはお決まりの値だ。
baseKey は基準となるキーであり、
通常は HKEY_CLASSES_ROOT などの値である。
これは HKEY 型の定数として定義されている。
開いたキーは引数で受け取る事になっており、
戻り値は Windows のエラーコードとなる。
~Ex という関数は、Ex が付かない関数を拡張したものだ。
Windows API にはこの手の名前が良く登場する。
別に古い RegCreateKey を使っても良いのだが、
大抵は 16 ビット時代の賜物で、
昨今の環境では非推奨になっていることが多い。
RegSetValueEx は、開いたキーに値を登録する。
今回の登録情報は全て文字列値なので、
REG_SZ というレジストリ型を指定している。
レジストリには無名の値が存在するため、
name は NULL でも構わないのだが、
値が NULL になるのは認められない。
レジストリには値として文字列以外も
バイナリや整数型も登録できるので、
値は BYTE 配列として受け取ることになっている。
そこで文字列を強制的に BYTE* 型にキャストしている。
データの長さもバイト単位なので、
末尾の NUL も含めて計算が必要となる。
書き込みが終われば、RegCloseKey でキーを閉じる。
========== library.cpp ==========
// レジストリの値を削除する
static LONG DeleteRegistryValue(
HKEY baseKey,
LPCTSTR path,
LPCTSTR name) {
HKEY key;
// キーを開く
LONG error = RegOpenKeyEx(baseKey, path, 0, KEY_WRITE, &key);
if (error != ERROR_SUCCESS) return error;
// 値を削除
error = RegDeleteValue(key, name);
// キーを閉じる
RegCloseKey(key);
return error;
}
========== end of library.cpp ==========
そして、DeleteRegistryValue というヘルパ関数を作る。
これも先頭に static を付与し、内部リンケージとしておく。
RegOpenKeyEx は、RegCreateKeyEx と違い
キーが存在しない場合は作成せずにエラーとなる。
RegDeleteValue で登録されている値を削除し、
RegCloseKey でキーを閉じれば OK だ。
これら 2 つのヘルパ関数を使えば、
キーの開閉を気にせずにコードを書くことができる。