OS : 2008Server
VC.NET2008・Win32コンソールアプリケーションで開発しております。
タイマーで10秒ごとにプログラムを常時処理するプロセス(exe)を作成しています。
やりたい事は、ちょうど処理中にタスクマネージャから「プロセスの終了」または
マシンのシャットダウンをした場合、処理が完了してからプロセスを終了したいので
す。
簡単なプログラムで表しますと、
-------------------------------------------------------------------------------
--
//■メイン処理
_tWinMain(){
・・・
SetTimer( hWnds, 1, 10000, NULL ); // タイマー開始(10秒)
}
//■ウィンドウメッセージ処理
WndProc(){
switch( message ){
case WM_TIMER : // タイマー
test_process(); // プログラム処理
break;
・・・
}
}
//■プログラム処理
test_process(){
・・・
・・・処理中・・・ // ← ここで「プロセス終了」orシャットダウン!!!
・・・
return( 0 ); // ← このreturnまで処理したい!!!
}
-------------------------------------------------------------------------------
--
test_process()の処理が終わってから「プロセス終了」を検知してプロセスを終了させ
たい
のですが、可能でしょうか?
test_process()をコールする前で『プロセス終了を受け付けない』の命令などがあるの
でしょうか?
どうか宜しくお願い致します。
タイトルが不適切だよ・・・待たせたいの間違いぢゃねえか?
まず「シャットダウン」と「プロセスの抹消」では話が違うのでそこを区別。
シャットダウン、すなわち、正規の終了の場合、メッセージループのあるアプリなら
WM_QUERYENDSESSION や WM_ENDSESSION がくるので、それで処理すればいい。
これは UNIX でいうところの SIGTERM signal に相当する。
プロセスの抹消の場合はこういう猶予なしにただプログラムが抹消されるので、
特定の区間では受け付けない、なんてことは不可能。
同じく UNIX では SIGKILL に相当。
で、こういうの(ユーザーの操作による介入なしにただ一定の処理をする)って
普通は「サービス」にするものだが、それぢゃだめかいな?
シャットダウンの際には正規に終了メッセージが来るようになってるが。
ご返答ありがとうございます。
正規終了は、WM_QUERYENDSESSION・WM_ENDSESSIONが来るんですね!
test_process()のコール前後で『プログラム処理中』のフラグ操作して、
WM_QUERYENDSESSIONが来た場合、フラグが『プログラム処理中』であれば
プロセスを終了させないってすればいいんでしょうかね。
サンプルプログラムを作って試してみて、解決しましたらまた載せます!
試してみました。
------------------------------------------------------------------------------
bool isRun; // 処理中フラグ(true:処理中、false:処理していない)
//■メイン処理
_tWinMain(){
・・・
SetTimer( hWnds, 1, 10000, NULL ); // タイマー開始(10秒)
}
//■ウィンドウメッセージ処理
WndProc(){
switch( message ){
case WM_TIMER : // タイマー
isRun = true; // 処理中フラグ=1
test_process(); // プログラム処理
isRun = false; // 処理中フラグ=0
break;
case WM_QUERYENDSESSION :
if (isRun == true) { // 処理中か?
while( 1 ){
if( isRun == false ){ // 処理おわった?
break;
}
Sleep( 1000 );
}
return TRUE;
}
break;
case WM_ENDSESSION :
break;
・・・
}
}
//■プログラム処理
test_process(){
・・・処理中・・・ // ← ここで「プロセス終了」orシャットダウン!!!
return( 0 ); // ← このreturnまで処理したい!!!
}
------------------------------------------------------------------------------
ご教授していただいたとおり、シャットダウン時にWM_QUERYENDSESSIONが取れました!
しかし、WM_QUERYENDSESSIONの中の「return TRUE」を「return FALSE」としても、
シャットダウンされてしましました。
WinXPで試すと、シャットダウンせずにプロセスも生きたままだったんですが・・・。
また、最終的にはこのプロセスをサービスに登録して稼動させます。
試しで、サンプルプログラムをサービスに登録して実行してみると、
WM_QUERYENDSESSIONが取れませんでした。
(サービスに登録した場合は、WM_QUERYENDSESSIONではない?)
OSの違い? 32ビット機・64ビット機の違い?があるのでしょうか??
いろいろと試行錯誤してみた結果、
サンプルプロセスをサービスに登録し、サービスの「開始」でプロセスを起動。
起動中にPCのシャットダウンした場合、GetMessage()で何のメッセージも取得
されませんでした。
WM_QUERYENDSESSIONやWM_CLOSE、WM_QUITなどが取得されると思っていましたが、
WndProc()自体が呼ばれませんでした。
サービスの「開始」ではなく、手動でexeを起動させた場合は、WM_QUERYENDSESSIONが
取れました。
サービスに登録したプロセスが正常終了する場合、メッセージ(イベント?)を取得
することは可能なのでしょうか?
サービスの流儀と Windows Application の流儀は若干違うので、
Windows Application での常識をサービスに当てはめないほうがいいよ。
WM_(QUERY)ENDSESSION は Windows Application の話であって、
サービスではサービスマネージャから別のメッセージが来ることになっている。
で、当該処理を Windows Application で実装することにしたのか、
それともサービスで実装することにしたのか、どっちなんだろう。
サービスって無から作るのはめんどくさいので Microsoft が用意している
フレームワーク (ASP の CServiceModule とか .NET 系の ServiceBase とか) を
使って組むもんだ (俺は無から組んだことはない)
ネイティブ C++ ならたとえば
http://program.station.ez-net.jp/special/vc/atl/service_vc6.asp
マシンのシャットダウン時のメッセージ OnShutdown を受け取るには
SERVICE_CONTROL_SHUTDOWN をあらかじめセットしておく必要がある。
tetrapodさん、ありがとうございます!
当該処理はサービスで実装します。
いろいろと調べた結果「QueryServiceStatus()」でサービスの状態を取得できる
ようで、試してみたらできました。
これでシャットダウン時の検知はできたので後は何とかやってみます。
ご教授いただきありがとうございました!