0

I have a odd problem. I want to detect when windows wants to shutdown and stop it from shutting down using java. I thought about using a shutdown hook and just run a command shutdown /a however it doesnt seem to be working.

2 Answers2

1

You need to respond to the WM_QUERYENDSESSION message and return 0.

You can do it with JNA.

Another example here: https://github.com/mirror/jdownloader/blob/master/src/org/jdownloader/osevents/windows/jna/ShutdownDetect.java

kichik
  • 33,220
  • 7
  • 94
  • 114
  • I am fairly new to java coming from c#. With my research does this mean it would stop execution of my java program when this is being called? I imagine ill need to figure out a way to recover from a user trying to shutdown the system. – Mitch McCollum Apr 03 '20 at 17:20
  • 1
    It's up to you to terminate or not to terminate the program during message handling. You can return 0, ask Windows to stop the shut down, and then just do nothing to your program so it continues. – kichik Apr 03 '20 at 17:44
0

After battling with this problem few weeks and finally solving it i wanted to share the code here. Here is minimal example using java 1.8 and JNA 5.13.0 (also platform).

TIP: I had problem using this code first (unsatisfied links). I discovered i had library (jar file) on my JDK which had older JNA in it. Make sure you only have 1 version of JNA in your project.

import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.*;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinUser.*;
import com.sun.jna.win32.W32APIOptions;
import com.sun.jna.platform.win32.User32;

public class RealShutdownBlocker {
private static final int WM_QUERYENDSESSION = 0x0011;

    public static void main(String[] args) {
        User32 user32 = Native.loadLibrary("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS);

        WindowProc callback = new WindowProc() {
            public LRESULT callback(HWND hWnd, int message, WPARAM wParam, LPARAM lParam) {
                if (message == WM_QUERYENDSESSION) {
                    return new LRESULT(0);
                }
                return user32.DefWindowProc(hWnd, message, wParam, lParam);
            }
        };
        
        WNDCLASSEX windowClass = new WNDCLASSEX();
        windowClass.hInstance = null;
        windowClass.lpszClassName = "BlockShutdown";
        windowClass.lpfnWndProc = callback;
        user32.RegisterClassEx(windowClass);

        HWND hwnd = user32.CreateWindowEx(0, "BlockShutdown", "This prevents windows shutdown", WinUser.WS_OVERLAPPEDWINDOW, 100, 100, 640,
                480, null, null, null, null);

        // needs to be SW_SHOW for this to work
        user32.ShowWindow(hwnd, WinUser.SW_SHOW);

        MSG msg = new MSG();
        while (user32.GetMessage(msg, null, 0, 0) != 0) {
            user32.TranslateMessage(msg);
            user32.DispatchMessage(msg);
        }
    }
}

EDIT: No need for kernel32. Deleted it.

Kajisensi
  • 43
  • 6
  • interesting, but please add POM/classpath/jars you used to compile this code. – Tom Elias Feb 21 '23 at 08:48
  • https://github.com/java-native-access/jna Here you can download jna and jna-platform. I used latest (5.13.0 currently). I added them to my project with eclipse by "Add jars" But you could do it by just adding them to your POM – Kajisensi Feb 21 '23 at 09:35
  • Also loadLibrary() is deprecated but still kept. Can be changed to load() without problems. – Kajisensi Feb 21 '23 at 09:58