Home > Mobile >  How to display message using WTSSendMessage?
How to display message using WTSSendMessage?

Time:04-19

I want to display some message to the user when a task is completed. But the Application is running as a service, so it's not possible to use a UI component.

Microsoft documentation says we can use win32 API: WTSSendMessage to show a dialog box. I went through the JNA documentation but couldn't find any reference for this specific thing. I want to do this for a Java application. Is there a way through JNA?

Link to the documentation of WTSSendMessageA: https://docs.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi32-wtssendmessagea

Here are some other ways suggested by Microsoft: https://docs.microsoft.com/en-us/windows/win32/services/interactive-services?redirectedfrom=MSDN

CodePudding user response:

According to the link you provided, a service can

Display a dialog box in the user's session using the WTSSendMessage function.

JNA is comprised of the base functionality in the jna artifact and user-contributed mappings in the jna-platform artifact. While the Wtsapi32 class exists in JNA, only some of that dll's functions have been mapped, but not WTSSendMessage.

I note you linked the docs to the -A suffixed version: this is the "ANSI" mapping that does not apply to any modern version of windows. If you map the un-suffixed version using the WinAPI default type mapper, it will automatically choose the correct -A or -W suffixed version (the difference is that -W uses UTF16 wide strings while -A uses 8-bit ASCII). But for your convenience you can just map the -W version, WTSSendMessageW.

Looking down the list of arguments, you need:

  • A HANDLE obtained from WTSOpenServer
  • The session to send to (you can use the current session)
  • A title bar string you can create
  • A message you can create
  • A style (you can just use the "OK" version)
  • A timeout
  • A pointer to receive the response value

For the server handle, the docs for WTSOpenServer state

You do not need to open a handle for operations performed on the RD Session Host server on which your application is running. Use the constant WTS_CURRENT_SERVER_HANDLE instead.

This is already mapped in JNA (it's a HANDLE wrapping null).

So you just need to map the WTSSendMessage function. The type mappings are straightforward. HANDLE and LPWSTR are mapped in JNA, and you should use int for the DWORD args and boolean for BOOL. You'll use an interface, and extend the existing JNA mapping to obtain access to its functions:

public interface MyWtsapi32 extends com.sun.jna.platform.win32.Wtsapi32 {
    // Your own instance to access your functions
    MyWtsapi32 INSTANCE = Native.load("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);

    // From https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox
    int MB_OK = 0; 

    // The function to send the message
    boolean WTSSendMessageW(HANDLE hServer, int SessionId,
        LPWSTR pTitle, int TitleLength,
        LPWSTR pMessage, int MessageLength,
        int Style, int Timeout, IntByReference pResponse, boolean bWait);
}

Then use the functions. We can use the current server handle, the current session, create our strings to pass, use the "OK" style, and ignore the timeout/response by passing false as the wait parameter.

LPWSTR pTitle = new LPWSTR("Message box title");
int titleLength = ("Message box title".length()   1) * Native.WCHAR_SIZE;
LPWSTR pMessage = new LPWSTR("Hello World!");
int messageLength = ("Hello World!".length()   1) * Native.WCHAR_SIZE;
IntByReference pResponse = new IntByReference();

MyWtsapi32.INSTANCE.WTSSendMessageW(
    WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION,
    pTitle, titleLength,
    pMessage, messageLength,
    MB_OK, 0, pResponse, false);
// should return IDASYNC in pResponse.getValue()

This is all untested. You'll need appropriate imports.

  • Related