Winapi SetWindowLongPtr在ShutdownBlockReasonCreate/Destroy中实现JNI本机代码

 2023-01-19    391  

问题描述

我目前正在从事一个Java项目,该项目涉及Eclipse RCP使用SWT,并试图通过在保存时向Windows环境中的用户提供有意义的消息来处理优雅的关闭.我本来应该使用 ShutDownBlockReasonCreate 和 shutdowndowndowndowndownblockreasondestroy apis来实现这一目标,但是经过一项研究,我不得不在我非常陌生的C ++本机代码中实施它们.因为它们在JNA和Eclipse SWT中不可用,因此无法提供此类功能(愿意知道否则)

经过所有的努力,我能够将工作的C ++代码(如下)组合在一起以控制SWT窗口(通过引用另一个实现 https://github.com/seraphy/javagracefulshutdownforwin7 ).但是,我偶然发现了与WindowProc回调有关的问题.来自Java背景这些语法花了我一段时间才理解.但是我有点想做什么.因为这是我们需要处理wm_queryendsession和wm_endsession消息的地方.

Winapi SetWindowLongPtr在ShutdownBlockReasonCreate/Destroy中实现JNI本机代码

但是,在解决这个问题之前,我想在这篇文章中谈论的问题与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文档.

预先感谢!

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

推荐答案

首先,您是在调用 FindWindow() 的ANSI版本,不接受UTF-8字符串.使用 unicode版本接受UTF-16字符串. Java字符串本地使用UTF-16进行公共界面,因此您无需浪费时间将它们不必要地转换为UTF-8.

第二,打电话后您的窗口无法正常操作, SetWindowLongPtr() 因为您的AppWndProc()需要使用 CallWindowProc() 而不是 DefWindowProc() 调用您替换的先前窗口过程.另外,使用AppWndProc()完成后,您不会还原以前的窗口过程.

第三,您应该使用 而不是SetWindowLongPtr(). See Disadvantages旧的子分类方法和 Safer safer子分类.

话虽如此,请尝试更多类似的东西:

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

以上所述是小编给大家介绍的Winapi SetWindowLongPtr在ShutdownBlockReasonCreate/Destroy中实现JNI本机代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/25811.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。