Implementing a workstation lock listener using Java

The window is locked when you press WIN_HOME + L key together. We can find many good examples to listen for a window lock event in VB. But I am making a window listener for Java. I did some research and made a listener program that listens for the window lock event. It has two interfaces and one main program with JFrame and uses the JNA library.

WindowUser32.java

public interface WindowUser32 extends User32
{   public static final WindowUser32 MYINSTANCE = (WindowUser32) Native.loadLibrary("user32",  WindowUser32.class, W32APIOptions.UNICODE_OPTIONS);
public int SetWindowLong(WinDef.HWND hWnd, int nIndex, Callback callback);
}

      

WindowListener.java

public interface WindowListener extends StdCallCallback
{
public LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam);
}

      

And the main class LockListener.java

public class LockListener
{

public static void main(String[] args)
    {   
        JFrame frame = new JFrame();
    frame.setVisible(true);

    HWND hwnd = new HWND();
    hwnd.setPointer(Native.getWindowPointer(frame));

    Wtsapi32.INSTANCE.WTSRegisterSessionNotification(hwnd, Wtsapi32.NOTIFY_FOR_ALL_SESSIONS);

    WindowListener listener = new WindowListener()
    {
        @Override
        public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam)
        {
            if (uMsg == WinUser.WM_SESSION_CHANGE)
            {
                switch (wParam.intValue())
                {
                    case Wtsapi32.WTS_SESSION_LOCK:
                        System.out.println("Locked " + new Date());
                    break;

                    case Wtsapi32.WTS_SESSION_UNLOCK:
                        System.out.println("Unlocked "  + new Date());
                    break;
                }
            }
            return User32.INSTANCE.DefWindowProc(hWnd, uMsg, wParam, lParam);
        }
    };

    WindowUser32.MYINSTANCE.SetWindowLong(hwnd, WindowUser32.GWL_WNDPROC, listener);

    // Wtsapi32.INSTANCE.WTSUnRegisterSessionNotification(hwnd);
}
}

      

The above code works fine if our frame is visible, but does not work when the visibility of the frame is set to false or the frame is selected.

How can we implement the above listener if the frame is designated?

+3


source to share


2 answers


Seems to work with a "hidden window" as shown in the JNA Win32WindowDemo . So instead of binding a "native Windows event listener" to the JFrame, use a "hidden window" as a background service.

I have split Win32WindowDemo into question-specific parts and added some parts to start and stop as a background service. Note that the thread that creates the HWND must also be used to read messages for the HWND (if another thread tries to read the messages, nothing happens).

First, the main class shows a JFrame with messages from Win32WindowDemo:

import java.awt.*;
import javax.swing.*;

