インスタンスハンドルとモジュールハンドルの違い

前書き

HINSTANCEとHMODULEの違いについて、また、使い分けについて、調べたことをまとめようと思います。

違いは何なのか

歴史的な違い

HINSTANCE と HMODULE の違い こちらをご覧ください。(タイトルがまんまかぶってますね)
2行でまとめると、歴史的には違うものだったが、
今となっては同じで、モジュールの先頭アドレスらしいです。

定義の違い

windef.hに

typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */

って書いてありました。
つまり、現在では、事実上型としての違いは何もありません。

インスタンスハンドルは、GetWindowLongで調べていいのか?

実はこっちが本題です。
別にGetWindowLongでいいのですが、それだとうまくいかないことがあるかもしれません。
前回の記事「ウィンドウハンドルから実行ファイル名を取得する」の、モジュールハンドルを取得する部分に関して。

// モジュールハンドルを得る
// EnumProcessModule式
HMODULE hModule = NULL;
DWORD gomi = 0;
if(!EnumProcessModules( hProcess, &hModule, sizeof(HMODULE), &gomi)) {
	dwErr = GetLastError();
	MessageBox( NULL, _T("EnumProcessModules"), NULL, NULL);
}

と書きましたが、これは

// GetWindowLong式
HMODULE hModule = (HMODULE)GetWindowLong( hWnd, GWL_HINSTANCE);
// (GetWindowLongPtrでも同じ)

と書き換えても、一応動きます。しかしこれだと一部のウィンドウではうまくいきません。

前回の記事のコードをGetWindowLong式に書き換えて実行した場合、
実行ファイル名が"ieframe.dll"となってしまいました。(本当は"iexplorer.exe")
ieframe.dllがIEのウィンドウをCreateWindowするのでしょう。
だから、GetWindowLongは、ieframe.dllのモジュールハンドル(DLLが読み込まれたアドレス)を返したのです。
参考インスタンスハンドルとモジュールハンドルって同じ用に扱ってもいい?

GetWindowLongとEnumProcessModules

ウィンドウハンドルからインスタンスハンドルを取得する方法としてはGetWindowLong/GetWindowLongPtrがあるわけですが、これで得たインスタンスハンドルではどうしてもうまくいかない場合、上で書いたような現象が起きているかもしれません。
そのような場合は以下のものを使ってみると、動くかもしれません。

//
// GetWindowLongやGetWindowLongPtrがうまくいかないときに使ってみると
// いいことがあるかもしれない。
//
// ウィンドウハンドルから実行ファイルのインスタンスハンドルを取得する
// 戻り値: 成功 インスタンスハンドル / 失敗 NULL
//
HINSTANCE GetInstanceHandle(
	HWND hWnd)	// 対象のHWND
{
	// プロセスID
	DWORD processID = NULL;
	GetWindowThreadProcessId( hWnd, &processID);

	// プロセスハンドル
	HANDLE hProcess = OpenProcess(
		PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
	if(!hProcess)
		return NULL;

	// モジュールハンドル
	HMODULE hModule = NULL;	// HINSTANCE ≒ HMODULE
	DWORD dummy = 0;
	BOOL bResult = EnumProcessModules( hProcess, &hModule, sizeof(HMODULE), &dummy);

	CloseHandle( hProcess);
	if(!bResult)
		return NULL;
	return hModule;
}