Winapi - SetWindowLongPtr в ShutdownBlockReasonCreate / уничтожить реализацию собственного кода JNI - PullRequest
1 голос
/ 09 января 2020

В настоящее время я работаю над проектом Java, включающим Eclipse RCP с использованием SWT, и пытался корректно завершить работу, предоставляя значимые сообщения пользователю в среде Windows при сохранении. Я должен был использовать ShutdownBlockReasonCreate и ShutdownBLockReasonDestroy API для достижения этой цели, но после некоторого исследования мне пришлось реализовать их в собственном коде C ++, который я очень новичок. Так как они недоступны в JNA и Eclipse, SWT не предоставляет такую ​​возможность в готовом виде (хотелось бы знать иначе)

После всех усилий я смог собрать работающий код C ++ ( следующим образом) для получения контроля над окном SWT (путем ссылки на другую реализацию https://github.com/seraphy/JavaGracefulShutdownForWin7). Однако я наткнулся на проблему, которая касается WindowPro c CALLBACK. Исходя из Java фона, этот синтаксис занял у меня некоторое время, чтобы понять. Но я вроде понимаю, что он пытается сделать. Потому что именно здесь нам нужно обрабатывать сообщения WM_QUERYENDSESSION и WM_ENDSESSION.

Но прежде чем перейти к этому, проблема, о которой я хочу поговорить в этом посте, конкретно связана с windows API SetWindowLongPtr как вы можете видеть в функции Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title). Как вы можете видеть, я прокомментировал это просто потому, что мое окно ведет себя очень странно, когда этот метод вызывается после ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON). Например,

  • опция «Файл» при нажатии больше не отображает меню;
  • При изменении размера окна половина окна становится темной, когда вы пытаетесь изменить его размер обратно
  • При закрытии окна базовый процесс все еще работает

Да, я Нужно использовать этот метод для того, чтобы активировать управление окном для получения сообщений os, но затем оно начало портить уже построенное окно Eclipse SWT. Кто-нибудь знает, правильно ли я все это реализовал? Или я не в курсе? Что точно делает SetWindowLongPtr ? Я не смог найти ни одной хорошей ссылки, и я не смог получить много от чтения Microsoft Do c.

Заранее спасибо!

#include <jni.h>

#include <iostream>
#include "com_app_project_winapi_WindowsAPI.h"
#include <windows.h>

using namespace std;

namespace {

    LPCWSTR SHUTDOWN_REASON = L"Application is still saving ...";

    LRESULT CALLBACK AppWndProc(
        _In_ HWND hWnd,
        _In_ UINT message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    ) {


        switch (message) {
            // Not doing anything yet
        }

        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}


JNIEXPORT void JNICALL Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title) {
    cout << "shutdownblockreason create" << endl;

    const char *str = NULL;

    str = (env)->GetStringUTFChars(title, 0);
    HWND hWnd = FindWindow(NULL, str);
    (env)->ReleaseStringUTFChars(title, str);
    if (hWnd == NULL) {
        return;
    }

    ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON);


    //SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(AppWndProc));

    return;
}

JNIEXPORT void JNICALL Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonDestroy(JNIEnv *env, jclass cls, jstring title) {
    cout << "shutdownblockreason destroy" << endl;

    const char *str = NULL;

    str = (env)->GetStringUTFChars(title, 0);
    HWND hWnd = FindWindow(NULL, str);
    (env)->ReleaseStringUTFChars(title, str);
    if (hWnd == NULL) {
        return;
    }

    ShutdownBlockReasonDestroy(hWnd);

    return;
}

1 Ответ

2 голосов
/ 09 января 2020

Во-первых, вы вызываете версию ANSI FindWindow(), которая не принимает строки UTF-8. Вместо этого используйте версию Unicode , которая принимает строки UTF-16. Строки Java изначально используют UTF-16 для своего интерфейса c, поэтому вам не нужно тратить время на их преобразование в UTF-8 без необходимости.

Во-вторых, ваше окно не работает правильно после вызова SetWindowLongPtr(), потому что ваш AppWndProc() должен использовать CallWindowProc() вместо DefWindowProc() для вызова предыдущей оконной процедуры, которую вы заменили. Кроме того, вы не восстанавливаете предыдущую оконную процедуру, когда вы закончили использовать AppWndProc().

В-третьих, вы должны использовать SetWindowSubclass() вместо SetWindowLongPtr(). См. Недостатки старого подхода к подклассам и Более безопасные подклассы .

С учетом сказанного, попробуйте что-то более похожее на это:

#include <jni.h>
#include <iostream>
#include "com_app_project_winapi_WindowsAPI.h"
#include <windows.h>
#include <commctrl.h>

namespace {
    LPCWSTR SHUTDOWN_REASON = L"Application is still saving ...";

    /*
    WNDPROC PrevWndProc = NULL;
    LRESULT CALLBACK AppWndProc(
        _In_ HWND hWnd,
        _In_ UINT message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam
    ) {
    */
    LRESULT CALLBACK AppWndProc(
        _In_ HWND hWnd,
        _In_ UINT message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam,
        _In_ UINT_PTR uIdSubclass,
        _In_ DWORD_PTR dwRefData
    ) {
        switch (message) {
            case WM_NCDESTROY:
                RemoveWindowSubclass(hWnd, AppWndProc, uIdSubclass);
                break;

            //...
        }

        //return CallWindowProc(PrevWndProc, hWnd, message, wParam, lParam);
        return DefSubclassProc(hWnd, message, wParam, lParam);
    }
}

JNIEXPORT void JNICALL Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title) {
    std::cout << "shutdownblockreason create" << std::endl;

    const jchar *str = env->GetStringChars(title, NULL);
    HWND hWnd = FindWindowW(NULL, (LPCWSTR) str);
    env->ReleaseStringChars(title, str);
    if (!hWnd) {
        return;
    }

    ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON);

    //PrevWndProc = (WNDPROC) SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(AppWndProc)); 
    SetWindowSubclass(hWnd, &AppWndProc, 1, 0);
}

JNIEXPORT void JNICALL Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonDestroy(JNIEnv *env, jclass cls, jstring title) {
    std::cout << "shutdownblockreason destroy" << std::endl;

    const jchar *str = env->GetStringChars(title, NULL);
    HWND hWnd = FindWindowW(NULL, (LPCWSTR) str);
    env->ReleaseStringChars(title, str);
    if (!hWnd) {
        return;
    }

    //SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(PrevWndProc));
    RemoveWindowSubclass(hWnd, &AppWndProc, 1);

    ShutdownBlockReasonDestroy(hWnd);
}
...