如何使用 WTSSendMessage 显示消息?

How to display message using WTSSendMessage?

我想在任务完成时向用户显示一些消息。但是该应用程序是 运行 作为一项服务,因此无法使用 UI 组件。

Microsoft 文档说我们可以使用 win32 API: WTSSendMessage 来显示对话框。我浏览了 JNA 文档,但找不到关于这个特定内容的任何参考。我想为 Java 应用程序执行此操作。有办法通过JNA吗?

Link 到 WTSSendMessageA 的文档:https://docs.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi32-wtssendmessagea

以下是 Microsoft 建议的其他一些方法: https://docs.microsoft.com/en-us/windows/win32/services/interactive-services?redirectedfrom=MSDN

根据the link you provided,服务可以

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

JNA 由 jna 工件中的基本功能和 jna-platform 工件中的 user-contributed 映射组成。虽然 Wtsapi32 class 存在于 JNA 中,但仅映射了该 dll 的一些函数,但未映射 WTSSendMessage.

我注意到您将文档链接到后缀为 -A 的版本:这是不适用于 windows 的任何现代版本的“ANSI”映射。如果使用 WinAPI 默认类型映射器映射 un-suffixed 版本,它将自动选择正确的 -A 或 -W 后缀版本(不同之处在于 -W 使用 UTF16 宽字符串,而 -A 使用 8 位 ASCII) .但为了您的方便,您可以只映射 -W 版本,WTSSendMessageW.

查看参数列表,您需要:

  • WTSOpenServer
  • 获得的HANDLE
  • 发送至session(可以使用当前的session)
  • 您可以创建的标题栏字符串
  • 您可以创建的消息
  • 一种风格(你可以使用“OK”版本)
  • 超时
  • 接收响应值的指针

对于服务器句柄,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.

这已经在 J​​NA 中映射(它是一个 HANDLE 包装 null)。

所以你只需要映射WTSSendMessage函数。类型映射很简单。 HANDLELPWSTR 在 JNA 中映射,您应该对 DWORD args 使用 int,对 BOOL 使用 boolean。您将使用一个接口,并扩展现有的 JNA 映射以获得对其功能的访问:

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);
}

然后使用函数。我们可以使用当前服务器句柄,当前 session,创建要传递的字符串,使用“OK”样式,并通过传递 false 作为等待参数来忽略 timeout/response。

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()

这一切都未经测试。您需要适当的导入。