2011-01-13 12 views
7

Tôi đang cố viết một ứng dụng đơn giản trong Java sẽ giao tiếp với thiết bị USB. Các thiết bị USB được thực hiện bởi tôi bằng cách sử dụng một vi điều khiển vi mạch. Giao tiếp khá đơn giản, vì thiết bị USB là từ lớp HID, mảng 64 byte được trao đổi giữa máy tính và thiết bị. Chương trình của tôi tìm thấy thiết bị dựa trên ID sản phẩm và ID nhà cung cấp, có thể ghi và đọc 64 byte, nhưng bây giờ tôi muốn phát hiện khi thiết bị được kết nối hoặc ngắt kết nối khỏi máy tính.Thực hiện JAVA JNA WindowProc

Như tôi đã thấy trong chương trình C# do Microchip cung cấp như một ứng dụng ví dụ, phương pháp WndProc được ghi đè và thông báo WM_DEVICECHANGE được xử lý. Câu hỏi của tôi là làm thế nào điều này có thể được thực hiện trong Java bằng cách sử dụng JNA, làm thế nào tôi có thể ghi đè lên phương pháp WindowProc và xử lý tin nhắn, nếu điều này là có thể ở tất cả :), nhưng tôi hy vọng nó là: D

Cảm ơn trước cho câu trả lời .

Gabor.

+0

Bạn có thể vui lòng đăng mã bạn đã sử dụng không. Cảm ơn. –

+0

Tôi có một câu hỏi, Bạn không phải sử dụng một cái gì đó như RegisterDeviceNotification hoặc bạn chỉ tìm kiếm các thiết bị cổng mà các cửa sổ phát sóng WM_DEVICECHANGE tự động? –

Trả lời

1

Bạn có thể tạo COM DLL hoặc OCX của chương trình C# và sử dụng nó trong mã java. Nếu bạn tạo ứng dụng.

Sử dụng JACOB HOẶC JCOM

Nó sẽ là một cầu nối giữa Java và COM Object. Tùy chọn khác là bạn có thể sử dụng JNI để giao tiếp với DLL và OCX.

+0

Cảm ơn bạn đã trả lời, nhưng không có lựa chọn nào khác, bởi vì tôi không thực sự muốn sử dụng mã C#, tôi vừa đề cập đến nó, vì không phải từ nơi tôi có ý tưởng về WM_DEVICECHANGE. Ví dụ thông qua lớp Kernel32 của JNA, tôi đã truy cập vào các phương thức ReadFile và WriteFile để đọc và ghi vào thiết bị USB của mình. Cảm ơn. – Gabor

8

Cuối cùng tôi quản lý để giải quyết vấn đề :) Và tôi tìm thấy giải pháp sau đây:

Đầu tiên mở rộng giao diện User32 theo cách sau

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

Sau đó, mở rộng giao diện WinUser với mã Windows Message mà bạn cần, trong trường hợp của tôi đây là WM_DEVICECHANGE, bởi vì tôi muốn kiểm tra xem thiết bị USB đã được gắn hay tháo ra khỏi máy tính chưa.

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

Sau đó, tạo giao diện với chức năng gọi lại, đây thực sự là hàm WndProc của tôi.

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

Và rồi đâu đó trong mã của JFrame nơi bạn khởi tạo điều thêm địa chỉ mới cho các thủ tục cửa sổ với chức năng SetWindowLong:

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

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

Mã này hoạt động độc đáo, nhưng tôi có một số nghi ngờ liên quan đến một điều. Tôi không chắc liệu giá trị trả về của hàm gọi lại có đúng không. Tôi đã đọc trong MSDN rằng sau khi xử lý một tin nhắn WM_DEVICECHANGE chức năng gọi lại nên trả về true và tôi không chắc chắn rằng giá trị tôi hiện đang quay trở lại là một trong những dự kiến ​​của hệ thống, vì vậy bất kỳ đề nghị được chào đón.

Nếu bất cứ ai quan tâm đến toàn bộ mã tôi đã viết cho truyền thông HID chỉ cần hỏi, tôi sẽ hạnh phúc hơn để giúp :)

Chúc mừng, Gabor.

+2

cảm ơn bạn đã chia sẻ kết quả của mình – mtraut

+0

Không cần phải tạo giao diện gọi lại tùy chỉnh như MyListener nữa. JNA cung cấp giao diện WinUser.WindowProc. – Sundae

1

Các giải pháp tôi đã đăng trước đây có một số vấn đề, không may :(

Vì nó đè WndProc của cửa sổ, các điều khiển tôi thêm vào Khung của tôi đã không làm việc (không đáng ngạc nhiên, bởi vì không có sơn, sơn lại, v.v .. đã được xử lý).Sau đó, tôi nhận ra rằng thay vì trả lại LRESULT(1) tôi nên gọi proc cửa sổ mặc định (vì nó được sử dụng trong các chương trình Win32 C++), nhưng điều này vẫn không giải quyết được vấn đề, khung được vẽ nhưng các nút không hoạt động, mặc dù tôi đã có thể cập nhật nhãn ... Vì vậy, tôi cũng phải từ bỏ giải pháp này.

Sau khi tìm kiếm một số chi tiết trên internet tôi đã tìm thấy một bài viết tuyệt vời here(chỉnh sửa: liên kết là chết, original article can be found here), nơi một cửa sổ ẩn tĩnh được tạo ra để xử lý các cửa sổ tin nhắn. Tôi quản lý để mã nó cho ứng dụng của tôi và nó hoạt động tuyệt vời. (Tôi đã phải mở rộng hơn nữa các lớp học từ JNA vì một số chức năng không được bao gồm. Tôi có thể đăng mã của tôi nếu ai đó quan tâm.)

Hy vọng điều này sẽ giúp.

+6

Không đăng thông tin bổ sung làm câu trả lời, thay vào đó hãy chỉnh sửa câu hỏi của bạn. –

+0

Tôi rất thú vị bởi mã của bạn. Bạn có thể cung cấp nó? Cảm ơn! – Maxbester

+0

Tôi cũng quan tâm đến mã của bạn. Bạn có thể pls cung cấp nó? Tnx! – Martijn

2

Nếu bạn không có tay cầm cửa sổ hiện tại, trước tiên bạn phải tạo cửa sổ của riêng mình. Và khi bạn tạo một cửa sổ mới, bạn cũng phải quản lý bơm thông báo của nó. Đây là một ví dụ về cách bạn có thể làm điều này. JNA's own example code cũng có thể rất hữu ích.

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