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

在Java 1.4中,你可以使用((SunToolkit)Toolkit.getDefaultToolkit())。getNativeWindowHandleFromComponent(),但是被删除了。

它看起来像你现在必须使用JNI来做到这一点。 你有JNI代码和示例Java代码来做到这一点?

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

我想要非常精确的东西,所以我可以传递一个对JDialog或JFrame的引用,并获得窗口句柄。

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

你没有写任何C / JNI代码。 来自Java:

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

注意事项:

  • 这使用了一个sun。*包。 显然这不是公共API。 但它不太可能改变(我认为比上面的解决scheme更不容易打破)。
  • 这将只在Windows上编译和运行。 您需要将其转换为reflection代码,以使其具有便携性。

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

更新:

有了JNA,它会更容易一些。 我做了一个小例子 ,find句柄,并用它来把程序放在前面。

下面的代码可以让你传递一个Component来获取窗口句柄(HWND)。 要确保组件具有对应的窗口句柄,请调用组件上的isLightWeight(),并validation它是否等于false。 如果没有,通过调用Component.getParent()来尝试它的父类。

Java代码:

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

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

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

上述两种方法都可以正常工作,但是都将HWND作为java int(32位)返回。 这对于32位平台来说很好,但是你的应用程序在64位平台上不太可能正常工作。 我会将返回types更改为long(64位),因为这将在64位和32位系统上正确运行(您只需重新编译DLL)

我发现这个: http : //jna.java.net/javadoc/com/sun/jna/Native.html#getWindowID(java.awt.Window )

JNA可以让你调用本地库,而无需编写jni本地代码。 事实certificate,库本身有一个方法需要一个窗口,并产生一个int,大概是一个句柄(或指针?),希望可以在所有平台上工作。

在JNA库中,我们看到在运行无头时使用Java 5和6 UnsatisfiedLinkError中的Native AWT,因此使用dynamic链接。 请参阅https://github.com/twall/jna/blob/master/native/dispatch.c中的; Java_com_sun_jna_Native_getWindowHandle0方法。

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