In Java Swing how do you get a Win32 window handle (hwnd) reference to a window?

后端 未结 6 640
伪装坚强ぢ
伪装坚强ぢ 2020-11-28 09:24

In Java 1.4 you could use ((SunToolkit) Toolkit.getDefaultToolkit()).getNativeWindowHandleFromComponent() but that was removed.

It looks like you have to use JNI to

相关标签:
6条回答
  • 2020-11-28 09:51

    You don't have write any C/JNI code. From Java:

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

    Caveats:

    • This uses a sun.* package. Obviously this is not public API. But it is unlikely to change (and I think less likely to break than the solutions above).
    • This will compile and run on Windows only. You would need to turn this into reflection code for this to be portable.
    0 讨论(0)
  • 2020-11-28 09:53

    In JNA library we see that using Native AWT in Java 5 and 6 UnsatisfiedLinkError when run headless, so use dynamic linking. See the method Java_com_sun_jna_Native_getWindowHandle0 in https://github.com/twall/jna/blob/master/native/dispatch.c.

    0 讨论(0)
  • 2020-11-28 09:57

    I found this: http://jna.java.net/javadoc/com/sun/jna/Native.html#getWindowID(java.awt.Window)

    JNA lets you call native libraries without having to write jni native code. Turns out the library itself has a method that takes a Window and produces an int, presumably a handle (or pointer?) that hopefully works on all platforms.

    0 讨论(0)
  • 2020-11-28 09:59

    The following code lets you pass a Component to get the window handle (HWND) for it. To make sure that a Component has a corresponding window handle call isLightWeight() on the Component and verify that it equals false. If it doesn't, try it's parent by calling Component.getParent().

    Java code:

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

    Header file 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
    

    The C source 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;
    
    }
    
    0 讨论(0)
  • 2020-11-28 10:03

    This is the same as Jared MacD's answer but it uses reflection so that the code can compile and load on a non-Windows computer. Of course it will fail if you try to call it.

    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);
    
        }
    
    
    }
    
    0 讨论(0)
  • 2020-11-28 10:06

    This little JNI method accepts a window title and returns the corresponding window handle.

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

    UPDATE:

    With JNA, it's a little bit easier. I made a small example which find the handle and use it to bring the program to front.

    0 讨论(0)
提交回复
热议问题