コンソールウィンドウの割り込み制御
ウィンドウプログラムから標準出力をコンソールウィンドウに出力するには以下のコードで可能です
//標準出力を指定し、標準出力関数を使ってみる
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <iostream>
#include <io.h>
#include <fcntl.h>
using namespace std;
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
int hConsole;
::AllocConsole(); //コンソール割り当て
hConsole = ::_open_osfhandle((intptr_t)::GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
*stdout = *::_tfdopen(hConsole, TEXT("w"));
::setvbuf(stdout, NULL, _IONBF, 0);
printf("printfで出力\n");
cout<<"coutで出力"<<endl;
::MessageBox(NULL, TEXT("ストッパーです"), TEXT("AllocConsole"), MB_OK);
::FreeConsole(); //コンソールを解放します
::_close(hConsole); //ハンドルを閉じます
return 0;
}
しかし、このままでは以下の条件でプログラムが終了してしまいます
・(コンソールウィンドウがアクティブな状態で)Ctrl+C、またはCtrl+Breakキーを押す
・コンソールウィンドウの×ボタンを押す
一見コンソールウィンドウだけが閉じるかのような条件ですが
メインプログラム自体も終了してしまいます
そこで今回は、コンソール側からは終了させない処理を追加してみたいと思います
コンソールウィンドウは、Ctrl+Cや×ボタンが押されたとき、その信号を処理するHandlerRoutine関数を
持っています
デフォルトでは、Ctrl+Cなどを受け取るとExitProcess関数を呼び出すというだけの処理になっているので
プロセスが強制終了してしまいます
そこで、割り込みの信号を制御するHandlerRoutine関数を追加します
ハンドラ関数の定義は以下のような形になります
BOOL WINAPI HandlerRoutine(DWORD type)
HandlerRoutineの名前は任意です
Ctrl+Cなど、割り込みが入るごとにこの関数が処理されることになります
どの割り込みが入ったのかは、引数のtypeに定数が格納されています
定数 |
割り込みの種類 |
CTRL_C_EVENT |
Ctrl+Cが押された |
CTRL_BREAK_EVENT |
Ctrl+Breakが押された |
CTRL_CLOSE_EVENT |
コンソールを閉じた(×ボタンなど) |
CTRL_LOGOFF_EVENT |
ログオフした |
CTRL_SHUTDOWN_EVENT |
シャットダウンした |
そして、HandlerRoutine関数の戻り値にFALSEを指定すると強制終了するので、
終了したくない場合はTRUEを返します
例えばCtrl+Cを無効にしたい場合は、ハンドラ関数を
//コンソールのCtrl+Cを無効にする
BOOL WINAPI HandlerRoutine(DWORD type)
{
switch(type)
{
case CTRL_C_EVENT: //Ctrl+Cを受け取った
return TRUE; //終了しないのでTRUEを返す
}
return FALSE; //それ以外の時は強制終了
}
のように処理します
定数の5パターン分用意すると以下のようになります
//コンソールのCtrl+C,Ctrl+Break,閉じるを無効にする
//ログオフとシャットダウンが発生したときは終了するようにする
BOOL WINAPI HandlerRoutine(DWORD type)
{
switch(type)
{
case CTRL_C_EVENT: //Ctrl+Cを受け取った
case CTRL_BREAK_EVENT: //Ctrl+Breakを受け取った
case CTRL_CLOSE_EVENT: //コンソールを閉じた
return TRUE; //無効にするのでTRUEを返す
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
return FALSE;
}
return FALSE; //それ以外の時は強制終了
}
これで、コンソールウィンドウの割り込みを制御できます
あとはSetConsoleCtrlHandler関数を使い、自分の指定したハンドラ関数を追加します
BOOL SetConsoleCtrlHandler(
PHANDLER_ROUTINE HandlerRoutine, // ハンドラ関数のアドレス
BOOL Add // ハンドラを追加するか、削除するか
);
第1引数はハンドラ関数のアドレスを入れます
第2引数はハンドラを追加するのでTRUEを指定します(削除する場合はFALSE)
以下はHandlerRoutine関数を追加したコードです
//標準出力を指定し、標準出力関数を使ってみる
//割り込み制御追加
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <iostream>
#include <io.h>
#include <fcntl.h>
using namespace std;
//割り込み制御
BOOL WINAPI HandlerRoutine(DWORD type)
{
switch(type)
{
case CTRL_C_EVENT: //Ctrl+Cを受け取った
case CTRL_BREAK_EVENT: //Ctrl+Breakを受け取った
case CTRL_CLOSE_EVENT: //コンソールを閉じた
return TRUE; //無効にするのでTRUEを返す
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
return FALSE;
}
return FALSE; //それ以外の時は強制終了
}
//メイン関数
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
int hConsole;
::AllocConsole(); //コンソール割り当て
hConsole = ::_open_osfhandle((intptr_t)::GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
*stdout = *::_tfdopen(hConsole, TEXT("w"));
::setvbuf(stdout, NULL, _IONBF, 0);
::SetConsoleCtrlHandler(HandlerRoutine, TRUE); //←ここを追加!
printf("printfで出力\n");
cout<<"coutで出力"<<endl;
::MessageBox(NULL,TEXT("ストッパーです"),TEXT("AllocConsole"),MB_OK);
::FreeConsole(); //コンソールを解放します
::_close(hConsole);
return 0;
}
これでコンソールのCtrl+CとCtrl+Breakを無効化できます
ただし、コンソールを閉じたとき(×ボタンを押したときなど)は以下のようになります

キャンセルを押すと終了しません(処理を続行します)
すぐに終了を押すと終了してしまうのですが、コンソール画面から不用意に終了させない
という効果はあると思います
次は、標準エラー出力についてです
続き
TOP>プログラミング>コンソールウィンドウの割り込み制御