通过JNA发送用户定义的Windows消息
Send a user-defined Windows-message through JNA
我想要一件简单但困难的事情:从JNA端发送一条特定的用户定义的Windows消息,以便该消息被C++端的消息循环(GetMessage()
/DispatchMessage()
)捕获,然后该消息循环将被中断。实际上,它应该通过Swing GUI中的按钮点击来执行。我的问题和考虑:
1) 例如,假设我在C++端将自己的消息定义为#define WM_CUSTOM_MSG (WM_USER+42)
,当然,在C++端的消息循环中添加一个适当的if语句用于中断。但我的目的是从java发送这个消息。
2) 为此,我写了以下内容:
public class User32Ext {
interface User32Interface extends User32 {
User32Interface INSTANCE = Native.load("user32",
User32Interface.class, W32APIOptions.DEFAULT_OPTIONS);
@Override
HWND FindWindowEx(HWND lpParent, HWND lpChild, String lpClassName, String lpWindowName);
HWND GetTopWindow(HWND hwnd);
HWND GetParent(HWND hwnd);
@Override
HWND GetDesktopWindow();
int SendMessage(HWND hWnd, int Msg, IntByReference wParam, IntByReference lParam);
void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
void SwitchToThisWindow(HWND hWnd, boolean fAltTab);
}
private final User32Interface u32 = User32Interface.INSTANCE;
public User32Ext() {
super();
// TODO Auto-generated constructor stub
}
public void sendInterruptMessage(final String windowName) {
try {
final User32.HWND hwnd = u32.FindWindowEx(null, null, null, windowName);
final int msg = 0x400 + 42;
final User32.WPARAM wparam = new User32.WPARAM();
final User32.LPARAM lparam = new User32.LPARAM();
final LRESULT res = u32.SendMessage(hwnd, msg, wparam, lparam);
} catch (final RuntimeException e) {
e.printStackTrace();
}
}
}
然后只创建一个这个伪类的对象,并在按钮事件中使用我的JFrame
的标题作为参数来调用sendInterruptMessage
。
遗憾的是,双方都没有发现任何影响。我很确定我犯了一些致命的错误,因为我对Windows和JNA编程不够熟悉。那么,你能告诉我,至少我在概念上是对的,实现这样的期望结果吗?或者只是Java方面存在一些编程错误。谢谢
附言:如果它可以在不发送自定义消息的情况下实现,但使用一些标准的Windows消息,那就太好了,我只想确定,这个消息所做的唯一事情就是中断我的C++消息循环。
在将WINAPI函数映射到JNA时,必须注意将Windows API定义与适当的Java/JNA类型精确匹配。您的某些映射是错误的。SendMessage
的最后两个参数是WPARAM
和LPARAM
,它们似乎在sendInterruptMessage()
映射中使用。它们正在调用JNA项目中已经映射的SendMessage
函数。在自己的SendMessage
映射中放入什么并不重要,因为您甚至没有调用它,因为您使用的是不同的类型。删除它。另外,从超类中删除已放置@Override
的两个方法。你没有理由覆盖他们已经在做的事情。
事实上,经过进一步检查,你似乎从这个答案中复制了别人在2014年写的代码。然而,您需要的映射已于2017年添加到JNA项目中。在不知道代码的作用的情况下复制代码并不是成功的秘诀。不需要您的整个界面。只需调用JNA的User32
接口。
在对FindWindowEx
的调用中,前三个参数传递null,第四个参数只放置String。这似乎与API不匹配,后者似乎不允许将null作为第三个参数。您检查过返回的句柄是否为空吗?很可能是这样,根据API,您可以使用GetLastError
查看错误代码,该错误代码可能与不正确的参数有关。
第三个参数的文档指定,
如果lpszClass是一个字符串,它会指定窗口类名。这个类名可以是在RegisterClass或RegisterClassEx,或任何预定义的控件类名,或可以是MAKEINTATOM(0x8000)。在后一种情况下,0x8000是原子对于菜单类。有关详细信息,请参阅的备注部分这个主题。
它看起来不像是您在按要求执行此操作。
如果第一次调用成功(这会让我感到惊讶),那么评估现有SendMessage
调用的LRESULT
返回值,看看它是否指示成功或生成错误代码,这将对您很有指导意义。事实上,您可能正在向它传递一个null句柄,在这种情况下,什么都没有发生也就不足为奇了。
从检查指示成功/失败的方法返回值开始,并评估错误代码应该有助于调试。
最后,正如iinspectable在评论中指出的那样,您传递的代码不是自定义消息。根据文件,
消息标识符值如下所示:
系统为系统定义的
消息保留范围从0x0000到0x03FF(WM_USER–1的值)的消息标识符值。应用程序不能将这些值用于私人消息。范围0x0400(WM_USER的值)到0x7FFF中的值可用于专用窗口类的消息标识符。
如果应用程序标记为4.0版,则可以使用0x8000(WM_APP)到0xBFFF范围内的消息标识符值用于私人消息。
- 当应用程序调用RegisterWindowMessage函数
来注册消息时,系统会返回范围从0xC000到0xFFFF的消息标识符。此
函数返回的消息标识符保证在整个系统中是唯一的。使用
此功能可以防止在其他应用程序中可能出现的冲突将相同的消息标识符用于不同的目的
阅读WINAPI文档以了解每个参数中的预期内容将帮助您找到要传递的正确值,这对于从代码中获得预期结果至关重要。
- 通过JNA发送用户定义的Windows消息
- 什么是窗口最大化/最小化/恢复的WM Windows消息
- 注册以在 MFC 中发出 Win32 事件信号时接收 Windows 消息
- 在控制台应用程序中处理空的windows消息队列
- 处理Windows消息,以便我的应用程序正确响应
- 相对于 3D 应用程序中的 Windows 消息循环的计时错误
- infine windows消息循环-c++
- 如何使用QCoreApplication::winEventFilter处理Windows消息
- Sleep() in Windows 消息循环
- 奇怪的Windows消息序列WM_KEYDOWN/WM_KEYUP,同时按VK_MENU(Alt键)
- Windows 消息过程的函数指针数组
- winapi - 未记录的 Windows 消息0x0313稳定
- 来自 GetMessage 的 Windows 消息 9
- 如何正确处理来自MSFTEDIT_CLASS(RichEdit)控件的Windows消息
- 无限循环中的Windows消息泵
- Windows消息传递-获取非客户端区域的设备上下文的各种方法
- 处理来自子类的windows消息
- C++GetAsyncKeyState和GetCursorPos与Windows消息传递的比较
- 正在获取windows消息名称
- 使用Windows消息循环的回调实现