19

Java アプリケーションを実行するバット スクリプトがあります。その上で ctrl+c を押すと、アプリケーションは正常に終了し、すべてのシャットダウン フックが呼び出されます。ただし、bat スクリプトの cmd ウィンドウを閉じるだけでは、シャットダウン フックは呼び出されません。

これを解決する方法はありますか?おそらく、ウィンドウが閉じられたときに呼び出されたアプリケーションを終了する方法をバットスクリプトに伝える方法はありますか?

4

3 に答える 3

22

addShutdownHookドキュメントから:

まれに、仮想マシンが異常終了する場合があります。つまり、正常にシャットダウンせずに実行を停止する場合があります。これは、仮想マシンが外部で終了した場合に発生します。たとえば、Unix の SIGKILL シグナルや Microsoft Windows の TerminateProcess 呼び出しによって発生します。

残念ながら、ここで何もする必要はないと思います。


Windows コンソールの CTRL-CLOSEシグナル。微調整できないようです。

上記のリンクを引用:

CTRL+CLOSEユーザーがコンソールを閉じると、システムはシグナルを生成します。コンソールに接続されているすべてのプロセスがシグナルを受信し、各プロセスが終了する前にクリーンアップする機会を与えます。プロセスがこのシグナルを受信すると、ハンドラー関数は、クリーンアップ操作を実行した後、次のいずれかのアクションを実行できます。

  • 呼び出しExitProcessてプロセスを終了します。
  • 戻るFALSE。登録されたハンドラー関数が を返さない場合TRUE、デフォルトのハンドラーはプロセスを終了します。
  • 戻るTRUE。この場合、他のハンドラー関数は呼び出されず、ポップアップ ダイアログ ボックスがユーザーにプロセスを終了するかどうかを尋ねます。ユーザーがプロセスを終了しないことを選択した場合、システムはプロセスが最終的に終了するまでコンソールを閉じません。

UPD。ネイティブの微調整が受け入れられる場合、WinAPISetConsoleCtrlHandler関数はデフォルトの動作を抑制する方法を開きます。

UPD2Java シグナル処理と終了に関する啓示 は比較的古い記事ですが、「Java シグナル ハンドラーの記述」セクションには実際に必要なものが含まれている可能性があります。


UPD3 . 上記の記事のJavaシグナルハンドラーを試しました。それはSIGINTうまく機能しますが、私たちが必要としているものではなく、私はそれを持ち歩くことにしましたSetConsoleCtrlHandler. 結果は少し複雑で、プロジェクトに実装する価値がないかもしれません。とにかく、それは他の誰かを助けることができます。

したがって、アイデアは次のとおりです。

  1. シャットダウン ハンドラ スレッドへの参照を保持します。
  2. JNI を使用してカスタム ネイティブ コンソール ハンドラ ルーチンを設定します。
  3. シグナルでカスタム Java メソッドを呼び出しますCTRL+CLOSE
  4. そのメソッドからシャットダウン ハンドラを呼び出します。

Java コード:

public class TestConsoleHandler {

    private static Thread hook;

    public static void main(String[] args) {
        System.out.println("Start");
        hook = new ShutdownHook();
        Runtime.getRuntime().addShutdownHook(hook);
        replaceConsoleHandler(); // actually not "replace" but "add"

        try {
            Thread.sleep(10000); // You have 10 seconds to close console
        } catch (InterruptedException e) {}
    }

    public static void shutdown() {
        hook.run();
    }

    private static native void replaceConsoleHandler();

    static {
        System.loadLibrary("TestConsoleHandler");
    }
}

class ShutdownHook extends Thread {
    public void run() {
        try {
            // do some visible work
            new File("d:/shutdown.mark").createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Shutdown");
    }
}

ネイティブreplaceConsoleHandler:

JNIEXPORT void JNICALL Java_TestConsoleHandler_replaceConsoleHandler(JNIEnv *env, jclass clazz) {
    env->GetJavaVM(&jvm);
    SetConsoleCtrlHandler(&HandlerRoutine, TRUE);
}

そしてハンドラ自体:

BOOL WINAPI HandlerRoutine(__in DWORD dwCtrlType) {
    if (dwCtrlType == CTRL_CLOSE_EVENT) {
        JNIEnv *env;
        jint res =  jvm->AttachCurrentThread((void **)(&env), &env);
        jclass cls = env->FindClass("TestConsoleHandler");
        jmethodID mid = env->GetStaticMethodID(cls, "shutdown", "()V");
        env->CallStaticVoidMethod(cls, mid);
        jvm->DetachCurrentThread();
        return TRUE;
    }
    return FALSE;
}

そして、それは機能します。JNI コードでは、クリアランスのためにすべてのエラー チェックが省略されています。シャットダウン ハンドラ"d:\shutdown.mark"は、正しいシャットダウンを示すために空のファイルを作成します。

コンパイル済みのテスト バイナリを含む完全なソースは、こちら にあります

于 2012-02-14T13:33:01.687 に答える
0

バッチ ファイルは終了する可能性がありますが、オペレーティング システム、コマンド プロセッサ、およびバッチ ファイルの実行がどのように開始されたか (コマンド プロンプトまたはショートカット)。

taskkillWindowsで配布されているプログラムを終了するための良いコマンドです(バッチファイル自体ではなく、別のプログラムを停止したいと思っています)。

プロセス ID、実行可能ファイル名、ウィンドウ タイトル、ステータス (応答なし)、DLL 名、またはサービス名によってプログラムを終了できます。

バッチ ファイルでこれを使用する方法に基づいたいくつかの例を次に示します。

"program.exe" を強制的に停止します (多くの場合、プログラムを強制的に停止するには /f "force" フラグが必要です。試行錯誤して、アプリケーションに必要かどうかを確認してください)。

taskkill /f /im program.exe 

応答しないプログラムを停止します。

taskkill /fi "Status eq NOT RESPONDING"

ウィンドウのタイトルに基づいてプログラムを停止します (* ワイルドカードはここで何にでも一致させることができます):

taskkill /fi "WindowTitle eq Please Login"

taskkill /fi "WindowTitle eq Microsoft*"

これを使用して、ネットワーク上の別のコンピューターでプログラムを停止することもできます (ただし、アカウントのパスワードをバッチ ファイルに書き込むことはお勧めできません)。

taskkill /s JimsPC /u Jim /p James_007 /im firefox.exe

Windows にも配布されている別の代替手段はtskill. それほど多くのオプションはありませんが、コマンドは少し単純です。

編集:

あるかどうかわかりません。cmdウィンドウを閉じることは、アプリに似ていると思いますforce-closing。つまり、通知なしですぐに終了します。これには多くのアプリケーションの動作があり、要求されたforce-closeときに最終的に終了するまでに実際には長い時間がかかります。これは、OS がすべてのリソースを解放しようとする際に、一部のリソース (特に特定の I/O リソースやファイル リソース) がすぐに解放されないためです。

IMO、必要に応じてJavaができることは何もありません。強制クローズは OS レベルで発生し、その時点で使用中のメモリ、ファイル、I/O ハンドルなどを解放します。Java は (他のプログラムも) 強制クローズを制御できません。この時点で、OS が担当します。

私が間違っている場合は、誰かが私を修正してください。

于 2012-02-14T13:43:37.740 に答える