閉じないウィンドウ


WM_DESTROY までの過程

前回は、正しくアプリケーションを終了させる説明をしました
しかし、場合によってはウィンドウの破棄をさせたくないケースもあるでしょう
"閉じる"や×ボタンが押されても、ウィンドウが破棄されなくするにはどうすれば良いでしょう

DefWindowProc() を使わないというのも一つの手ですが
そのほかのウィンドウの基本動作まで失われてしまいます
そこで、DefWindowProc() がウィンドウを破棄する前に
こちらのウィンドウプロシージャがメッセージを流すという手法が考えられます

では、DefWindowProc() がウィンドウを破棄する過程を知る必要があります
ユーザーが "閉じる"などを選択し、ウィンドウの破棄を要求すると
DefWindowProc() はウィンドウプロシージャに WM_SYSCOMMAND メッセージを送ります
さらに、DefWindowProc() がこれを受け取ると ウィンドウプロシージャに WM_CLOSE を送ります

DefWindowProc() は WM_CLOSE を受け取ると DestroyWindow() 関数を呼び出します
この関数は、指定されたウィンドウを破棄します

BOOL DestroyWindow(HWND hWnd);

hWnd には、破棄するウィンドウのハンドルを指定します
この関数は、ウィンドウの破棄に必要な様々な終了処理を行います
そして WM_DESTROY と WM_NCDESTROY メッセージをウィンドウに送ります
私たちは、以前この関数が送った WM_DESTROY を利用して終了処理を作ったのです

両方とも同じメッセージで、パラメータはなく、返すべき値は 0 です
戻り値は、関数が成功すると0以外、失敗すると0になります

ウィンドウを破棄しないようにするためには DefWindowProc() に
ウィンドウプロシージャからWM_CLOSEを渡さないようにすればよいのです
WM_CLOSE が返すべき値は 0 です
#include<windows.h>

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
	switch (msg) {
	case WM_CLOSE:
		return 0;
	case WM_RBUTTONUP:
		DestroyWindow(hwnd);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
		 PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	MSG msg;
	WNDCLASS winc;

	winc.style		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	= winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return 0;

	hwnd = CreateWindow(
			TEXT("KITTY") , TEXT("Kitty on your lap") ,
			WS_OVERLAPPEDWINDOW  | WS_VISIBLE ,
			100 , 100 , 200 , 200 , NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return 0;

	while (GetMessage(&msg , NULL , 0 , 0)) DispatchMessage(&msg);
	return msg.wParam;
}
WM_CLOSE が渡されると、ウィンドウプロシージャは制御を返します
結果として DefWinProc() にメッセージが渡されないため、ウィンドウは破棄されません

当然、代わりに何らかの方法で終了しなければいけません
上のプログラムは、クライアントエリアを右クリックすると終了します
//マウス処理については、後ほど紹介します


DestroyWindow()

BOOL DestroyWindow(HWND hWnd);

WM_DESTROY メッセージとWM_NCDESTROY メッセージをウィンドウに送り
ウィンドウの破棄に必要な作業を行います

hWnd - 破棄するウィンドウを指定します

戻り値 - 成功すると 0 以外の値、失敗すると 0 が返ります



前のページへ戻る次のページへ