2011-01-13 10 views
7

Estoy tratando de escribir una aplicación simple en Java que se comunicará con un dispositivo USB. El dispositivo USB está hecho por mí usando un microcontrolador Microchip. La comunicación es bastante simple, dado que el dispositivo USB es de la clase HID, se intercambian matrices de 64 bytes entre la computadora y el dispositivo. Mi programa encuentra el dispositivo basado en la identificación del producto y la identificación del vendedor, puede escribir y leer 64 bytes, pero ahora me gustaría detectar cuándo el dispositivo está conectado o desconectado de la computadora.Implementación JAVA JNA WindowProc

Como he visto en un programa de C# proporcionado por Microchip como una aplicación de ejemplo, se invalida el método WndProc y se maneja el mensaje WM_DEVICECHANGE. Mi pregunta es cómo se puede hacer esto en Java usando JNA, cómo puedo anular el método de WindowProc y manejar mensajes, si esto es posible :), pero espero que lo sea: D

Gracias de antemano por las respuestas .

Gabor.

+0

Puede publicar el código que ha utilizado. Gracias. –

+0

Tengo una pregunta: ¿No tiene que usar algo como RegisterDeviceNotification o simplemente está buscando dispositivos de puertos para los que Windows transmite WM_DEVICECHANGE automáticamente? –

Respuesta

1

Puede crear COM DLL u OCX de su programa C# y usarlo en el código java. Si creas una aplicación

uso JACOB O JCOM

será un puente entre Java y objetos COM. Otra opción es usar JNI para comunicarse con DLL y OCX.

+0

Gracias por la respuesta, pero ¿no hay otra opción, porque realmente no quiero usar el código C#, simplemente lo mencioné, porque no tengo la idea del WM_DEVICECHANGE. Por ejemplo, a través de la clase Kernel32 del JNA, tuve acceso a los métodos ReadFile y WriteFile para leer y escribir en mi dispositivo USB. Gracias. – Gabor

8

fin he conseguido resolver el problema :) Y me encontré con la siguiente solución:

Primera ampliar la interfaz User32 de la siguiente manera

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

luego extender la interfaz winuser con el código de mensajes de Windows que necesita, en mi caso este es el WM_DEVICECHANGE, porque quiero verificar que el dispositivo USB esté conectado o desconectado de la computadora.

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

A continuación, cree una interfaz con la función de devolución de llamada, que en realidad será mi función 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); 
    } 
}; 

Y a continuación, en alguna parte del código del JFrame donde inicializar cosas agregar la nueva dirección para el procedimiento de ventana con la función SetWindowLong:

// Get Handle to current window 
    HWND hWnd = new HWND(); 
    hWnd.setPointer(Native.getWindowPointer(this)); 

    MyUser32.MYINSTANCE.SetWindowLong(hWnd, MyUser32.GWLP_WNDPROC, listener); 

Este código funciona muy bien, pero tengo algunas dudas con respecto a una cosa. No estoy seguro de si el valor de retorno de la función de devolución de llamada es correcto. Leí en MSDN que, después de manejar un mensaje WM_DEVICECHANGE, la función de devolución de llamada debe ser verdadera y no estoy seguro de que el valor que estoy devolviendo actualmente sea el esperado por el sistema, por lo que cualquier sugerencia es bienvenida.

Si alguien está interesado en todo el código que he escrito para la comunicación HID sólo pregunte, yo sería más que feliz de ayudar :)

Saludos, Gabor.

+2

gracias por compartir sus resultados – mtraut

+0

No es necesario crear una interfaz de devolución de llamada personalizada ya que MyListener ya no existe. JNA proporciona la interfaz WinUser.WindowProc. – Sundae

1

La solución que he publicado anteriormente tiene algunos problemas, por desgracia :(

Ya que anula el WndProc de la ventana, los controles que he añadido a mi marco fueron no trabajar (no es sorprendente, ya que no hay pintura, pintar, etc. mensajes fueron manejados).Entonces me di cuenta de que en lugar de devolver LRESULT(1) debía llamar al proceso de ventana predeterminado (como se usa en los programas Win32 C++), pero esto aún no resolvía el problema, el marco estaba pintado pero los botones no funcionaban, aunque Pude actualizar las etiquetas ... Así que tuve que abandonar esta solución también.

Después de buscar un poco más en el Internet he encontrado un gran artículo here(edit: link está muerto, original article can be found here), donde se crea una ventana oculta estática para manejar mensajes de ventanas. Logré codificarlo para mi aplicación y funciona muy bien. (Tuve que ampliar aún más las clases de JNA porque no se incluyeron varias funciones. Puedo publicar mi código si alguien está interesado.)

Espero que esto ayude.

+6

No publique información adicional como respuesta, edite su pregunta en su lugar. –

+0

Soy interesante por tu código. ¿Podrías proporcionarlo? ¡Gracias! – Maxbester

+0

También estoy interesado en su código. ¿Podrías por favor proporcionarlo? Tnx! – Martijn

2

Si no tiene un identificador de ventana existente, primero debe crear su propia ventana. Y cuando creas una nueva ventana, también tienes que administrar su bomba de mensajes. Aquí hay un ejemplo de cómo puedes hacer esto. JNA's own example code también podría ser muy útil.

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