2011-01-13 14 views
7

Ich versuche, eine einfache Anwendung in Java zu schreiben, die mit einem USB-Gerät kommunizieren wird. Das USB-Gerät wird von mir mit einem Microchip Microcontroller hergestellt. Die Kommunikation ist ziemlich einfach, da das USB-Gerät aus der HID-Klasse besteht, werden Arrays von 64 Bytes zwischen dem Computer und dem Gerät ausgetauscht. Mein Programm findet das Gerät anhand der Produkt-ID und der Hersteller-ID, kann 64 Bytes schreiben und lesen, aber jetzt möchte ich feststellen, ob das Gerät mit dem Computer verbunden oder getrennt ist.JAVA JNA WindowProc Implementierung

Wie ich in einem C# -Programm gesehen habe, das von Microchip als Beispielanwendung bereitgestellt wird, wird die WndProc-Methode überschrieben und die WM_DEVICECHANGE-Nachricht verarbeitet. Meine Frage ist, wie kann dies in Java mit JNA getan werden, wie kann ich die WindowProc-Methode überschreiben und Nachrichten behandeln, wenn dies überhaupt möglich ist :), aber ich hoffe es ist: D

Vielen Dank im Voraus für die Antworten .

Gabor.

+0

Können Sie bitte den Code, den Sie verwendet haben, posten. Vielen Dank. –

+0

Ich habe eine Frage, mussten Sie nicht etwas wie RegisterDeviceNotification verwenden oder Sie suchen nur nach Ports-Geräten, für die Windows WM_DEVICECHANGE automatisch ausstrahlt? –

Antwort

1

Sie können COM DLL oder OCX Ihres C# -Programms erstellen und im Java-Code verwenden. Wenn Sie eine Anwendung erstellen.

Verwenden JACOB ODER JCOM

Es wird eine Brücke zwischen Java und COM-Objekt sein. Andere Option ist, dass Sie JNI verwenden können, um mit DLL und OCX zu kommunizieren.

+0

Danke für die Antwort, aber gibt es keine andere Möglichkeit, weil ich nicht wirklich den C# -Code verwenden möchte, ich habe es gerade erwähnt, weil ich nicht von der Idee zum WM_DEVICECHANGE gekommen bin. Zum Beispiel hatte ich über die Kernel32-Klasse des JNA Zugriff auf die ReadFile- und WriteFile-Methoden zum Lesen und Schreiben auf mein USB-Gerät. Vielen Dank. – Gabor

8

ich es endlich geschafft, das Problem zu lösen :) Und ich fand die folgende Lösung:

zuerst die User32 Schnittstelle auf folgende Weise erweitern

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

die winuser Schnittstelle mit dem Windows Message Code erweitern dann das brauchst du, in meinem Fall ist das der WM_DEVICECHANGE, weil ich überprüfen will, ob das USB-Gerät an den Computer angeschlossen oder von ihm gelöst wurde.

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

Dann erstellen Sie eine Schnittstelle mit der Callback-Funktion, die tatsächlich meine WndProc-Funktion sein wird.

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

Und dann irgendwo im Code des JFrame, wo Sie initialisieren Dinge die neue Adresse für die Fensterprozedur mit der SetWindowLong Funktion hinzufügen:

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

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

Dieser Code funktioniert gut, aber ich habe einige Zweifel in Bezug auf eine Sache. Ich bin mir nicht sicher, ob der Rückgabewert der Callback-Funktion korrekt ist. Ich habe in der MSDN gelesen, dass nach der Behandlung einer WM_DEVICECHANGE Nachricht die Callback-Funktion True zurückgeben sollte und ich bin mir nicht sicher, dass der Wert, den ich momentan zurückgebe, der vom System erwartete Wert ist.

Wenn jemand interessiert sich für den gesamten Code, den ich für die HID-Kommunikation geschrieben habe gerade fragen, wäre ich mehr als glücklich :)

Beifall zu helfen, Gabor.

+2

danke für das Teilen Ihrer Ergebnisse – mtraut

+0

Keine Notwendigkeit, eine benutzerdefinierte Callback-Schnittstelle zu erstellen, da MyListener nicht mehr ist. JNA stellt die WinUser.WindowProc-Schnittstelle bereit. – Sundae

1

Die Lösung, die ich zuvor geschrieben hat einige Probleme, leider :(

Da es die WndProc des Fensters überschreibt, die Kontrollen ich meinen Rahmen hinzugefügt wurden nicht funktioniert (nicht überraschend, da keine Farbe, neu streichen, usw. wurden Nachrichten bearbeitet).Dann erkannte ich, dass anstatt LRESULT(1) ich das Standardfenster Proc (wie es in Win32 C++ - Programme verwendet wird) aufrufen, aber das Problem immer noch nicht gelöst, der Rahmen wurde gemalt, aber die Tasten funktionierten nicht, obwohl ich konnte Etiketten aktualisieren ... Also musste ich diese Lösung ebenfalls aufgeben.

Nach weiteren Suche im Internet habe ich einen großen Artikel gefunden here(edit: Link ist tot, original article can be found here), wo ein statisches versteckte Fenster erstellt wird, um Windows-Nachrichten zu verarbeiten. Ich habe es für meine Anwendung programmiert und es funktioniert super. (Ich musste die Klassen von JNA weiter ausdehnen, weil einige Funktionen nicht enthalten waren. Ich kann meinen Code veröffentlichen, wenn jemand interessiert ist.)

Hoffe, dass dies hilft.

+6

Veröffentlichen Sie keine zusätzlichen Informationen als Antwort, sondern bearbeiten Sie stattdessen Ihre Frage. –

+0

Ich bin interessant durch Ihren Code. Könnten Sie es bereitstellen? Vielen Dank! – Maxbester

+0

Ich bin auch an Ihrem Code interessiert. Könnten Sie bitte es bereitstellen? Tnx! – Martijn

2

Wenn Sie kein vorhandenes Fensterhandle haben, müssen Sie zuerst ein eigenes Fenster erstellen. Und wenn Sie ein neues Fenster erstellen, müssen Sie auch die Nachrichtenpumpe verwalten. Hier ist ein Beispiel, wie Sie das tun können. JNA's own example code könnte auch sehr nützlich sein.

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