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.

Community
  • 1
  • 1
Sarel Botha
  • 12,419
  • 7
  • 54
  • 59

6 Answers6

24

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.
rogerdpack
  • 62,887
  • 36
  • 269
  • 388
Jared MacD.
  • 241
  • 2
  • 2
  • 1
    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?" – rogerdpack Jul 02 '11 at 03:48
  • @mike: reflection might help: http://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. – rogerdpack Jul 02 '11 at 03:53
  • getPeer() is deprecated as of JDK version 1.1. – glenneroo Nov 11 '16 at 17:04
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;
 }
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
RealHowTo
  • 34,977
  • 11
  • 70
  • 85
  • 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) – Kevin Day Dec 26 '08 at 23:39
  • This is not precise enough. I'd rather not hope that the window title is not in use by another window. – Sarel Botha Jan 05 '09 at 21:52
  • 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. – RealHowTo Feb 10 '09 at 03:51
  • 2
    Small example is awesome – user2171669 Mar 15 '14 at 11:08
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;

}
Sarel Botha
  • 12,419
  • 7
  • 54
  • 59
  • 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? – pdinklag Mar 14 '11 at 06:56
  • No idea. Try asking a new question to get more eyes on the issue. – Sarel Botha Mar 14 '11 at 20:02
  • 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. – Archie Sep 13 '12 at 09:30
6

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.

Mike
  • 2,393
  • 3
  • 25
  • 37
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);

    }


}
Sarel Botha
  • 12,419
  • 7
  • 54
  • 59
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.

Jon
  • 2,932
  • 2
  • 23
  • 30