2010-11-25 8 views
6

SetConsoleCtrlHandlerを使用して、処理するハンドラとCTRL_CLOSE_EVENTを使用するコンソールアプリケーションがあります。ハンドラは単にTRUEを返します。ダイアログボックスが表示され、ユーザーにシャットダウンまたはキャンセルを続行するよう指示します。Windows Web Server 2008のCTRL_CLOSE_EVENTでCtrlHandlerが呼び出されていません

このソフトウェアは、Windows XP SP3およびWindows Web Server 2008 SP2で動作します。

XPでは、コンソールウィンドウの「X」をクリックすると、コントロールハンドラが呼び出され、プロンプトが期待通りに表示されます。 Server 2008では、コンソールウィンドウを閉じてもコントロールハンドラは呼び出されず、アプリケーションはプロンプトを表示せずに終了します。

コントロールハンドラが正しく設定されていることを確認するために、CTRL_C_EVENTのケースを追加しました。私はコードがCtrl-Cのために呼ばれることを見ることができます。

Server 2008でクローズイベントを処理する方法に違いはありますか?彼らはctrlハンドラを一切通らないようです。

EDIT

は、私はすべての情報について CTRL_CLOSE_EVENTもはやVistaで取り扱わ以降さを見つけることができません SetConsoleCtrlHandlerのためのMSDNのページを見てみます。

コンソールのCtrlイベントの代わりにウィンドウ(HWND)を扱っている場合、コンソールウィンドウに送信されたクローズメッセージを取得して処理することは可能ですか?ここで

+0

うん、この動作はVistaで変更されました。プログラムでシャットダウンをブロックすることはできません。 –

+2

これ以上の通知はありませんか?このように閉じたときにプロセスがクリーンアップを実行することは可能ですか? –

+0

はい、Vista(Server 2008)ではこれが変更されています。ログオフイベントはもう受信しません。私自身のコンソールアプリケーションのために、私は隠されたウィンドウを作成し、クローズイベントとログオフイベントの両方を受け取ります。 – bronekk

答えて

3

は(Windows 7の上で実行されている)私は、コンソールアプリケーションで何をすべきかです:

私。閉じる/ログオフ通知を待つための隠しウィンドウを作成します。重要

void interrupt::start() 
{ 
    WNDCLASSEX wc = {}; 
    HINSTANCE hi = GetModuleHandle(NULL); 

    wc.cbSize  = sizeof(WNDCLASSEX); 
    wc.lpfnWndProc = WndProc; 
    // . . . etc 

    if(!RegisterClassEx(&wc)) 
    return; 

    hwnd_ = CreateWindowEx(WS_EX_CLIENTEDGE, class_name, "Waiting for user logoff event", 
    WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hi , NULL); 

    ShowWindow(hwnd_, SW_HIDE); 
    UpdateWindow(hwnd_); 

    MSG msg = {}; 
    while(GetMessage(&msg, NULL, 0, 0)) 
    { 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
    } 

    // call internal function for sending "stop" notification to rest of program 
    ctrl.stop(CTRL_CLOSE_EVENT); 
} 

IIそのメッセージループのためにそれを自身のスレッドを与えます。ウィンドウメッセージハンドラで "特別なイベント"の処理を実装する

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch(msg) 
    { 
    case WM_ENDSESSION: 
    if (lParam) 
    { 
     // call internal function for sending "stop" notification to rest of program 
     ctrl.stop(lParam == ENDSESSION_LOGOFF ? (int) interrupt::logoff : CTRL_CLOSE_EVENT); 
    } 
    break; 
    case WM_CLOSE: 
    DestroyWindow(hwnd); 
    break; 
    case WM_DESTROY: 
    PostQuitMessage(0); 
    break; 
    default: 
    return DefWindowProc(hwnd, msg, wParam, lParam); 
    } 
    return 0; 
} 

iii。 「停止」要求を処理するための内部機能を実装する。 2つの特別な条件を処理する必要があります。

a。 がウィンドウメッセージスレッドから呼び出された場合、ウィンドウにWM_CLOSEを送信し、スレッドが終了するまで待ちます。

b。 でメインスレッドから呼び出された場合は、静的変数の終了(少なくとも1つ)を待ちます。

これは、CtrlHandlerの終了後、Windowsが無条件でプロセスを終了させ、コードをクリーンアップすることがないためです。静的変数はメインスレッドで破棄されるため、この待機は少なくともint main()が終了したことを保証します。静的変数のコンストラクタ(メインウィンドウの "shadow"ウィンドウを開始したものと同じもの)のメインスレッドのスレッドIDを取得できます。ここで

は、私は私のコードでそれをやった方法です:

void interrupt::stop(int signal) 
{ 
    // . . . 

    // Set exit signal 
    InterlockedExchange(&stage_, 2L); 

    // Close shadow window if notification is from elsewhere 
    if (hwnd_ && GetCurrentThreadId() != thread_.id()) 
    { 
    PostMessage(hwnd_, WM_CLOSE, 0, 0); 
    thread_.wait(); 
    } 

    // Wait for completion of own destructor on main thread 
    if (GetCurrentThreadId() != main_thread_id_) 
    while(stage_ != 3L) 
     Sleep(10); 
} 

// My static variable to wait for 
interrupt ctrl; 
+0

OPが求めているのは、 'x'ボタンでコンソールウィンドウを閉じるのを傍受できるのでしょうか? – Anonymous

関連する問題