代码之家  ›  专栏  ›  技术社区  ›  Sarel Botha

在Java Swing中,如何获得Win32窗口句柄(HWND)引用窗口?

  •  27
  • Sarel Botha  · 技术社区  · 16 年前

    在爪哇1.4中,可以使用((SunTooToCK)工具包.GETDebug工具KoE())。

    看起来你现在必须用JNI来做这个。有JNI代码和Java代码示例吗?

    我需要这个来调用win32 getwindowlong和setwindowlong API调用,这可以通过jawin库完成。

    我想要一些非常精确的东西,这样我可以将一个引用传递给jdialog或jframe,并获得窗口句柄。

    Swing transparency using JNI 可能是相关的。

    7 回复  |  直到 11 年前
        1
  •  21
  •   rogerdpack    13 年前

    您没有编写任何C/JNI代码。来自Java:

    import sun.awt.windows.WComponentPeer;
    
    public static long getHWnd(Frame f) {
       return f.getPeer() != null ? ((WComponentPeer) f.getPeer()).getHWnd() : 0;
    }
    

    Caveats:

    • 这需要一个sun.*包。显然,这不是公共API。但它不太可能改变(我认为打破的可能性比上述解决方案要小)。
    • 这将只在Windows上编译和运行。为了便于移植,您需要将其转换为反射代码。
        2
  •  14
  •   RealHowTo    11 年前

    这个小JNI方法接受一个窗口标题并返回相应的窗口句柄。

    JNIEXPORT jint JNICALL Java_JavaHowTo_getHwnd
         (JNIEnv *env, jclass obj, jstring title){
     HWND hwnd = NULL;
     const char *str = NULL;
    
     str = (*env)->GetStringUTFChars(env, title, 0);
     hwnd = FindWindow(NULL,str);
     (*env)->ReleaseStringUTFChars(env, title, str);
     return (jint) hwnd;
     }
    

    更新:

    有了JNA,事情就简单了一点。我做了一个 small example 找到手柄,用它把程序放到最前面。

        3
  •  10
  •   Sarel Botha    15 年前

    下面的代码允许您传递一个组件来获取它的窗口句柄(hwnd)。要确保组件具有相应的窗口句柄,请调用组件上的isLightweight(),并验证它是否等于false。如果没有,请通过调用component.getParent()尝试它的父级。

    Java代码:

    package win32;
    public class Win32 {
        public static native int getWindowHandle(Component c);
    }
    

    头文件main.h:

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class win32_Win32 */
    
    #ifndef _Included_win32_Win32
    #define _Included_win32_Win32
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     win32_Win32
     * Method:    getWindowHandle
     * Signature: (Ljava/awt/Component;Ljava/lang/String;)I
     */
    JNIEXPORT jint JNICALL Java_win32_Win32_getWindowHandle
      (JNIEnv *, jclass, jobject);
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    c源main.c:

    #include<windows.h>
    #include <jni.h>
    #include <jawt.h>
    #include <jawt_md.h>
    
    HMODULE _hAWT = 0;
    
    JNIEXPORT jint JNICALL Java_win32_Win32_getWindowHandle
      (JNIEnv * env, jclass cls, jobject comp)
    {
        HWND hWnd = 0;
        typedef jboolean (JNICALL *PJAWT_GETAWT)(JNIEnv*, JAWT*);
        JAWT awt;
        JAWT_DrawingSurface* ds;
        JAWT_DrawingSurfaceInfo* dsi;
        JAWT_Win32DrawingSurfaceInfo* dsi_win;
        jboolean result;
        jint lock;
    
        //Load AWT Library
        if(!_hAWT)
            //for Java 1.4
            _hAWT = LoadLibrary("jawt.dll");
        if(!_hAWT)
            //for Java 1.3
            _hAWT = LoadLibrary("awt.dll");
        if(_hAWT)
        {
            PJAWT_GETAWT JAWT_GetAWT = (PJAWT_GETAWT)GetProcAddress(_hAWT, "_JAWT_GetAWT@8");
            if(JAWT_GetAWT)
            {
                awt.version = JAWT_VERSION_1_4; // Init here with JAWT_VERSION_1_3 or JAWT_VERSION_1_4
                //Get AWT API Interface
                result = JAWT_GetAWT(env, &awt);
                if(result != JNI_FALSE)
                {
                    ds = awt.GetDrawingSurface(env, comp);
                    if(ds != NULL)
                    {
                        lock = ds->Lock(ds);
                        if((lock & JAWT_LOCK_ERROR) == 0)
                        {
                            dsi = ds->GetDrawingSurfaceInfo(ds);
                            if(dsi)
                            {
                                dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
                                if(dsi_win)
                                {
                                    hWnd = dsi_win->hwnd;
                                }
                                else {
                                    hWnd = (HWND) -1;
                                }
                                ds->FreeDrawingSurfaceInfo(dsi);
                            }
                            else {
                                hWnd = (HWND) -2;
                            }
                            ds->Unlock(ds);
                        }
                        else {
                            hWnd = (HWND) -3;
                        }
                        awt.FreeDrawingSurface(ds);
                    }
                    else {
                        hWnd = (HWND) -4;
                    }
                }
                else {
                    hWnd = (HWND) -5;
                }
            }
            else {
                hWnd = (HWND) -6;
            }
        }
        else {
            hWnd = (HWND) -7;
        }
        return (jint)hWnd;
    
    }
    
        4
  •  5
  •   luke    15 年前

    上述两种方法都工作得很好,但是它们都返回一个HWND作为Java int(32位)。对于32位平台来说,这是可以的,但是您的应用程序不太可能在64位平台上运行。我将把返回类型更改为long(64位),因为它在64位和32位系统上都能正常工作(您只需要重新编译DLL)。

        5
  •  4
  •   Mike    13 年前

    我发现这一点: http://jna.java.net/javadoc/com/sun/jna/Native.html#getWindowID(java.awt.Window )

    JNA允许您调用本机库,而不必编写JNI本机代码。 结果发现库本身有一个方法,该方法接受一个窗口并生成一个int,大概是一个句柄(或指针?)希望在所有平台上都能工作。

        6
  •  1
  •   Jon Chetan Kalore    13 年前

    在JNA库中,我们看到在Java 5中使用原生AWT,而在无头运行时使用6不满足链接错误,因此使用动态链接。见方法 Java_com_sun_jna_Native_getWindowHandle0 在里面 https://github.com/twall/jna/blob/master/native/dispatch.c .

        7
  •  1
  •   Sarel Botha    12 年前

    这与JaredMacd的答案相同,但它使用反射,以便代码可以在非Windows计算机上编译和加载。当然,如果你试着称之为失败。

    import java.awt.Frame;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class WindowHandleGetter {
        private static final Logger log = LoggerFactory.getLogger(WindowHandleGetter.class);
        private final Frame rootFrame;
    
        protected WindowHandleGetter(Frame rootFrame) {
            this.rootFrame = rootFrame;
        }
    
        protected long getWindowId() {
    
            try {
                Frame frame = rootFrame;
    
                // The reflection code below does the same as this
                // long handle = frame.getPeer() != null ? ((WComponentPeer) frame.getPeer()).getHWnd() : 0;
    
                Object wComponentPeer = invokeMethod(frame, "getPeer");
    
                Long hwnd = (Long) invokeMethod(wComponentPeer, "getHWnd");
    
                return hwnd;
    
            } catch (Exception ex) {
                log.error("Error getting window handle");
            }
    
            return 0;
        }
    
        protected Object invokeMethod(Object o, String methodName) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    
            Class c = o.getClass();
            for (Method m : c.getMethods()) {
                if (m.getName().equals(methodName)) {
                    Object ret = m.invoke(o);
                    return ret;
                }
            }
            throw new RuntimeException("Could not find method named '"+methodName+"' on class " + c);
    
        }
    
    
    }