我想要一个简单但困难的事情:从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();
}
}
}
然后仅创建此伪类的对象,并在按钮事件中以我的sendInterruptMessage
的标题作为参数调用JFrame
。
可悲的是,双方都没有发现任何影响。我非常确定我犯了一些致命的错误,因为我对Windows和JNA编程还不够熟悉。那么,您能否告诉我,至少我在概念上是正确的,实现了这样的预期结果?或Java方面仅存在一些编程错误。谢谢!
P.S。如果可以在不发送自定义消息的情况下实现它,但是使用一些标准的Windows消息,那就很好了,我只想确定,此消息唯一要做的就是中断我的C ++消息循环。
将WINAPI函数与JNA映射时,必须注意将Windows API定义与相应的Java / JNA类型完全匹配。您的某些映射是错误的。 SendMessage
的最后两个参数是WPARAM
和LPARAM
,您似乎在sendInterruptMessage()
映射中使用它们。这些被称为already-mapped SendMessage
function in the JNA project。放入自己的SendMessage
映射中没有关系,因为您甚至没有调用它,因为您正在使用不同的类型。删除它。还要从超类中删除您已打开SendMessage
的两个方法。您没有理由覆盖他们已经在做什么。
实际上,经过进一步检查,似乎您已复制了他人在2014年编写的代码@Override
。但是,2017年需要映射from this answer。在不知道代码作用的情况下复制代码并不是成功的秘诀。不需要您的整个界面。只需调用JNA的were added to the JNA project接口。
在对User32
的调用中,您为前三个参数传递了null,并且仅在第四个参数中放置了String。这似乎不匹配FindWindowEx
。您是否检查了返回的句柄是否为空?可能是这样,根据API,您可以使用the API which does not appear to allow null as the third argument查看该错误代码,该错误代码很可能与不正确的参数相关联。
第三个参数的文档指定,
如果lpszClass是一个字符串,则它指定窗口类名称。的类名可以是在RegisterClass中注册的任何名称,也可以是RegisterClassEx或任何预定义的控件类名称,或者它可以是MAKEINTATOM(0x8000)。在后一种情况下,0x8000是原子菜单类。有关更多信息,请参见这个主题。
似乎没有按照要求执行。
如果第一次调用成功(这会让我感到惊讶),那么对您评估现有GetLastError
调用的LRESULT
返回值,并查看它是否指示成功或生成错误代码,将对您很有帮助。实际上,您可能会向其传递一个null句柄,在这种情况下,什么也没有发生就不足为奇了。
首先检查表示成功/失败的方法返回值并评估错误代码应有助于调试。
最后,如注释中的SendMessage
所示,您传递的代码不是自定义消息。 iinspectable,
消息标识符值使用如下:
系统保留系统定义的消息标识符值,范围从0x0000到0x03FF(WM_USER的值– 1)消息。应用程序不能将这些值用于私人消息。
0x0400(WM_USER的值)到0x7FFF范围内的值可用于私有窗口类的消息标识符。
如果您的应用程序标记为版本4.0,则可以使用0x8000(WM_APP)到0xBFFF范围内的消息标识符值用于私人消息。
- 当应用程序调用RegisterWindowMessage函数时,系统返回消息标识符,范围从0xC000到0xFFFF。注册消息。由此返回的消息标识符保证功能在整个系统中都是唯一的。用于此功能可防止其他应用程序发生冲突将相同的消息标识符用于不同的目的。
阅读WINAPI文档以了解每个参数的期望值将有助于您找到正确的值,这对于从代码中获得期望的结果至关重要。