閉じないウィンドウ
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 が返ります