3

setconsolehandler()コンソールの終了イベントを管理する場合は、を使用する必要があることを知っています。

をブロックする方法がわかりませんCTRL_CLOSE_EVENT。そのイベントをキャッチした場合、false / trueを返そうとしましたが、成功しませんでした

これが私がこれまでに持っているものです(アントン・ゴゴレフに感謝します!)

[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

public delegate bool HandlerRoutine(CtrlTypes CtrlType);

public enum CtrlTypes{
    CTRL_C_EVENT = 0,
    CTRL_BREAK_EVENT,
    CTRL_CLOSE_EVENT,
    CTRL_LOGOFF_EVENT = 5,
    CTRL_SHUTDOWN_EVENT
}

private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{ 
    if(ctrlType == CtrlTypes.CTRL_CLOSE_EVENT)
        return false;// I have tried true and false and viceversa with the return   
                     // true/false but I cant seem to get it right.
    return true;
}


//and then I use this to call it
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

また、新しいスレッドを実行してコンソールが閉じているかどうかを監視し、メインスレッドが何かを実行している途中でその閉じをブロックすることは可能ですか?

4

3 に答える 3

7

のドキュメントにSetConsoleCtrlHandler()は次のように書かれています:

ユーザーがコンソールを閉じたり、ログオフしたり、システムをシャットダウンしたりすると、システムは CTRL_CLOSE_EVENT、CTRL_LOGOFF_EVENT、および CTRL_SHUTDOWN_EVENT シグナルを生成し、プロセスが終了前にクリーンアップできるようにします。

これは、CTRL+C または CTRL+BREAK イベントを処理する場合とは異なり、プロセスがクローズ、ログオフ、またはシャットダウンをキャンセルする機会を得られないことを意味します。

于 2009-02-10T18:17:32.057 に答える
1

コンソールのクローズ要求にきちんと従いながら、アプリケーションのクローズを妨げる可能性のある「ハック」の可能性を見つけました。特に、これはコンソールを「おまけ」として作成した GUI アプリケーションに適していると思います。MSDN のドキュメントによると、Ctrl ハンドラーが呼び出される時点で、ハンドラーを呼び出すプロセスで新しいスレッドが作成されます。したがって、私の解決策は、デフォルト ハンドラーが ExitProcess を呼び出す前に、攻撃している侵入スレッドを強制終了することです。ハンドラー ルーチン内 (C++ のコード):

// Detach Console:
FreeConsole();
// Prevent closing:
ExitThread(0);
return TRUE; // Not reached

編集:予想通り、これはいくつかの問題を引き起こしているようです。AllocConsole() への後続の呼び出しは無期限にハングするため、スレッドを途中で終了すると適切にクリーンアップできないと思われます。

編集2:

上記を明確にするために、プログラムを実行し続けることに直接的な問題は見つかりませんでした。ただし、kernel32 が作成したスレッドを強制的に終了したため、kernel32 内のリソースは不確定な状態になる可能性があることに注意してください。これにより、プログラムを実行し続けると、予期しない問題が発生する可能性があります。

ほとんどの場合、これらの問題はコンソール API に関連していると思います。前述のように、AllocConsoleこの時点以降は機能しません (アプリケーションがハングします)。そのため、プログラムは新しいコンソールを開くことができません。他のコンソール機能も失敗する可能性が高いです。基本的に、その時点以降、kernel32 を (直接的または間接的に) 呼び出すことはすべて、未定義の動作の対象となりますが、実際にはコンソール機能以外に問題はないと思われます。

私の結論は、可能な限りこの方法を避けるべきだということですが、早期終了がより悪い場合、これは緊急の回避策と考えられ、控えめに注意して使用することができます.

于 2013-08-26T13:14:05.033 に答える
1

実際にはブロックできます (少なくとも Windows XP ではこれを再現しました)。たとえば、ハンドラーにスリープ状態の無限 while ループがある場合、これにより、このプロセスが永久に (または少なくとも長時間、またはユーザーがタスク マネージャーを介してプロセスを強制終了するまで) 終了するのを停止します。

本当にスレッドを開始する必要がある場合は、( AutoResetEventC# で) 待機条件を使用してスレッドを開始し (ほとんどの場合、新しいスレッドはおそらく必要ありません)、スレッドが終了したときに待機状態を通知します。ただし、ほとんどの場合、ハンドラーでクリーンアップを行うだけで十分です。

最悪の場合、永遠に待機した場合でも、プロセスは実行されたままになり、再度ログインしたときに確認できます (少なくとも Windows XP では)。ただし、これにより、デスクトップがログアウト画面に移動する前に約 20 秒間一時停止し (アプリケーションが終了するのを待機している間)、ログアウト画面で再び一時停止します (2 回目の試行中と思われます)。 . もちろん、永遠に待つことは強くお勧めしません。長時間実行されるものについては、これを実際にサービスに入れる必要があります。

于 2012-07-14T03:36:09.523 に答える