Как сделать так, чтобы Java-приложение корректно завершало работу в Windows?

У меня есть Java-приложение, которое я хочу выключить "красиво", когда пользователь выбирает "Пуск" -> "Выключение". Я пытался использовать JVM слушателей завершения через Runtime.addShutdownHook(...), но это не работает, так как я не могу использовать какие-либо элементы пользовательского интерфейса из него.

Я также пытался использовать обработчик выхода в главном окне пользовательского интерфейса приложения, но, насколько я могу судить, он не может приостановить или остановить остановку. Как я могу справиться с выключением красиво?

3 ответа

Решение

Ранее упомянутый подход JNI, вероятно, будет работать.

Вы можете использовать JNA, которая в основном является оболочкой для JNI, чтобы упростить ее использование. Дополнительным бонусом является то, что он (по моему мнению, по крайней мере), как правило, быстрее и более удобен в обслуживании, чем необработанный JNI. Вы можете найти JNA по адресу https://jna.dev.java.net/

Если вы только запускаете приложение в меню "Пуск", потому что пытаетесь заставить его вести себя как служба в Windows, вы можете использовать оболочку службы Java, которая находится здесь: http://wrapper.tanukisoftware.org/doc/english/download.jsp

Насколько я знаю, вам нужно начать использовать JNI для настройки обработчика сообщений для сообщения Windows WM_QUERYENDSESSION.

Чтобы сделать это (если вы новичок в программировании Windows, как я), вам необходимо создать новый класс окна с новой функцией обработки сообщений (как описано здесь) и обработать WM_QUERYENDSESSION из обработчика сообщений.

NB. Вам нужно будет использовать JNIEnv::GetJavaVM(...), а затем JavaVM::AttachCurrentThread(...) в потоке обработки сообщений, прежде чем вы сможете вызывать любые методы Java из собственного кода обработки сообщений.

Вы можете использоватьsun.misc.Signalиsun.misc.SignalHandlerвнутренние классы для замены стандартныхjava.lang.Terminatorс вашим собственным обработчиком. Не забудьте позвонитьSystem::exitоттуда. JDK внутренне повышаетSIGTERMв ответ наWM_QUERYENDSESSION. Подробности смотрите в awt_Toolkit.cpp .

      public static void setQuitStrategy(Runnable handler) throws Exception {
    Class<?> signalClass = Class.forName("sun.misc.Signal");
    Class<?> signalHandlerClass = Class.forName("sun.misc.SignalHandler");

    Object signal = signalClass.getConstructor(String.class).newInstance("TERM");
    Object signalHandler = Proxy.newProxyInstance(signalHandlerClass.getClassLoader(), new Class[] { signalHandlerClass }, (proxy, method, args) -> {
        handler.run();
        return null;
    });

    Method handle = signalClass.getMethod("handle", new Class[] { signalClass, signalHandlerClass });
    handle.invoke(null, signal, signalHandler);
}
Другие вопросы по тегам