2009年8月22日土曜日

モーダルウィンドウの実装

モーダルウィンドウの作成では,ウィンドウスタイルにWS_CHILDを指定してはいけない. モーダルダイアログボックスと同様,オーナーウィンドウは存在することができる.

モーダルウィンドウを作成する関数(メソッド)の簡単な実装例を以下に示す.

int DoModal(HWND hWndOwner)
{
    ////
    //  オーナーウィンドウの存在確認
    if( hWndOwner && ! ::IsWindow(hWndOwner) )
        return 0;

    ////
    //  ウィンドウの作成
    if( ! ::CreateWindow( /* 引数省略(WS_CHILDスタイル禁止) */ ) )
        return -1;
        
    ////
    //  オーナーウィンドウの無効化
    ::EnableWindow(hWndOwner, FALSE);
    
    ////
    //  メッセージループ
    BOOL bReturned;
    MSG  msg;
    while( bReturned = ::GetMessage(&msg) )
    {
        if( -1 == bReturned )
            return -1;
        else
        {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
        }
    }
    
    ////
    //  オーナーウィンドウの有効化
    ::EnableWindow(hWndOwner, TRUE);
    ::SetWindowPos(hWndOwner, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    
    return static_cast<int>(msg.wParam);
}

上記のコードからも分るように,モーダルウィンドウを終了する際には,WM_QUITメッセージをポストしなくてはならない.

これだけでもモーダルウィンドウとしては機能するが,ユーザーの便利の為にWM_DESTROYメッセージの処理に以下のコードを追加する.

// hWndOwner : オーナーウィンドウのハンドル
// hWnd : モーダルウィンドウのハンドル
::SetWindowPos(hWndOwner, hWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

モーダルダイアログは,自らがアイドル状態になるとき WM_ENTERIDLEメッセージ をオーナーウィンドウに送信するが,実装しなくても動く.

ATL用のテンプレートクラスを作ってみたので,よかったらどうぞ.

0 件のコメント:

コメントを投稿