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 fromWTSOpenServer
- 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.