Отправить определяемое пользователем Windows -сообщение через JNA - PullRequest
0 голосов
/ 29 мая 2020

Мне нужна простая, но сложная вещь: отправить определенное c пользовательское Windows -сообщение со стороны JNA, чтобы это сообщение было перехвачено сообщением-l oop (GetMessage() / DispatchMessage()) на стороне C ++, и сообщение l oop будет прервано. Фактически это должно выполняться нажатием кнопки в Swing GUI. Мои вопросы и соображения:

1) Предположим, например, что я определил на стороне C ++ свое собственное сообщение как #define WM_CUSTOM_MSG (WM_USER+42) и, конечно, добавил соответствующий оператор if для прерывания внутри моего сообщения-l oop на C ++ сторона. Но моя цель - отправить это сообщение из java.

2) Для этого я написал следующее:

public class User32Ext {
    interface User32Interface extends User32 {
        User32Interface INSTANCE = Native.load("user32",

                User32Interface.class, W32APIOptions.DEFAULT_OPTIONS);

        @Override
        HWND FindWindowEx(HWND lpParent, HWND lpChild, String lpClassName, String lpWindowName);

        HWND GetTopWindow(HWND hwnd);

        HWND GetParent(HWND hwnd);

        @Override
        HWND GetDesktopWindow();

        int SendMessage(HWND hWnd, int Msg, IntByReference wParam, IntByReference lParam);

        void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

        void SwitchToThisWindow(HWND hWnd, boolean fAltTab);

    }

    private final User32Interface u32 = User32Interface.INSTANCE;

    public User32Ext() {
        super();
        // TODO Auto-generated constructor stub
    }

    public void sendInterruptMessage(final String windowName) {
        try {
            final User32.HWND hwnd = u32.FindWindowEx(null, null, null, windowName);
            final int msg = 0x400 + 42;
            final User32.WPARAM wparam = new User32.WPARAM();
            final User32.LPARAM lparam = new User32.LPARAM();
            final LRESULT res = u32.SendMessage(hwnd, msg, wparam, lparam);
        } catch (final RuntimeException e) {
            e.printStackTrace();
        }
    }
 }

, а затем просто создайте объект этого фиктивного класса и вызовите sendInterruptMessage с моим заголовком JFrame в качестве параметра в событии кнопки.

К сожалению, с обеих сторон абсолютно никакого эффекта не обнаружено. Я почти уверен, что сделал фатальную ошибку, потому что у меня недостаточно опыта в программировании Windows и JNA. Итак, не могли бы вы сказать мне, по крайней мере, я прав концептуально, реализуя желаемый результат таким образом? Или на стороне Java есть ошибки программирования. Спасибо!

PS, если бы это можно было реализовать без отправки специального сообщения, но с каким-то стандартным Windows сообщением, это прекрасно, я просто хочу быть уверенным, единственное, что делает это сообщение, - это прерывает мой Сообщение C ++ l oop.

1 Ответ

1 голос
/ 29 мая 2020

При отображении функций WINAPI с JNA вы должны позаботиться о точном совпадении определений Windows API с соответствующими типами Java / JNA. Некоторые из ваших сопоставлений неверны. Последние два аргумента SendMessage - это WPARAM и LPARAM, которые вы, похоже, используете в своем сопоставлении sendInterruptMessage(). Они вызывают функцию уже отображенную SendMessage в проекте JNA . Неважно, что вы вставляете в свое собственное отображение SendMessage, поскольку вы даже не вызываете его, поскольку вы используете разные типы. Удалите это. Также удалите два метода, которые вы добавили @Override из суперкласса. У вас нет причин перезаписывать то, что они уже делают.

На самом деле, при дальнейшей проверке кажется, что вы скопировали код, написанный кем-то другим в 2014 году из этого ответа . Однако нужные вам сопоставления были добавлены в проект JNA в 2017 году. Копирование кода без знания того, что он делает, не является рецептом успеха. Весь ваш интерфейс не нужен. Просто вызовите интерфейс User32 JNA.

При вызове FindWindowEx вы передаете null для первых трех аргументов и помещаете String только в четвертый аргумент. Кажется, это не соответствует API, который, похоже, не допускает null в качестве третьего аргумента . Вы проверили, является ли возвращаемый дескриптор нулевым? Вероятно, это так, и в соответствии с API вы можете использовать GetLastError для просмотра этого кода ошибки, который, вероятно, связан с неправильными аргументами.

В документации для этого третьего аргумента указывается

Если lpszClass является строкой, она определяет имя класса окна. Имя класса может быть любым именем, зарегистрированным с помощью RegisterClass или RegisterClassEx, или любым из предопределенных имен классов управления, или это может быть MAKEINTATOM (0x8000). В последнем случае 0x8000 - это атом для класса меню. Для получения дополнительной информации см. Раздел «Примечания» этого топа c.

Не похоже, что вы делаете это так, как требуется.

Если этот первый вызов был успешным ( что меня удивило бы), вам было бы поучительно оценить возврат LRESULT из существующего вызова SendMessage и посмотреть, указывает ли он на успех или генерирует код ошибки. Фактически, вы, вероятно, передаете ему нулевой дескриптор, и в этом случае неудивительно, что ничего не происходит.

Начиная с проверки возвращаемых значений метода, которые указывают на успех / неудачу, и оценка кодов ошибок должна помочь вам отладить .

Наконец, как указано iinspectable в комментариях, код, который вы передаете, не является настраиваемым сообщением. Согласно документации ,

Значения идентификаторов сообщений используются следующим образом:

  • Система резервирует значения идентификаторов сообщений в диапазон от 0x0000 до 0x03FF (значение WM_USER - 1) для системных сообщений
    . Приложения не могут использовать эти значения для личных сообщений.

  • Значения в диапазоне от 0x0400 (значение WM_USER) до 0x7FFF доступны для идентификаторов сообщений для частных классов окон.

  • Если ваше приложение имеет версию 4.0, вы можете использовать значения идентификатора сообщения в диапазоне от 0x8000 (WM_APP) до 0xBFFF для личных сообщений.

  • система возвращает идентификатор сообщения в диапазоне от 0xC000 до 0xFFFF, когда приложение вызывает функцию RegisterWindowMessage
    для регистрации сообщения. Идентификатор сообщения, возвращаемый этой функцией
    , гарантированно будет уникальным во всей системе. Использование
    этой функции предотвращает конфликты, которые могут возникнуть, если другие приложения используют тот же идентификатор сообщения для разных целей.

Чтение документации WINAPI, чтобы узнать, что ожидается в каждом параметре, поможет вам найти правильные значения для передачи и имеет решающее значение для получения ожидаемых результатов от вашего кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...