Winapi-ShutdownBlockReasonCreate/Destroy JNI本机代码的实现中的SetWindowLongPtr [英] Winapi - SetWindowLongPtr in ShutdownBlockReasonCreate / Destroy implementation of JNI native code

查看:133
本文介绍了Winapi-ShutdownBlockReasonCreate/Destroy JNI本机代码的实现中的SetWindowLongPtr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用SWT进行涉及Eclipse RCP的Java项目,并试图通过在保存时向Windows环境中的用户提供有意义的消息来处理正常关闭.我本应该使用 ShutdownBlockReasonCreate ShutdownBLockReasonDestroy API来实现这一点,但是经过一些研究,我不得不用我刚接触的C ++本机代码来实现它们.由于它们在JNA中不可用,因此Eclipse SWT不提供这种功能(很想知道否则)

I'm currently working on a Java project involving Eclipse RCP using SWT and was trying to handle graceful shutdown by providing meaningful messages to user in Windows environment when saving. I was supposed to use ShutdownBlockReasonCreate and ShutdownBLockReasonDestroy APIs to achieve this but after some research I had to implement them in C++ native code which I'm very new to. As they are not available in JNA and Eclipse SWT does not provide such capability off-the-shelf (would love to know otherwise)

经过所有努力,我能够整理一个有效的C ++代码(如下所示)以控制SWT窗口(通过引用另一种实现 https://github.com/seraphy/JavaGracefulShutdownForWin7 ).但是,我偶然发现了一个与WindowProc CALLBACK有关的问题.来自Java的这些语法使我花了一些时间来理解.但是我有点理解它正在尝试做的事情.因为这是我们需要处理WM_QUERYENDSESSION和WM_ENDSESSION消息的地方.

After going through all the effort I was able to pull together a working C++ code (as follows) to get control of the SWT window (by referencing another implementation https://github.com/seraphy/JavaGracefulShutdownForWin7). However I stumble upon an issue which relates to WindowProc CALLBACK. Coming from Java background these syntax took me a while to understand. But I sort of get what it's trying to do. Because this is where we need to handle WM_QUERYENDSESSION and WM_ENDSESSION messages.

但是,在此之前,我想在这篇文章中讨论的问题与Windows API SetWindowLongPtr 特别相关,正如您在Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title)函数中看到的那样.如您所见,我将其注释掉了,仅仅是因为在ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON)之后调用此方法时,我的窗口的行为非常奇怪.例如

But before getting to that, the problem I want to talk about in this post is specifically related to the windows API SetWindowLongPtr as you can see in the Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title) function. As you can see I commented it out, simply because my window tends to behave very strange when this method was called after ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON). For example,

  • 单击文件"选项时,不再显示菜单;
  • 调整窗口大小时,当您尝试调整窗口大小时,一半窗口变暗 调整大小
  • 关闭窗口时,基础进程仍在运行
  • "File" option when clicked, no longer show menu;
  • When resizing the window, half the window become dark when you try to resize it back
  • When closing the window, the underlying process still running

是的,我需要使用此方法来激活用于接收os消息的窗口的控件,但是随后它开始与已经构建的Eclipse SWT窗口混淆.有谁知道我是否正确地完成了整个工作?还是我偏离了轨道? SetWindowLongPtr 到底有什么作用?我找不到任何好的参考资料,也无法从阅读Microsoft文档中受益匪浅.

Yes I need to use this method in order to activate the control of the window for receiving os messages, but then it started to mess up with the Eclipse SWT window that was already built. Does anyone know if I have implemented this whole thing correctly? Or am I off-track? What does SetWindowLongPtr do exactly? I couldn't find any good reference and I couldn't get much out of reading the Microsoft Doc.

提前谢谢!

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

推荐答案

首先,您正在调用 Unicode版本,接受UTF-16字符串. Java字符串本机使用UTF-16作为其公共接口,因此您无需浪费时间将它们转换为UTF-8.

Firstly, you are calling the ANSI version of FindWindow(), which doesn't accept UTF-8 strings. Use the Unicode version instead, which accepts UTF-16 strings. Java strings natively use UTF-16 for their public interface, so you don't need to waste time converting them to UTF-8 unnecessarily.

第二,调用 CallWindowProc() 而不是 DefWindowProc() 调用您替换的上一个窗口过程.另外,使用AppWndProc()完成操作后,您将不会还原以前的窗口过程.

Second, your window fails to operate correctly after calling SetWindowLongPtr() because your AppWndProc() needs to use CallWindowProc() instead of DefWindowProc() to call the previous window procedure that you replaced. Also, you are not restoring the previous window procedure when you are done using AppWndProc().

第三,您应该使用 SetWindowSubclass() 而不是SetWindowLongPtr().请参见缺点和更安全的子分类.

Third, you should be using SetWindowSubclass() instead of SetWindowLongPtr(). See Disadvantages of the Old Subclassing Approach and Safer subclassing.

话虽如此,请尝试以下类似操作:

With that said, try something more like this instead:

#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-ShutdownBlockReasonCreate/Destroy JNI本机代码的实现中的SetWindowLongPtr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