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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/386792/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:06:33  来源:igfitidea点击:

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

javawinapiswingjava-native-interfacehwnd

提问by Sarel Botha

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 JNImay be related.

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

采纳答案by Sarel Botha

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

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

Java code:

爪哇代码:

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 源代码 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;

}

回答by RealHowTo

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 examplewhich find the handle and use it to bring the program to front.

使用 JNA,它会更容易一些。我做了一个小例子,它找到了句柄并用它把程序带到了前面。

回答by Jared MacD.

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

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

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.
  • 这使用 sun.* 包。显然这不是公共 API。但它不太可能改变(我认为比上面的解决方案更不容易崩溃)。
  • 这将仅在 Windows 上编译和运行。您需要将其转换为反射代码以使其具有可移植性。

回答by Mike

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 本机代码即可调用本机库。原来库本身有一个方法,它接受一个 Window 并产生一个 int,大概是一个句柄(或指针?),希望在所有平台上都可以使用。

回答by Evandro Millian

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_getWindowHandle0in https://github.com/twall/jna/blob/master/native/dispatch.c.

在 JNA 库中,我们看到在 Java 5 和 6 中使用 Native AWT 在无头运行时出现 UnsatisfiedLinkError,因此使用动态链接。查看方法Java_com_sun_jna_Native_getWindowHandle0https://github.com/twall/jna/blob/master/native/dispatch.c

回答by Sarel Botha

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

    }


}