質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • C++

    3758questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Win32 API

    245questions

    Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

外部アプリケーションの終了確認後の状況を取得したい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 426

RyuL

score 3

CreateProcessで起動した外部アプリケーションにて、このアプリケーションに終了メッセージを送信させた時に、そのアプリケーションが終了確認ダイアログで終了するかしないかの確認をする仕様だった場合の話です。

その時の現在のコードがこちらです。

case WM_CLOSE:
    SendMessage( appHwnd, WM_CLOSE, 0, 0L ); // appHwnd:外部アプリケーションのハンドル
    if( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_OBJECT_0 ) // pi:外部アプリケーションのプロセス情報
    {
        CloseHandle( pi.hProcess );
        DefWindowProc( hWnd, message, wParam, lParam ); // hWnd:このアプリケーションのハンドル
    }

    break;

このコードを見てわかる通り、確認ダイアログで終了を選択した場合は問題ないのですが、終了をキャンセルした場合でもこちらのアプリケーションが終了してしまいます。

外部アプリケーションで終了をキャンセルした場合は、こちらのアプリケーションも終了をキャンセルしたいのですが、どの様にしたらいいのかご教授いただければ幸いです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

単純に WM_CLOSE 内で待ち合わせなければ問題ないかと思います。定期的にプロセスの終了を監視するために WM_TIMER を使うと以下のようになります。

case WM_CREATE:
    // WM_CREATE でなくても CreateProcess に成功した後で SetTimer すれば良い。
    SetTimer( hWnd, 1, 200, NULL );
    break;

case WM_CLOSE:
    SendMessage( appHwnd, WM_CLOSE, 0, 0L );
    return 0; // DefWindowProc に渡さない。

case WM_TIMER:
    if( wParam == 1 )
    {
        if( WaitForSingleObject( pi.hProcess, 0 ) == WAIT_OBJECT_0 ) // プロセスの終了をチェックするだけで待機しない。
        {
            CloseHandle( pi.hProcess );
            DestroyWindow( hWnd );
        }
    }
    break;

WM_TIMER を使うのが嫌ならメッセージループ側でプロセスの終了を待機しても良いかと思います。以下が例ですが、WM_CLOSE で終了要求を送信しても自アプリを終了しないようにするのは同じです。

// メッセージループ
bool continueMessageLoop = true;
while( continueMessageLoop )
{
    DWORD result = MsgWaitForMultipleObjects( 1, &pi.hProcess, FALSE, INFINITE, QS_ALLEVENTS );
    if( result == WAIT_OBJECT_0 )
    {
        CloseHandle( pi.hProcess );
        DestroyWindow( hWnd ); // hWnd は WM_TIMER 時と同じもの
        // pi.hProcess が常にシグナル状態となるので、プロセス終了後に MsgWaitForMultipleObjects 呼び出しが成立しない。
        // WM_DESTROY で PostQuitMessage せずに終了した方が良い。
        break;
    }
    else if( result == WAIT_OBJECT_0 + 1 )
    {
        MSG msg;
        while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        {
            switch( msg.message )
            {
            case WM_QUIT:
                // 多分、ここには来ない。
                continueMessageLoop = false;
                break;
            default:
                TranslateMessage( &msg );
                DispatchMessage( &msg );
                break;
            }
        }
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/17 10:19

    ご教授ありがとうございます。
    教えて頂いた通りに書いたら問題なく解決しました。
    WM_TIMERは他の処理で使っていたので、こちらの方法で解決しました。
    また、よろしくお願いいたします。

    キャンセル

+2

すでに解決済みになっていますが、別の方法もあります。

外部アプリへのWM_CLOSE送信をSendMessage関数で行っているということは、関数から返ってきたときには外部アプリのWM_CLOSE処理は完了しているということになります。
WM_CLOSE処理では、通常DestroyWindow関数で自身を破棄するわけですが、確認が必要な場合はダイアログで選択させ、その結果終了させる場合はDestroyWindow関数を呼び、終了させない場合は何もしない、という流れになります(すべてのアプリがそうなっているとは言い切れませんが)。
つまり、確認ダイアログで終了を選んだ場合はSendMessage関数から制御が戻ってきた時点でウィンドウが破棄されていて、キャンセルされていたらまだウィンドウが存在する、ということになります。

要するに、SendMessage関数から戻ってきたときに外部アプリのウィンドウの存在確認をすれば、終了したか否かを判定できるということです。

ウィンドウの存在確認はIsWindow関数でできます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • C++

    3758questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Win32 API

    245questions

    Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。