I'm trying to write a simple application in Java that will communicate with an USB device. The USB device is made by me using a Microchip Microcontroller. The communication is rather simple, since the USB device is from the HID Class, arrays of 64 bytes are exchanged between the computer and the device.
My program finds the device based on the product ID and the vendor ID, can write and read 64 bytes, but now I would like to detect when the device is connected or disconnected from the computer.
As I've seen in a C# program provided by Microchip as an example application, the WndProc method is overriden and the WM_DEVICECHANGE message is handled. My question is how can this be done in Java using JNA, how can I override the WindowProc Method and handle messages, if this is possible at all :), but I hope it is :D
Thanks in advance for the answers.
Gabor.
I finally managed to solve the problem :) And I found the following solution:
First extend the User32 interface in the following way
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);
}
Then extend the WinUser interface with the Windows Message code that you need, in my case this is the WM_DEVICECHANGE, because I want to check I the USB Device was attached or detached from the computer.
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;
}
Then create an interface with the callback function, which will actually be my WndProc function.
//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);
}
};
And then somewhere in the code of the JFrame where you initialize things add the new address for the window procedure with the SetWindowLong function:
// Get Handle to current window
HWND hWnd = new HWND();
hWnd.setPointer(Native.getWindowPointer(this));
MyUser32.MYINSTANCE.SetWindowLong(hWnd, MyUser32.GWLP_WNDPROC, listener);
This code works nicely, but I have some doubts regarding one thing. I'm not sure if the return value of the callback function is correct. I've read in the MSDN that after handling a WM_DEVICECHANGE message the callback function should return true and I'm not sure that the value i'm currently returning is the one expected by the system, so any suggestions are welcome.
If anyone is interested in the whole code I've written for the HID communication just ask, I would be more than happy to help :)
Cheers,
Gabor.
If you don't have an existing window handle you have to create your own window first. And when you create a new window you also have to manage its message pump. Here's an example on how you can do this. JNA's own example code could also be very useful.
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);
}
}
}
You can create COM DLL or OCX of your C# program and use it in the java code. If you create application.
Use JACOB OR JCOM
It will be a bridge between Java and COM Object. Other option is you can use JNI to communicate with DLL and OCX.
The solution I posted previously has some problems, unfortunately :(
Since it overrides the WndProc of the window, the controls I added to my Frame weren't working (not surprisingly, because no paint, repaint, etc. messages were handled). Then I realised that instead of returning LRESULT(1)
I should call the default window proc (as it is used in Win32 C++ programs), but this still didn't solve the problem, the frame was painted but the buttons weren't working, although I was able to update labels... So I had to abandon this solution too.
After searching some more on the internet I've found a great article here (edit: link is dead, original article can be found here), where a static hidden window is created to handle windows messages. I managed to code it for my application and it works great. (I had to further extend the classes from JNA because several functions were not included. I can post my code if someone is interested.)
Hope this helps.