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

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

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

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

Габор.


person Gabor    schedule 13.01.2011    source источник
comment
Не могли бы вы опубликовать код, который вы использовали. Спасибо.   -  person    schedule 20.09.2011
comment
У меня есть один вопрос, Вам не приходилось использовать что-то вроде RegisterDeviceNotification или вы просто ищете порты устройств, для которых windows автоматически транслирует WM_DEVICECHANGE?   -  person    schedule 14.10.2011


Ответы (4)


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

Сначала расширьте интерфейс 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, просто спросите, я был бы более чем счастлив помочь :)

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

person Gabor    schedule 14.01.2011
comment
Больше не нужно создавать собственный интерфейс обратного вызова, как MyListener. JNA предоставляет интерфейс WinUser.WindowProc. - person Sundae; 24.02.2015

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

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);
        }
    }
}
person Sundae    schedule 24.02.2015

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

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

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

person Ashfak Balooch    schedule 13.01.2011
comment
Спасибо за ответ, но нет ли другого варианта, потому что я действительно не хочу использовать код C #, я только что упомянул об этом, потому что это не то, откуда я взял идею о WM_DEVICECHANGE. Например, через класс Kernel32 JNA у меня был доступ к методам ReadFile и WriteFile для чтения и записи на мое USB-устройство. Спасибо. - person Gabor; 13.01.2011

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

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

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

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

person Gabor    schedule 25.01.2011
comment
Не публикуйте дополнительную информацию в качестве ответа, вместо этого отредактируйте свой вопрос. - person Joachim Sauer; 25.01.2011
comment
Меня также интересует ваш код. Не могли бы вы предоставить его? Спасибо! - person Martijn; 30.08.2013
comment
Меня также интересует ваш код. Не могли бы вы предоставить его? Спасибо! - person Algok; 11.08.2014