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

6

29

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

It looks like you have to use JNI to do this now. Do you have the JNI code and sample Java code to do this?

I need this to call the Win32 GetWindowLong and SetWindowLong API calls, which can be done via the Jawin library.

I would like something very precise so I can pass a reference to the JDialog or JFrame and get the window handle.

Swing transparency using JNI may be related.

Highcolored answered 22/12, 2008 at 17:20 Comment(0)
H
10

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;

}
Highcolored answered 5/1, 2009 at 17:40 Comment(3)
Sorry to bump a very old topic here, but I keep getting an EXCEPTION_ACCESS_VIOLATION in jvm.dll whenever I try to get the drawing surface (GetDrawingSurface) of a component (in my case a java.awt.Cavas). I made sure it is not lightweight and it is already visible on the screen. Has anything changed in Java 1.6 or is there anything else you need to do before you can get the drawing surface?Sargasso
No idea. Try asking a new question to get more eyes on the issue.Highcolored
pdinklag, were you able to deal with that issue calling GetDrawingSurface? I experience the same problem now, and jvm crashes in DSGetDrawingSurface. Tried with several jvms (1.6 and 1.7) - still crashes.Stephaniestephannie
R
23

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.
Raskind answered 16/9, 2010 at 21:2 Comment(3)
mike rodent asked " Thanks, this looks really good... but with WComponentPeer I'm getting: "Access restriction on required library, rt.jar" - rt.jar is part of my OpenOffice API imports. Given that sun.awt.windows classes aren't public, how do you use them like this?"Capacitate
@mike: reflection might help: comments.gmane.org/gmane.comp.video.mplayer.user/58067 @Jared you might be able to compile it in windows, just then never run that particular code in other OS's and it might work.Capacitate
getPeer() is deprecated as of JDK version 1.1.Alaska
H
15

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;
 }
Howlett answered 23/12, 2008 at 18:50 Comment(4)
just be sure to set the window title to something really, really unique before the call (so you don't accidentally pick up the hwnd for another window with the same title - the FindWindow call is not process specific)Mineralogist
This is not precise enough. I'd rather not hope that the window title is not in use by another window.Highcolored
You can replace the "NULL" with a class name to make the search more precise. You determine the window class name with a special tool like SPY++ or WinID.Howlett
Small example is awesomeAzikiwe
H
10

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;

}
Highcolored answered 5/1, 2009 at 17:40 Comment(3)
Sorry to bump a very old topic here, but I keep getting an EXCEPTION_ACCESS_VIOLATION in jvm.dll whenever I try to get the drawing surface (GetDrawingSurface) of a component (in my case a java.awt.Cavas). I made sure it is not lightweight and it is already visible on the screen. Has anything changed in Java 1.6 or is there anything else you need to do before you can get the drawing surface?Sargasso
No idea. Try asking a new question to get more eyes on the issue.Highcolored
pdinklag, were you able to deal with that issue calling GetDrawingSurface? I experience the same problem now, and jvm crashes in DSGetDrawingSurface. Tried with several jvms (1.6 and 1.7) - still crashes.Stephaniestephannie
R
7

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.

Reply answered 27/4, 2011 at 16:41 Comment(1)
Actually getWindowPointer() is for Windows. According to their docs the method getWindowID() is for X11.Highcolored
G
1

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.

Goudy answered 1/7, 2011 at 20:46 Comment(0)
H
1

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

    }


}
Highcolored answered 3/8, 2012 at 18:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.