Реализация JAVA JNA WindowProc - PullRequest
       27

Реализация JAVA JNA WindowProc

7 голосов
/ 13 января 2011

Я пытаюсь написать простое приложение на Java, которое будет взаимодействовать с USB-устройством. Устройство USB сделано мной, используя Микроконтроллер Микрочипа. Связь довольно проста, поскольку устройство USB относится к классу HID, между компьютером и устройством обмениваются массивами по 64 байта. Моя программа находит устройство на основе идентификатора продукта и идентификатора поставщика, может записывать и считывать 64 байта, но теперь я хотел бы определить, когда устройство подключено или отключено от компьютера.

Как я видел в программе на C #, предоставляемой Microchip в качестве примера приложения, метод WndProc переопределяется и обрабатывается сообщение WM_DEVICECHANGE. У меня вопрос, как это можно сделать в Java с использованием JNA, как я могу переопределить метод WindowProc и обрабатывать сообщения, если это вообще возможно :), но я надеюсь, что это так: D

Заранее спасибо за ответы.

Gabor.

Ответы [ 4 ]

8 голосов
/ 14 января 2011

Мне наконец-то удалось решить проблему :) И я нашел следующее решение:

Сначала расширьте интерфейс User32 следующим образом

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

Затем расширьте интерфейс WinUser с помощьюКод сообщения Windows, который вам нужен, в моем случае это WM_DEVICECHANGE, потому что я хочу проверить, было ли USB-устройство подключено или отсоединено от компьютера.

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

Затем создайте интерфейс с функцией обратного вызова,которая фактически будет моей функцией 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);
    }
};

А затем где-нибудь в коде JFrame, где вы инициализируете вещи, добавьте новый адрес для оконной процедуры с помощью функции SetWindowLong:

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

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

Этот код работает хорошо, но у меня есть некоторые сомнения относительно одной вещи.Я не уверен, что возвращаемое значение функции обратного вызова является правильным.Я прочитал в MSDN, что после обработки сообщения WM_DEVICECHANGE функция обратного вызова должна возвращать true, и я не уверен, что значение, которое я возвращаю в данный момент, является ожидаемым системой, поэтому любые предложения приветствуются.

Если кому-то будет интересен весь код, который я написал для HID-связи, просто спросите, я был бы более чем рад помочь:)

Приветствия, Габор.

2 голосов
/ 24 февраля 2015

Если у вас нет дескриптора окна, вы должны сначала создать собственное окно.И когда вы создаете новое окно, вы также должны управлять его насосом сообщений.Вот пример того, как вы можете это сделать. Пример кода JNA также может быть очень полезным.

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);
        }
    }
}
1 голос
/ 25 января 2011

Решение, которое я выложил ранее, к сожалению, имеет некоторые проблемы: (

Так как он переопределяет WndProc окна, элементы управления, которые я добавил в свой фрейм, не работали (что неудивительно, потому что сообщения рисования, перекраски и т. Д. Не обрабатывались). Затем я понял, что вместо возврата LRESULT(1) я должен вызывать процедуру окна по умолчанию (как это используется в программах Win32 C ++), но это все равно не решило проблему, рамка была нарисована, но кнопки не работали, хотя я смог обновить ярлыки ... Поэтому мне пришлось отказаться и от этого решения.

После поиска в Интернете я нашел отличную статью здесь (редактировать: ссылка не работает, оригинальную статью можно найти здесь ) где статическое скрытое окно создается для обработки сообщений Windows. Мне удалось закодировать его для моего приложения, и оно прекрасно работает. (Мне пришлось дополнительно расширить классы из JNA, потому что некоторые функции не были включены. Я могу опубликовать свой код, если кому-то интересно.)

Надеюсь, это поможет.

1 голос
/ 13 января 2011

Вы можете создать COM DLL или OCX вашей программы на C # и использовать ее в коде Java. Если вы создаете приложение.

Используйте JACOB ИЛИ JCOM

Это будет мост между Java и COM-объектом. Другой вариант - вы можете использовать JNI для связи с DLL и OCX.

...