Programming Field - プログラミング Tips

PropSheet: モードレスプロパティシートの終了方法(閉じ方)

PROPSHEETHEADER 構造体の dwFlags メンバに PSH_MODELESS を指定した場合、プロパティページはモードレスダイアログ(オーナーウィンドウが無効化されない)で作成され、PropertySheet 関数はそのウィンドウハンドルを返します(戻り値は元々 INT_PTR 型なので、型キャストしてください)。

このウィンドウの扱いと閉じ方について、MSDN ライブラリの「PropertySheet」関数の説明に以下の記述があります。

For a modeless property sheet, your message loop should use PSM_ISDIALOGMESSAGE to pass messages to the property sheet dialog box. Your message loop should use PSM_GETCURRENTPAGEHWND to determine when to destroy the dialog box. When the user clicks the OK or Cancel button, PSM_GETCURRENTPAGEHWND returns NULL. You can then use the DestroyWindow function to destroy the dialog box.

適当訳: モードレスプロパティシートでは、アプリケーションのメッセージループ内で、プロパティシートに PSM_ISDIALOGMESSAGE を送ってください。また、PSM_GETCURRENTPAGEHWND を送ってプロパティシートを終了するタイミングをチェックしてください。プロパティシートで OK やキャンセルボタンが押されると PSM_GETCURRENTPAGEHWND から NULL が返るので、そのタイミングで DestroyWindow を呼び出すことが出来ます。

PSM_ISDIALOGMESSAGE は、lParamLPMSG 型の引数を取るメッセージで、IsDialogMessage の代わりとなります。これを送らないと、プロパティシート内でキー操作が出来なくなります。

ということで、モードレスプロパティシートを適切に終了するには、以下のようなコードになります。

// g_hPropSheet はモードレスプロパティシートのハンドルを保持するグローバル変数
HWND g_hPropSheet;

    // メッセージループ
    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0))
    {
        // プロパティシートがメッセージ処理をするかどうかチェック
        if (!g_hPropSheet || !SendMessage(g_hPropSheet,
            PSM_ISDIALOGMESSAGE, 0, (LPARAM)(LPMSG) &msg))
        {
            // 通常のメッセージ処理を行う
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        // プロパティシートを閉じるべきかどうかチェック
        if (g_hPropSheet && !SendMessage(g_hPropSheet,
            PSM_GETCURRENTPAGEHWND, 0, 0))
        {
            // プロパティシートを終了する
            DestroyWindow(g_hPropSheet);
            g_hPropSheet = NULL;
        }
    }