Ответ 1
Из addShutdownHook документация:
В редких случаях виртуальная машина может прервать работу, то есть прекратить работу, не выключая ее. Это происходит, когда виртуальная машина завершается снаружи, например, с сигналом SIGKILL в Unix или вызовом TerminateProcess в Microsoft Windows.
Так что, к сожалению, мне здесь нечего делать.
CTRL-CLOSE в консоли Windows. Кажется непривлекательным.
Цитата выше:
Система генерирует сигнал
CTRL+CLOSE
, когда пользователь закрывает консоль. Все процессы, подключенные к консоли, получают сигнал, давая каждому процессу возможность очистить до завершения. Когда процесс получает этот сигнал, функция обработчика может выполнить одно из следующих действий после выполнения любых операций очистки:
- Вызовите
ExitProcess
, чтобы завершить процесс. - Возврат
FALSE
. Если ни одна из зарегистрированных функций обработчика не возвращаетTRUE
, обработчик по умолчанию завершает процесс. - Возврат
TRUE
. В этом случае не вызываются никакие другие функции обработчика, а всплывающее диалоговое окно запрашивает у пользователя, прекратить ли процесс. Если пользователь решает не прекращать процесс, система не закрывает консоль до тех пор, пока процесс не завершится окончательно.
UPD. Если для вас приемлемы собственные твики, функция WinAPI SetConsoleCtrlHandler
открывает путь для подавления поведения по умолчанию.
UPD2. Откровения по обработке и завершению обработки сигналов Java относительно старой статьи, но раздел Написание обработчиков сигналов Java действительно может содержать то, что вам нужно.
UPD3.
Я пробовал обработчики сигналов Java из статьи выше. Он работает с SIGINT
красиво, но это не то, что нам нужно, и я решил нести его с помощью SetConsoleCtrlHandler
. Результат немного сложный и может не стоить реализовывать в вашем проекте. В любом случае, это может помочь кому-то другому.
Итак, идея заключалась в следующем:
- Сохраняйте ссылку на поток обработчика выключения.
- Установить пользовательскую процедуру обработчика собственных консолей с помощью JNI.
- Вызовите настраиваемый метод Java на
CTRL+CLOSE
сигнале. - Обработчик выключения вызова из этого метода.
Код 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"
для указания правильного завершения работы.
Полные источники с скомпилированными тестовыми двоичными файлами здесь.