2013-08-17 4 views
9

にCTRL + Cを処理します。私は<em>Win32のC++</em>コンソールプログラムでは、<kbd>CTRL +</kbd><kbd>C</kbd>イベントの処理に関するいくつかの問題を持っているのWin32

基本的に私のプログラムは以下のようになります。問題はまったく実行されていないクリーンアップコードである

bool running; 

int main() { 

    running = true; 
    SetConsoleCtrlHandler((PHANDLER_ROUTINE) consoleHandler, TRUE); 

    while (running) { 
     // do work 
     ... 
    } 

    // do cleanup 
    ... 

    return 0; 
} 

bool consoleHandler(int signal) { 

    if (signal == CTRL_C_EVENT) { 

     running = false; 
    } 
    return true; 
} 

:(Windows Ctrl-C - Cleaning up local stack objects in command line appこの他の質問に基づきます)。

ハンドラ関数の実行後、プロセスは終了しますが、メインループの後にコードは実行されません。どうしましたか?

EDIT:要求されたとして、これは私のプログラムに似て、最小限のテストケースである:http://pastebin.com/6rLK6BU2

私は、出力の「テストのクリーンアップ命令」の文字列を得ることはありません。

これが重要かどうかわかりませんが、MinGWでコンパイルしています。


EDIT 2:テストケースプログラムに問題がSleep()関数の使用です。それがなければ、プログラムは期待どおりに動作します。

関数ハンドラは別のスレッドで実行されるため、ハンドラ/スレッドの実行が終了するとメインスレッドはスリープ状態になります。これがプロセスの中断の原因でしょうか?

+3

'SetConsoleCtrlHandler'は何を返しますか? – Caesar

+0

SetConsoleCtrlHandlerの戻り値は何ですか?あなたはエラーをチェックしていません、btw – lpapp

+1

'ConsoleHandler'機能はまったく動いていますか?デバッガでプログラムを実行してブレークポイントを設定すると、ブレークポイントで停止しますか? –

答えて

7

次のコードは、私の作品:

#include <windows.h> 
#include <stdio.h> 

BOOL WINAPI consoleHandler(DWORD signal) { 

    if (signal == CTRL_C_EVENT) 
     printf("Ctrl-C handled\n"); // do cleanup 

    return TRUE; 
} 

int main() 
{ 
    running = TRUE; 
    if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) { 
     printf("\nERROR: Could not set control handler"); 
     return 1; 
    } 

    while (1) { /* do work */ } 

    return 0; 
} 
10

the documentationによると(間違って宣言され、BTW)ハンドラはCTRL_CLOSE_EVENTCTRL_LOGOFF_EVENT、またはCTRL_SHUTDOWN_EVENT信号を受信したときに、プロセスがハンドラの後に終了されます終了します。あなたがしようとしていることをするには、クリーンアップコードをハンドラ自体に移すことになっています。

+0

私のプログラムはこれらのイベントを受け取っていないようですが、 'CTRL_C_EVENT'だけです。私のハンドラ関数で 'switch'を使って今すぐテストし、コンソールからCTRL + Cを押します。 – eang

8

特定の要件に応じて、いくつかのオプションがあります。あなたは、単にはCtrl +Cを無視したい場合は、HandlerRoutineパラメータとしてNULLを渡すSetConsoleCtrlHandlerを呼び出すことができます。

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    SetConsoleCtrlHandler(NULL, TRUE); 

    // do work 

    return 0; 
} 

これは、すべてのシグナルハンドラを削除します。このアプリケーションを終了するには、カスタムロジックを実装して、いつシャットダウンするかを判断する必要があります。あなたははCtrl +Cを処理したい場合は

は、次の2つのオプションがあります:シグナルのハンドラを設定するか、通常のキーボードの取り扱い上のキーボード入力を渡します。

ハンドラの設定は上記のコードと似ていますが、ハンドラとしてハンドラとしてNULLを渡すのではなく、独自の実装を提供します。

#include <windows.h> 
#include <stdio.h> 

volatile bool isRunnung = true; 

BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) { 
    switch (dwCtrlType) 
    { 
    case CTRL_C_EVENT: 
     printf("[Ctrl]+C\n"); 
     isRunnung = false; 
     // Signal is handled - don't pass it on to the next handler 
     return TRUE; 
    default: 
     // Pass signal on to the next handler 
     return FALSE; 
    } 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    SetConsoleCtrlHandler(HandlerRoutine, TRUE); 

    printf("Starting\n"); 
    while (isRunnung) { 
     Sleep(0); 
    } 
    printf("Ending\n"); 

    return 0; 
} 

このアプリケーションの出力は、次のとおりに関わらずメインwhile - ループ内のコードのクリーンアップコードを実行すること

Starting 
[Ctrl]+C 
Ending 

注意。シグナルハンドラは、ハンドラの1つがTRUEを返すまで、ハンドラ関数が最後に登録されたファーストコールベースで呼び出されるリンクリストを形成します。いずれのハンドラもTRUEを返さない場合は、デフォルトのハンドラが呼び出されます。コンソールのデフォルトハンドラは、Ctrl + Cの処理時にExitProcessを呼び出します。あなたが任意の前処理を防止するため、通常のキーボード入力などはCtrl +Cを処理したい場合は

代わりに、あなたはSetConsoleModeを呼び出すことによって、コンソールモードを変更する必要があります。 ENABLE_PROCESSED_INPUTフラグが除去されると

#include <windows.h> 
#include <stdio.h> 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    DWORD dwMode = 0x0; 
    GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwMode); 
    // Remove ENABLE_PROCESSED_INPUT flag 
    dwMode &= ~ENABLE_PROCESSED_INPUT; 
    SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwMode); 

    while (true) { 
     // Ctrl+C can be read using ReadConsoleInput, etc. 
    } 

    return 0; 
} 

Ctrlキー + Cは、システムによって処理され、通常のキーボード入力のようなコンソールに渡されなくなりました。 ReadConsoleInputまたはReadFileを使用して読み取ることができます。

免責事項:上記は32ビットおよび64ビットのリリースおよびデバッグ構成用にコンパイルされたWindows 8 64bitでテストされています。

関連する問題