2017-12-15 2 views
3

Ich habe eine Anwendung, die einige Methoden beim Beenden verarbeiten muss. Wenn der Benutzer jedoch Windows herunterfährt, ohne zuvor die Anwendung zu schließen, wird die App von Windows beendet und die Methoden zum Herunterfahren werden nicht ausgeführt.JavaFX - Wie Windows Abmelde-/Abschaltanforderung zu erkennen?

Wie kann ich erkennen, wenn der Benutzer das Herunterfahren oder Abmelden von Windows angefordert hat? Die Methoden, die ich ausführen muss, dauern Millisekunden, so dass ich den Shutdown-Prozess nicht unbedingt verschieben oder unterbrechen muss.

Ich benutze bereits JNA, um auf die Maschine zu reagieren, die gesperrt/entsperrt wird, aber die onMachineLogoff() Methode scheint auch nicht auch Abschaltanforderungen zu fangen.

+0

Sehen Sie, wenn https://stackoverflow.com/questions/42598097/using-javafx-application-stop-method-over-shutdownhook hilft (ich habe nicht ein Windows Box verfügbar atm um dies zu testen). –

+0

Aber wenn die Anwendung das System herunterfährt, schließt das System alle Anwendungen, und Sie können Ihre Methoden in 'setOnCloseRequest()' hinzufügen. –

+0

@XlintXms 'setOnCloseRequest()' ist spezifisch für ein Fenster/eine Bühne, nicht für die gesamte Anwendung. –

Antwort

1

Es gibt three different scenarios, wenn Sie Abschalt- und Abmeldeereignisse verarbeiten können. Ich werde mich auf die Windows-Anwendung konzentrieren, weil es auch für Konsolenanwendungen funktioniert und wenn Ihre Anwendung aus irgendeinem Grund die Funktionen von User32 importiert, funktioniert das Konsolenhandle nicht.

Grundsätzlich erhalten Sie 2 Funktionen benötigen:

ATOM RegisterClassEx(WNDCLASSEX *lpwcx); 

RegisterClassEx eine neue Art von Fenster mit einem Haken erstellen (das unsere shutdown/Abmelde Handler) zugeordnet.

HWND WINAPI CreateWindowEx(
    int dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, 
    int dwStyle, int x, int y, int nWidth, int nHeight, 
    HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam 
); 

CreateWindowEx instanziiert ein neues Fenster, das Fenster ein Ereignis Haken (von der registrierten Klasse) zugeordnet hat, auf diese Weise Windows den zugehörigen Haken mit all possible events benachrichtigen.

hier ein voll funktionstüchtiges Beispiel, starten Sie es einfach und Abmelde oder Herunterfahren des Computers, nachdem sie wieder beginnen, werfen Sie einen Blick auf %userprofile%\shutdown-hook.log Datei muss diese Ereignisse behandelt haben durch so etwas wie

... 
action=proc-callback, event=22 
... 

code Anmeldung

public class Main { 

    /** 
    * <pre> 
    * Steps: 
    * 
    * 1. Create a WinProc (this function will handle all events) 
    * 2. Create a window class using the created WinProc 
    * 3. Create a window using the created window class 
    * 4. Use the WinProc to handle shutdown events 
    * </pre> 
    */ 
    public static void main(String[] args) { 
// registering a window - https://msdn.microsoft.com/pt-br/library/windows/desktop/ms633587 
//       https://msdn.microsoft.com/pt-br/library/windows/desktop/ms633577 
// typedef struct tagWNDCLASSEX { 
// UINT  cbSize; 
// UINT  style; 
// WNDPROC lpfnWndProc; 
// int  cbClsExtra; 
// int  cbWndExtra; 
// HINSTANCE hInstance; 
// HICON  hIcon; 
// HCURSOR hCursor; 
// HBRUSH hbrBackground; 
// LPCTSTR lpszMenuName; 
// LPCTSTR lpszClassName; 
// HICON  hIconSm; 
// } WNDCLASSEX, *PWNDCLASSEX; 
// 
// ATOM WINAPI RegisterClassEx(
// _In_ const WNDCLASSEX *lpwcx 
// ); 
     final WinUser.WNDCLASSEX clazz = new WinUser.WNDCLASSEX(); 
     clazz.lpszClassName = "MyCustomWindow"; 
     clazz.cbSize = Native.getNativeSize(WinUser.WNDCLASSEX.class, null); 
     clazz.lpfnWndProc = new MyWinProc(); 

     WinDef.ATOM classInst = User32.INSTANCE.RegisterClassEx(clazz); 
     System.out.printf("action=registerclass, clazz=%s, error=%d\n", classInst, Native.getLastError()); 

     WinDef.HWND w = User32.INSTANCE.CreateWindowEx(
      512, clazz.lpszClassName, "My Window", 
      WinUser.WS_OVERLAPPEDWINDOW, -2147483648, -2147483648, 250, 100, 
      null, null, null, null 
     ); 
     System.out.printf("action=createWindow, w=%s, error=%d\n", w, Native.getLastError()); 

     WinUser.MSG msg = new WinUser.MSG(); 
     while (User32.INSTANCE.GetMessage(msg, null, 0, 0)) { 
      User32.INSTANCE.DispatchMessage(msg); 
     } 
    } 

