在Java Swing中,如何将Win32窗口句柄(hwnd)引用到窗口?

时间:2020-12-22 07:04:59

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

在Java 1.4中,您可以使用((SunToolkit) Toolkit.getDefaultToolkit()). getnativewindowhandlefromcomponent(),但它被删除了。

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?

看来你现在必须用JNI来做这个了。您是否有JNI代码和示例Java代码?

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

我需要它调用Win32 GetWindowLong和SetWindowLong API调用,这可以通过Jawin库完成。

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

我想要一些非常精确的东西,这样我就可以把一个引用传递给JDialog或JFrame,并获取窗口句柄。

Swing transparency using JNI may be related.

使用JNI的Swing透明性可能是相关的。

7 个解决方案

#1


20  

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

您没有编写任何C/JNI代码。从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).
  • 它使用一个太阳。*包。显然,这不是公共API。但它不太可能改变(我认为比上面的解决方案更不可能打破)。
  • This will compile and run on Windows only. You would need to turn this into reflection code for this to be portable.
  • 这将只在Windows上编译和运行。为了便于携带,您需要将其转换为反射代码。

#2


13  

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

这个小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;
 }

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.

有了JNA,就简单多了。我做了一个小的例子,找到了手柄,并使用它把程序带到前面。

#3


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().

下面的代码让您通过一个组件来获取窗口句柄(HWND)。为了确保组件有相应的窗口句柄,在组件上调用is轻量级(),并验证它等于false。如果没有,通过调用Component.getParent()来尝试它的父元素。

Java code:

Java代码:

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

Header file main.h:

头文件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:

C 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


6  

Both of the above methods work just fine, but both return a HWND as a java int (32bits). this is fine for a 32 bit platform, but it will be unlikely that your application will be functional on a 64bit platform. I would change the return types to longs (64bits) as this will behave correctly on both 64 and 32bit systems (you'll only need to recompile the DLL)

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

#5


4  

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

我发现: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.

JNA允许您调用本地库,而不必编写jni本机代码。事实证明,库本身有一个方法,它使用一个窗口并产生一个int,大概是一个处理(或指针?),希望在所有平台上都能工作。

#6


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.

在JNA库中,我们看到在Java 5和6中使用本机AWT在运行headless时不满足的链接错误,所以使用动态链接。在https://github.com/twall/jna/blob/master/native/dispatch.c中查看方法Java_com_sun_jna_Native_getWindowHandle0。

#7


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.

这和Jared MacD的答案是一样的,但是它使用反射,这样代码就可以在非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);

    }


}

#1


20  

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

您没有编写任何C/JNI代码。从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).
  • 它使用一个太阳。*包。显然,这不是公共API。但它不太可能改变(我认为比上面的解决方案更不可能打破)。
  • This will compile and run on Windows only. You would need to turn this into reflection code for this to be portable.
  • 这将只在Windows上编译和运行。为了便于携带,您需要将其转换为反射代码。

#2


13  

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

这个小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;
 }

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.

有了JNA,就简单多了。我做了一个小的例子,找到了手柄,并使用它把程序带到前面。

#3


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().

下面的代码让您通过一个组件来获取窗口句柄(HWND)。为了确保组件有相应的窗口句柄,在组件上调用is轻量级(),并验证它等于false。如果没有,通过调用Component.getParent()来尝试它的父元素。

Java code:

Java代码:

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

Header file main.h:

头文件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:

C 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


6  

Both of the above methods work just fine, but both return a HWND as a java int (32bits). this is fine for a 32 bit platform, but it will be unlikely that your application will be functional on a 64bit platform. I would change the return types to longs (64bits) as this will behave correctly on both 64 and 32bit systems (you'll only need to recompile the DLL)

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

#5


4  

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

我发现: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.

JNA允许您调用本地库,而不必编写jni本机代码。事实证明,库本身有一个方法,它使用一个窗口并产生一个int,大概是一个处理(或指针?),希望在所有平台上都能工作。

#6


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.

在JNA库中,我们看到在Java 5和6中使用本机AWT在运行headless时不满足的链接错误,所以使用动态链接。在https://github.com/twall/jna/blob/master/native/dispatch.c中查看方法Java_com_sun_jna_Native_getWindowHandle0。

#7


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.

这和Jared MacD的答案是一样的,但是它使用反射,这样代码就可以在非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);

    }


}