2011-01-13 11 views
7

Sto provando a scrivere una semplice applicazione in Java che comunichi con un dispositivo USB. Il dispositivo USB è realizzato da me utilizzando un Microchip Microcontroller. La comunicazione è piuttosto semplice, poiché il dispositivo USB appartiene alla classe HID, gli array di 64 byte vengono scambiati tra il computer e il dispositivo. Il mio programma trova il dispositivo in base all'ID del prodotto e all'ID del fornitore, può scrivere e leggere 64 byte, ma ora vorrei rilevare quando il dispositivo è connesso o disconnesso dal computer.Implementazione JAVA JNA WindowProc

Come ho visto in un programma C# fornito da Microchip come applicazione di esempio, il metodo WndProc viene sovrascritto e viene gestito il messaggio WM_DEVICECHANGE. La mia domanda è come può essere fatto in Java usando JNA, come posso sovrascrivere il metodo WindowProc e gestire i messaggi, se è possibile del tutto :), ma spero che sia: D

Grazie in anticipo per le risposte .

Gabor.

+0

Puoi inserire il codice che hai utilizzato. Grazie. –

+0

Ho una domanda, non dovevi usare qualcosa come RegisterDeviceNotification o stai solo cercando dispositivi portuali per i quali Windows trasmette automaticamente WM_DEVICECHANGE? –

risposta

1

È possibile creare COM DLL o OCX del programma C# e utilizzarlo nel codice java. Se si crea un'applicazione.

Usa JACOB O JCOM

Sarà un ponte tra Java e COM oggetto. Un'altra opzione è che è possibile utilizzare JNI per comunicare con DLL e OCX.

+0

Grazie per la risposta, ma non c'è un'altra opzione, perché in realtà non voglio usare il codice C#, l'ho appena menzionato, perché non è da dove ho avuto l'idea del WM_DEVICECHANGE. Ad esempio attraverso la classe Kernel32 di JNA ho avuto accesso ai metodi ReadFile e WriteFile per leggere e scrivere sul mio dispositivo USB. Grazie. – Gabor

8

sono finalmente riuscito a risolvere il problema :) E ho trovato la seguente soluzione:

Prima estendere l'interfaccia User32 nel seguente modo

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

quindi estendere l'interfaccia winuser con il codice di Windows Messaggio di cui hai bisogno, nel mio caso questo è il WM_DEVICECHANGE, perché voglio verificare se il dispositivo USB è stato collegato o scollegato dal 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; 
} 

Quindi creare un'interfaccia con la funzione di richiamata, che sarà in realtà la mia funzione 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); 
    } 
}; 

E poi da qualche parte nel codice del JFrame dove si inizializza cose aggiungere il nuovo indirizzo per la procedura di finestra con la funzione SetWindowLong:

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

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

Questo codice funziona bene, ma ho qualche dubbio riguardo una cosa Non sono sicuro che il valore restituito dalla funzione di callback sia corretto. Ho letto in MSDN che dopo aver gestito un messaggio WM_DEVICECHANGE la funzione di callback dovrebbe restituire true e non sono sicuro che il valore che sto attualmente restituendo sia quello atteso dal sistema, quindi qualsiasi suggerimento è benvenuto.

Se qualcuno è interessato a tutto il codice che ho scritto per la comunicazione HID basta chiedere, sarei più che felice di aiutarvi :)

Acclamazioni, Gabor.

+2

grazie per aver condiviso i risultati – mtraut

+0

Non è necessario creare un'interfaccia di callback personalizzata come MyListener è più. JNA fornisce l'interfaccia WinUser.WindowProc. – Sundae

1

La soluzione che ho postato in precedenza ha qualche problema, purtroppo :(

Dal momento che sostituisce il WndProc della finestra, i controlli che ho aggiunto al mio telaio sono stati non funziona (non a caso, perché nessuna vernice, ridisegnare, messaggi ecc. sono stati gestiti).Poi ho capito che invece di restituire LRESULT(1) dovrei chiamare la finestra predefinita proc (come è usata nei programmi C++ Win32), ma questo ancora non risolveva il problema, la cornice era dipinta ma i pulsanti non funzionavano, anche se io è stato in grado di aggiornare le etichette ... Quindi ho dovuto abbandonare anche questa soluzione.

Dopo aver cercato un po 'su internet ho trovato un grande articolo here(edit: collegamento è morto, original article can be found here), dove si crea una finestra nascosta statica per gestire i messaggi di Windows. Sono riuscito a codificarlo per la mia applicazione e funziona benissimo. (Ho dovuto estendere ulteriormente le classi da JNA perché diverse funzioni non erano incluse.Posso pubblicare il mio codice se qualcuno è interessato.)

Spero che questo aiuti.

+6

Non pubblicare ulteriori informazioni come risposta, modifica invece la tua domanda. –

+0

Sono interessante per il tuo codice. Potresti fornirlo? Grazie! – Maxbester

+0

Anche io sono interessato al tuo codice. Potresti fornirlo? Tnx! – Martijn

2

Se non si dispone di un handle di finestra esistente, è necessario creare prima la propria finestra. E quando crei una nuova finestra devi anche gestirne il messaggio. Ecco un esempio su come puoi farlo. JNA's own example code potrebbe anche essere molto utile.

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