    public interface User32 extends Library { 

     User32 INSTANCE = Native.loadLibrary("User32", User32.class, W32APIOptions.UNICODE_OPTIONS); 

//  ATOM WINAPI RegisterClassEx(
//   _In_ const WNDCLASSEX *lpwcx 
//  ); 
     WinDef.ATOM RegisterClassEx(WinUser.WNDCLASSEX lpwcx); 

// HWND WINAPI CreateWindowEx(
// _In_  DWORD  dwExStyle, 
// _In_opt_ LPCTSTR lpClassName, 
// _In_opt_ LPCTSTR lpWindowName, 
// _In_  DWORD  dwStyle, 
// _In_  int  x, 
// _In_  int  y, 
// _In_  int  nWidth, 
// _In_  int  nHeight, 
// _In_opt_ HWND  hWndParent, 
// _In_opt_ HMENU  hMenu, 
// _In_opt_ HINSTANCE hInstance, 
// _In_opt_ LPVOID lpParam 
// ); 
     WinDef.HWND CreateWindowEx(
      int dwExStyle, 
      String lpClassName, 
      String lpWindowName, 
      int dwStyle, 
      int x, 
      int y, 
      int nWidth, 
      int nHeight, 
      WinDef.HWND hWndParent, 
      WinDef.HMENU hMenu, 
      WinDef.HINSTANCE hInstance, 
      WinDef.LPVOID lpParam 
     ); 

//  BOOL WINAPI GetMessage(
//   _Out_ LPMSG lpMsg, 
//   _In_opt_ HWND hWnd, 
//   _In_  UINT wMsgFilterMin, 
//   _In_  UINT wMsgFilterMax 
//  ); 
     boolean GetMessage(WinUser.MSG lpMsg, WinDef.HWND hWnd, int wMsgFilterMin, int wMsgFilterMax); 

//  LRESULT WINAPI DispatchMessage(
//   _In_ const MSG *lpmsg 
//  ); 
     WinDef.LRESULT DispatchMessage(WinUser.MSG lpmsg); 

     WinDef.LRESULT DefWindowProc(WinDef.HWND hWnd, int uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam); 
    } 

    /** 
    * <pre> 
    * All Possible events - 
    * https://msdn.microsoft.com/en-us/library/windows/desktop/ms644927.aspx#system_defined 
    * https://github.com/tpn/winsdk-10/blob/master/Include/10.0.10240.0/um/WinUser.h 
    * </pre> 
    */ 
    public static class MyWinProc implements WinUser.WindowProc { 
     private final OutputStream out; 

     public MyWinProc() { 
      try { 
       // this is unsafe because this file will never be closed, anyway it is just for a example 
       out = new FileOutputStream(new File(System.getProperty("user.home") + File.separator + "shutdown-hook.log")); 
      } catch (FileNotFoundException e) { 
       throw new RuntimeException(e); 
      } 
     } 

     @Override 
     public WinDef.LRESULT callback(WinDef.HWND hWnd, int uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam) { 
      final String msg = String.format("action=proc-callback, event=%d %n", uMsg); 
      System.out.print(msg); 
      try { 
       out.write(msg.getBytes()); 
       switch (uMsg){ 
        case 0x0016: 
         out.write("shutdown".getBytes()); 
         break; 
        case 0x0011: 
         out.write("logoff".getBytes()); 
         break; 
       } 
       out.flush(); 
      } catch (IOException e) { 
       throw new RuntimeException(e); 
      } 
      return User32.INSTANCE.DefWindowProc(hWnd, uMsg, wParam, lParam); 
     } 
    } 
} 

obs: nur ein Vorschlag, Ihre Anforderungen je denke ich, dass vielleicht kann mehr Sinn macht, wenn man nur einen Hintergrund-Thread statt und tim starten e nach der Zeit tun Sie die Aufgabe, die Sie tun müssen, wenn die Windows blue screen of death oder die Macht weggeht oder jemand nur den Strom abschalten dann werden die Windows-Ereignisse Ihnen nicht helfen. Auf jeden Fall ist Hintergrund Thread-Lösung sehr viel einfacher.

import java.util.concurrent.Executors; 
import java.util.concurrent.TimeUnit; 

public class Main { 

    public static void main(String[] args) { 
     Executors.newSingleThreadExecutor().execute(() -> { 
      while(!Thread.currentThread().isInterrupted()){ 
       System.out.println("do a background stuff"); 
       try { 
        TimeUnit.SECONDS.sleep(10); 
       } catch (InterruptedException e) {/*I will look at that in the while clause*/} 
      } 
     }); 
     System.out.println("doing another stuff"); 
    } 
} 

Meine Abhängigkeiten

compile group: 'net.java.dev.jna', name: 'jna', version: '4.5.0' 
compile group: 'net.java.dev.jna', name: 'jna-platform', version: '4.5.0'