このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
昨日作った WriteRegistryStringValue を使うと、
COM クラスとエクステンションの登録処理を、
少しは見やすく書くことができる。
========== library.cpp ==========
// (…前略…)
// (…DllMain…)
// (…DllGetClassObject…)
// (…DllCanUnloadNow…)
// (…WriteRegistryStringValue…)
// (…DeleteRegistryValue…)
// COM クラスと重ね合わせアイコンハンドラの登録
static HRESULT RegisterIconOverlayHandler(
REFCLSID classID,
LPCTSTR description,
LPCTSTR threadingModel) {
// 軽いチェック
if (description == NULL) return E_UNEXPECTED;
if (threadingModel == NULL) return E_UNEXPECTED;
// CLSID を文字列に
WCHAR clsidString[40];
if (!StringFromGUID2(classID, clsidString, 40)) return SELFREG_E_CLASS;
WCHAR keyPath[256];
// DLL のパスを得る
TCHAR modulePath[MAX_PATH];
if (!GetModuleFileName(g_moduleHandle, modulePath, MAX_PATH))
return E_UNEXPECTED;
LONG error = ERROR_SUCCESS;
// CLSID\<クラス ID> のパスを作成
wsprintf(keyPath, L"CLSID\\%s", clsidString);
// (既定値) = <説明>
error = WriteRegistryStringValue(HKEY_CLASSES_ROOT,
keyPath, NULL, description);
if (error != ERROR_SUCCESS) return SELFREG_E_CLASS;
// CLSID\<クラス ID>\InProcServer32 のパスを作成
lstrcat(keyPath, L"\\InProcServer32");
// (既定値) = <DLL のパス>
error = WriteRegistryStringValue(HKEY_CLASSES_ROOT,
keyPath, NULL, modulePath);
if (error != ERROR_SUCCESS) return SELFREG_E_CLASS;
// ThreadingModel = <スレッディングモデル>
error = WriteRegistryStringValue(HKEY_CLASSES_ROOT,
keyPath, L"ThreadingModel", threadingModel);
if (error != ERROR_SUCCESS) return SELFREG_E_CLASS;
// Software\…\ShellIconOverlayIdentifiers\<説明> のパスを作成
wsprintf(keyPath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\%s", description);
// (既定値) = <クラス ID>
error = WriteRegistryStringValue(HKEY_LOCAL_MACHINE,
keyPath, NULL, clsidString);
if (error != ERROR_SUCCESS) return SELFREG_E_CLASS;
return S_OK;
}
========== (library.cpp) ==========
RegisterIconOverlayHandler は、
クラス 1 つの登録処理をまとめたものだ。
レジストリファイルでは数行でも、
API を使って登録するには結構手間が掛かる。
StringFromGUID2 は、構造体であるクラス ID を、
中括弧で囲んだおなじみの表現に書式化する関数である。
レジストリではほとんどが文字列なので、
この関数や、逆の処理を行う CLSIDFromString 関数の
お世話になることが多い。
========== (library.cpp) ==========
// COM クラスと重ね合わせアイコンハンドラの登録解除
static HRESULT UnregisterIconOverlayHandler(
REFCLSID classID,
LPCTSTR description) {
// 軽いチェック
if (description == NULL) return E_UNEXPECTED;
// CLSID を文字列に
WCHAR clsidString[40];
if (!StringFromGUID2(classID, clsidString, 40)) return SELFREG_E_CLASS;
WCHAR keyPath[256];
LONG error = ERROR_SUCCESS;
// Software\…\ShellIconOverlayIdentifiers\<説明> のパスを作成
wsprintf(keyPath, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\%s", description);
// (既定値) を削除
error |= DeleteRegistryValue(HKEY_CLASSES_ROOT, keyPath, NULL);
error |= RegDeleteKey(HKEY_CLASSES_ROOT, keyPath);
// CLSID\<クラス ID>\InProcServer32 のパスを作成
wsprintf(keyPath, L"CLSID\\%s\\InProcServer32", clsidString);
// ThreadingModel と (既定値) を削除
error |= DeleteRegistryValue(HKEY_CLASSES_ROOT, keyPath, L"ThreadingModel");
error |= DeleteRegistryValue(HKEY_CLASSES_ROOT, keyPath, NULL);
error |= RegDeleteKey(HKEY_CLASSES_ROOT, keyPath);
// CLSID\<クラス ID> のパスを作成
wsprintf(keyPath, L"CLSID\\%s", clsidString);
// (既定値) を削除
error |= DeleteRegistryValue(HKEY_CLASSES_ROOT, keyPath, NULL);
error |= RegDeleteKey(HKEY_CLASSES_ROOT, keyPath);
return error ? S_FALSE : S_OK;
}
========== end of library.cpp ==========
UnregisterIconOverlayHandler は登録の解除を行う。
RegisterIconOverlayHandler の逆順に処理をしている。
登録解除の場合は、値を削除するだけでなく、
RegDeleteKey を使ってキーも削除する必要がある。
さて、これら関数は DllRegisterServer や
DllUnregisterServer から呼ばれる予定なのだが、
処理の原子性が保障されていない。
これは、関数の途中でエラーが起きた場合は、
中途半端に登録された状態となりうる事を意味する。
幸い、DllRegisterServer や DllUnregisterServer は、
処理に失敗した際には中途半端な状態になっても構わないと、
ドキュメントに明記されているため、
安心して上記の関数を使うことができるのである。
明日は、いよいよ仕上げとなる。