简体   繁体   English

如何修改没有窗口句柄的窗口类?

[英]How do I modify a window class without a window handle?

I am currently trying to translate a few WIN32API functions to Java using JNI. 我目前正在尝试使用JNI将一些WIN32API函数转换为Java。 One of those functions is RegisterClassEx . 这些功能之一是RegisterClassEx Usually, I think you would specify a different callback function for every window class you register, but since I'm translating the callback to Java as well this doesn't work. 通常,我认为您会为注册的每个窗口类指定一个不同的回调函数,但是由于我将回调也转换为Java,因此这是行不通的。

So the current plan is to append a jobject (defined as _jobject* ) to the window class and work with that in the callback. 因此,当前的计划是将一个jobject (定义为_jobject* )添加到窗口类,并在回调中使用它。 Problem is: you can only change data attached to a window class using a HWND. 问题是:您只能使用HWND更改附加到窗口类的数据。 The MSDN documentation to the best of my knowledge doesn't specify a function that can modify a window class using only a window class ATOM or the name. 就我所知,MSDN文档未指定仅可以使用窗口类ATOM或名称来修改窗口类的函数。

Thus my question: Is there a way to change a window class (using something like SetClassLongPtr ), without having to use a valid HWND? 因此,我的问题是:是否有一种方法可以更改窗口类(使用类似SetClassLongPtr的东西),而不必使用有效的HWND?

Java side (I'll eventually add a public function that does what I actually need done): Java方面 (我最终将添加一个执行我实际需要完成的公共功能):

public class c_winjni implements i_jnisystem {
    public interface i_wnd_proc {
        public int wnd_proc(long il_hwnd, int im_message, long im_wparam, long im_lparam);
    }

    private class c_wndclassex {
        public int im_style = 0;
        public i_wnd_proc ds_wnd_proc = null;
        public int im_cls_extra = 0;
        public int im_wnd_extra = 0;
        public long il_instance = 0L;
        public long il_icon = 0L;
        public long il_small_icon = 0L;
        public long il_cursor = 0L;
        public long il_background = 0L;
        public String str_menu_name = null;
        public String str_class_name = null;
    }

    private static native short registerClassEx(c_wndclassex ds_wcx, int[] imr_error);
}

C++ side : C ++方面

LRESULT CALLBACK default_window_callback_proc(HWND ds_hwnd, UINT im_message, WPARAM im_w_param, LPARAM im_l_param) {
    return DefWindowProc(ds_hwnd, im_message, im_w_param, im_l_param);
}

/*
 * Class:     c_winjni
 * Method:    registerClassEx
 * Signature: (Lc_winjni/c_wndclassex;[I)S
 */
JNIEXPORT_EX jshort JNICALL Java_c_1winjni_registerClassEx
    (JNIEnv *ads_env, jclass /*jds_class*/, jobject jds_wcx, jintArray jimr_error)
JNI_CPPEXCEPTION_TRAP_BEGIN {
    c_jnienv jds_env(ads_env);

    jint *aim_error = NULL;
    if (jimr_error && jds_env.get_array_length(jimr_error) > 0) {
        aim_error = jds_env.get_array_elements(jimr_error, NULL);
    }

    WNDCLASSEX ds_wcx;
    ds_wcx.cbSize = sizeof(WNDCLASSEX);
    ds_wcx.style = jds_env.get_int_field(jds_wcx, "im_style");

    // Imagine I'm checking whether field ds_wnd_proc in object jds_wcx is null.
    // If it is, use the default callback (as shown below).
    // If it isn't, set ds_wcx.lpfnWndProc to some other callback that reads
    // custom class data and calls a Java function of the object attached to the window class.
    ds_wcx.lpfnWndProc = default_window_callback_proc;

    ds_wcx.cbClsExtra = jds_env.get_int_field(jds_wcx, "im_cls_extra") + sizeof(LONG_PTR);
    ds_wcx.cbWndExtra = jds_env.get_int_field(jds_wcx, "im_wnd_extra");
    ds_wcx.hInstance = (HINSTANCE) jds_env.get_long_field(jds_wcx, "il_instance");
    ds_wcx.hIcon = (HICON) jds_env.get_long_field(jds_wcx, "il_icon");
    ds_wcx.hIconSm = (HICON) jds_env.get_long_field(jds_wcx, "il_small_icon");
    ds_wcx.hCursor = (HCURSOR) jds_env.get_long_field(jds_wcx, "il_cursor");
    ds_wcx.hbrBackground = (HBRUSH) jds_env.get_long_field(jds_wcx, "il_background");
    ct_jstring<TCHAR, 256> str_menu_name(ads_env, (jstring) jds_env.get_string_field(jds_wcx, "str_menu_name"));
    ds_wcx.lpszMenuName = str_menu_name.get_data();
    ct_jstring<TCHAR, 256> str_class_name(ads_env, (jstring) jds_env.get_string_field(jds_wcx, "str_class_name"));
    ds_wcx.lpszClassName = str_class_name.get_data();

    jshort result = RegisterClassEx(&ds_wcx);
    if (result == NULL && aim_error) {
        *aim_error = GetLastError();
    }

    // commit changes and invalidate pointer
    if (aim_error) {
        jds_env.release_array_elements(jimr_error, aim_error, 0);
    }
    return result;
} JNI_CPPEXCEPTION_TRAP_END2(ads_env, 0)

The simple answer to your question is that it is only possible to modify the extra class memory using SetClassLongPtr . 您问题的简单答案是只能使用SetClassLongPtr修改额外的类内存。 For which you need a valid window handle. 为此,您需要一个有效的窗口句柄。

Interesting problem... A WNDCLASSEX is a class, and HWND is a handle to a window. 有趣的问题... WNDCLASSEX是一个类,而HWND是一个窗口的句柄。 You may think of the first as a OO class, the second as a "pointer" or "reference" an object (instance). 您可能将第一个视为OO类,将第二个视为对象(实例)的“指针”或“引用”。 Yet to modify the class, you seem to have to go through an instance of that class... Weird :) I can imagine this is the most common scenario (having the HWND) (BTW, why you don't have a HWND?) 然而,要修改该类,您似乎必须遍历该类的一个实例……很奇怪:)我可以想象这是最常见的情况(具有HWND)(顺便说一句,为什么您没有HWND? )

An idea: would it be acceptable to create a window (hiddend) using the ATOM, and use the returned HWND as a "reference" for SetClassLongPtr ? 一个想法:使用ATOM创建一个窗口(隐藏)并将返回的HWND用作SetClassLongPtr的“引用”是否可以SetClassLongPtr

As to get a valid HWND for registered class ATOM, you can use the FindWindow function . 为了获得注册类ATOM的有效HWND,可以使用FindWindow函数

By passing NULL for the lpWindowName parameter you'll get a handle to the first window that matches the class. 通过为lpWindowName参数传递NULL ,您将获得与该类匹配的第一个窗口的句柄。 Of course you'll fail if there is no window instance present. 当然,如果不存在窗口实例,您将失败。 But in this it's probably good to assume that the corresponding window class isn't registered yet. 但是在这种情况下,最好假设相应的窗口类尚未注册。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM