ページ 11

ボタンのサブクラス化について

Posted: 2009年9月17日(木) 23:23
by Ace
Win32APIでボタンをサブクラス化して、色々試していたのですが、よく分からない挙動をして示したので質問させていただきます。
とりあえずソースをのせます。VC++2008Proでコンパイル成功の確認済みです。
#include <windows.h>

HINSTANCE hInst;

#define ID_BUTTON (1)
WNDPROC defBtnProc;

LRESULT CALLBACK BtnProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
	
	switch (msg) {
		case WM_LBUTTONUP: {
			int dammy = 0; // ブレークポイント用のダミー
			// これを実行するとWM_COMMANDのほうへメッセージがいかない!?
			//MessageBox(hWnd, L"HogeHoge at BtnProc", L"WM_LBUTTONUP", MB_OK);
			break;
		}
	}
	
	return CallWindowProc(defBtnProc, hWnd, msg, wp, lp);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
	
	switch (msg) {
		case WM_DESTROY: {
			PostQuitMessage(0);
			return 0;
		}
		case WM_CREATE: {
			HWND hBtn = CreateWindow(L"BUTTON", L"Click Me!",
				WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
				20, 20, 100, 30, hWnd, (HMENU)ID_BUTTON, hInst, 0);
			
			defBtnProc = (WNDPROC)GetWindowLong(hBtn, GWL_WNDPROC);
			SetWindowLong(hBtn, GWL_WNDPROC, (LONG)BtnProc);
			
			return 0;
		}
		case WM_COMMAND: {
			switch (LOWORD(wp)) {
				case ID_BUTTON: {
					MessageBox(hWnd, L"HogeHoge at WndProc", L"ID_BUTTON", MB_OK);
					return 0;
				}
			}
			break;
		}
	}
	
	return DefWindowProc(hWnd, msg, wp, lp);
}


int WINAPI wWinMain(
	HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPWSTR lpszCmdLine, int nCmdShow) {
	
	WNDCLASSEX wc = {0};
	HWND hWnd = 0;
	MSG msg = {0};
	BOOL ret = 0;
	
	hInst = hInstance;
	
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName = 0;
	wc.lpszClassName = L"BUTTON_TEST_CLASS_NAME";
	wc.hIconSm = wc.hIcon;
	
	if (!RegisterClassEx(&wc)) return -1;
	
	hWnd = CreateWindow(
		wc.lpszClassName, L"Button Test",
		WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
		300, 300, NULL, NULL, hInstance, NULL);
	
	if (!hWnd) return -1;
	
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	while (1) {
		ret = GetMessage(&msg, NULL, 0, 0);
		if (ret == -1) return -1;
		if (ret == 0) break;
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	
	return 0;
}
ソース中にも少し書きましたが、BtnProcのWM_LBUTTONUPでMessageBoxを実行するとWndProcにWM_COMMANDメッセージがいっていないようです。
しかし、BtnProcのWM_LBUTTONUPでMessageBoxを実行しなければ(ソースの状態です)、WM_COMMANDメッセージが送られているようなのです。

これはいったい何故なのでしょうか?
WM_LBUTTONUPでMessageBoxを実行したことにより何が起こってしまったのかがよく分かりません。
分かる方がいましたら、ご教示のほどよろしくお願いいたします。

Re:ボタンのサブクラス化について

Posted: 2009年9月19日(土) 00:15
by Justy

>これはいったい何故なのでしょうか?

 多分メインウィンドウが非アクティブ化になってしまっているからでしょう。


 起動した直後はメインウインドウがアクティブな状態になっていますが、
ボタンをクリックしてメッセージボックスを表示した瞬間にメインウインドウが
非アクティブ化され、メッセージボックスがアクティブになります。

 その為、非アクティブになったメインウインドウには WM_COMMANDが
来ないのだと思います。


 アクティブ・非アクティブの切り替わりは WM_ACTIVATEメッセージを
とらえると判ります。

Re:ボタンのサブクラス化について

Posted: 2009年9月19日(土) 03:13
by Ace
WM_COMMANDはウィンドウがアクティブな時しか送られないのですね。
なるほど、納得です。

ウィンドウメッセージはこういうところが煩雑で疲れます…。

数日間もやもやしていたのが、すっきりしました。
どうもありがとうございました。