public class WinLockDetect {

public static void main(String[] args) {

    try {
        new WinLockDetect().demo();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@SuppressWarnings("serial")
void demo() throws Exception {

    final JTextArea detectMsgs =new JTextArea();
    final JFrame window = new JFrame() {{
        getContentPane().add(detectMsgs);
        setSize(400, 200);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }};
    EventQueue.invokeLater(new Runnable() {
        public void run() { 
            window.setVisible(true); 
        };
    });
    Win32EventDetector winSessionDetect = new Win32EventDetector();
    winSessionDetect.setMsgLogger(detectMsgs);
    new Thread(winSessionDetect).start();
    Thread.sleep(500L);
    window.setState(java.awt.Frame.ICONIFIED);
}

}

      



Here's a stripped-down version of Win32WindowDemo as a background service:

import java.util.concurrent.*;
import javax.swing.JTextArea;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.*;
import com.sun.jna.platform.win32.WinDef.*;
import com.sun.jna.platform.win32.WinUser.*;

public class Win32EventDetector implements WindowProc, Runnable {


/** FIXME: don't know if this number is a real message ID. */
private static final int DESTROY_LISTENER = 4242; 

volatile boolean closed = true;
Semaphore closing = new Semaphore(0);
WString windowClass;
HMODULE hInst;
HWND hWnd;
JTextArea detectMsgs;

public void setMsgLogger(JTextArea detectMsgs) {
    this.detectMsgs = detectMsgs;
}

void println(String msg) {

    if (detectMsgs == null) {
        System.out.println(msg);
    } else {
        detectMsgs.append('\n' + msg);
        detectMsgs.setCaretPosition(detectMsgs.getDocument().getLength());
    }
}

@Override
public void run() {

    // define new window class
    windowClass = new WString("Win32EventDetectorClass");
    hInst = Kernel32.INSTANCE.GetModuleHandle("");
    WNDCLASSEX wClass = new WNDCLASSEX();
    wClass.hInstance = hInst;
    wClass.lpfnWndProc = Win32EventDetector.this;
    wClass.lpszClassName = windowClass;
    // register window class
    User32.INSTANCE.RegisterClassEx(wClass);
    getLastError();
    // create new window
    hWnd = User32.INSTANCE
            .CreateWindowEx(
                    User32.WS_EX_TOPMOST,
                    windowClass,
                    "My hidden helper window, used only to catch the windows events",
                    0, 0, 0, 0, 0,
                    null, // WM_DEVICECHANGE contradicts parent=WinUser.HWND_MESSAGE
                    null, hInst, null);
    getLastError();
    println("window sucessfully created! window hwnd: "
            + hWnd.getPointer().toString());

    closed = false;
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() { close(); }
    });

    Wtsapi32.INSTANCE.WTSRegisterSessionNotification(hWnd,
            Wtsapi32.NOTIFY_FOR_THIS_SESSION);
    println("Listening for window messages.");
    try {
        MSG msg = new MSG();
        while (User32.INSTANCE.GetMessage(msg, hWnd, 0, 0) != 0) {
            if (msg.message == DESTROY_LISTENER) {
                System.out.println("Got destroy message.");
                break;
            }
            println("Got a new message: " + msg.message);
            User32.INSTANCE.TranslateMessage(msg);
            User32.INSTANCE.DispatchMessage(msg);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("Stopped listening for window messages.");
    destroy();
}

private void destroy() {

    try {
        Wtsapi32.INSTANCE.WTSUnRegisterSessionNotification(hWnd);
        User32.INSTANCE.UnregisterClass(windowClass, hInst);
        User32.INSTANCE.DestroyWindow(hWnd);
        System.out.println("Hidden native window destroyed.");
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        closed = true;
        closing.release();
    }
}

public void close() {

    if (closed) { return; }
    User32.INSTANCE.PostMessage(hWnd, DESTROY_LISTENER, null, null);
    try {
        if (closing.tryAcquire(1000L, TimeUnit.MILLISECONDS)) {
            System.out.println("Hidden native window closed.");
        } else {
            System.out.println("Hidden native window could not be closed within time-out.");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public LRESULT callback(HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WinUser.WM_CREATE: {
        println("onCreate: WM_CREATE");
        return new LRESULT(0);
    }
    case WinUser.WM_DESTROY: {
        User32.INSTANCE.PostQuitMessage(0);
        return new LRESULT(0);
    }
    case WinUser.WM_SESSION_CHANGE: {
        this.onSessionChange(wParam, lParam);
        return new LRESULT(0);
    }
    default:
        return User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

public int getLastError() {
    int rc = Kernel32.INSTANCE.GetLastError();
    if (rc != 0)
        println("error: " + rc);
    return rc;
}

protected void onSessionChange(WPARAM wParam, LPARAM lParam) {
    switch (wParam.intValue()) {
    case Wtsapi32.WTS_CONSOLE_CONNECT: {
        println("WTS_CONSOLE_CONNECT");
        break;
    }
    case Wtsapi32.WTS_CONSOLE_DISCONNECT: {
        println("WTS_CONSOLE_DISCONNECT");
        break;
    }
    case Wtsapi32.WTS_SESSION_LOGON: {
        println("WTS_SESSION_LOGON");
        break;
    }
    case Wtsapi32.WTS_SESSION_LOGOFF: {
        println("WTS_SESSION_LOGOFF");
        break;
    }
    case Wtsapi32.WTS_SESSION_LOCK: {
        println("WTS_SESSION_LOCK");
        break;
    }
    case Wtsapi32.WTS_SESSION_UNLOCK: {
        println("WTS_SESSION_UNLOCK");
        break;
    }
    default: 
        println("Session change " + wParam.intValue());
        break;
    }
}

}

      

I tested this with JNA 4.1.0 (downloaded from here ) on Windows Vista 64bit using WINHOME_KEY + L. The background thread for the "hidden window" is stopped by the shutdown trigger, which fires when the JFrame from the main class is closed.

+3


source


I think you want to run the task in the background, so I highly recommend using swingworker to do this, so it doesn't matter if you set the visible to true or not in this case. In addition, you also have to select a specific event for actions or window states. If you select a window and want to perform tasks, then copy it under this event.

Window or state actions can precede window events:

Please see some examples on how to implement swingworker

How can I use the SwingWorker example correctly?



Extended Java: Multithreading Part 15 - Swing and the SwingWorker Class

How do I use SwingWorker in Java?

Java GUI threads - SwingWorker

-1


source







All Articles