我正在尝试用Java编写一个与USB设备通信的简单应用程序。 USB设备由我使用Microchip微控制器制造。通信相当简单,因为USB设备来自HID类,所以在计算机和设备之间交换64字节的数组。 我的程序根据产品ID和供应商ID查找设备,可以写入和读取64个字节,但现在我想检测设备何时连接或断开计算机。
正如我在Microchip提供的C#程序中看到的那样,WndProc方法被覆盖并处理WM_DEVICECHANGE消息。我的问题是如何使用JNA在Java中完成,我如何覆盖WindowProc方法并处理消息,如果可能的话:),但我希望它是:D
提前感谢您的答案。
的Gabor。
答案 0 :(得分:8)
我终于设法解决了问题:)我找到了以下解决方案:
首先以下列方式扩展User32接口
public interface MyUser32 extends User32 {
public static final MyUser32 MYINSTANCE = (MyUser32) Native.loadLibrary("user32", MyUser32.class, W32APIOptions.UNICODE_OPTIONS);
/**
* Sets a new address for the window procedure (value to be set).
*/
public static final int GWLP_WNDPROC = -4;
/**
* Changes an attribute of the specified window
* @param hWnd A handle to the window
* @param nIndex The zero-based offset to the value to be set.
* @param callback The callback function for the value to be set.
*/
public int SetWindowLong(WinDef.HWND hWnd, int nIndex, Callback callback);
}
然后使用您需要的Windows消息代码扩展WinUser接口,在我的情况下,这是WM_DEVICECHANGE,因为我想检查我是否已将USB设备连接到计算机或从计算机上分离。
public interface MyWinUser extends WinUser {
/**
* Notifies an application of a change to the hardware configuration of a device or the computer.
*/
public static final int WM_DEVICECHANGE = 0x0219;
}
然后用回调函数创建一个接口,它实际上是我的WndProc函数。
//Create the callback interface
public interface MyListener extends StdCallCallback {
public LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam);
}
public MyListener listener = new MyListener()
{
public LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam)
{
if (uMsg == MyWinUser.WM_DEVICECHANGE)
{
// TODO Check If my device was attached or detached
return new LRESULT(1);
}
return new LRESULT(0);
}
};
然后在初始化事物的JFrame代码中的某处使用SetWindowLong函数为窗口过程添加新地址:
// Get Handle to current window
HWND hWnd = new HWND();
hWnd.setPointer(Native.getWindowPointer(this));
MyUser32.MYINSTANCE.SetWindowLong(hWnd, MyUser32.GWLP_WNDPROC, listener);
这段代码效果很好,但我对一件事情有些怀疑。我不确定回调函数的返回值是否正确。我在MSDN中读到,在处理WM_DEVICECHANGE消息后,回调函数应该返回true并且我不确定我当前返回的值是系统预期的值,所以欢迎任何建议。
如果有人对我为HID通信编写的整个代码感兴趣,那么我会非常乐意提供帮助:)
干杯, 的Gabor。
答案 1 :(得分:2)
如果您没有现有的窗口句柄,则必须先创建自己的窗口。当您创建新窗口时,您还必须管理其消息泵。以下是有关如何执行此操作的示例。 JNA's own example code也非常有用。
Thread thread;
HWND hWnd;
static final int WM_NCCREATE = 0x0081;
void start() {
thread = new Thread(this::myThread);
thread.start();
}
void stop() {
User32.INSTANCE.PostMessage(hWnd, User32.WM_QUIT, null, null);
}
WindowProc callback = new WindowProc() {
@Override
public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_NCCREATE:
return new LRESULT(1);
case User32.WM_DEVICECHANGE:
return new LRESULT(1);
default:
return new LRESULT(0);
}
}
};
void myThread() {
WString className = new WString("myclass");
WNDCLASSEX wx = new WNDCLASSEX();
wx.clear();
wx.lpszClassName = className;
wx.lpfnWndProc = callback;
if (User32.INSTANCE.RegisterClassEx(wx).intValue() != 0) {
hWnd = User32.INSTANCE.CreateWindowEx(0, className, null, 0, 0, 0, 0, 0, null, null, null, null);
WinUser.MSG msg = new WinUser.MSG();
msg.clear();
while (User32.INSTANCE.GetMessage(msg, hWnd, 0, 0) > 0) {
User32.INSTANCE.TranslateMessage(msg);
User32.INSTANCE.DispatchMessage(msg);
}
}
}
答案 2 :(得分:1)
您可以创建C#程序的COM DLL或OCX,并在java代码中使用它。如果您创建应用程序。
使用JACOB OR JCOM
它将成为Java和COM对象之间的桥梁。其他选项是您可以使用JNI与DLL和OCX进行通信。
答案 3 :(得分:1)
不幸的是,我之前发布的解决方案存在一些问题:(
由于它覆盖了窗口的WndProc,我添加到我的Frame的控件无法正常工作(这并不奇怪,因为没有处理油漆,重绘等消息)。然后我意识到我应该调用默认窗口proc(因为它在Win32 C ++程序中使用)而不是返回LRESULT(1)
,但这仍然没有解决问题,框架被绘制但是按钮不是工作,虽然我能够更新标签...所以我不得不放弃这个解决方案。
在互联网上搜索了一些内容后,我发现了一篇很棒的文章here (编辑:链接已死,original article can be found here),其中创建了一个静态隐藏窗口处理Windows消息。我设法为我的应用程序编写代码,它工作得很好。 (我不得不进一步扩展JNA中的类,因为没有包含几个函数。如果有人感兴趣,我可以发布我的代码。)
希望这有帮助。