В Java 1.4 вы могли использовать ((SunToolkit) Toolkit.getDefaultToolkit ()). GetNativeWindowHandleFromComponent (), но это было удалено.
Похоже, теперь для этого вам нужно использовать JNI. У вас есть код JNI и образец кода Java для этого?
Мне нужно это для вызова вызовов API Win32 GetWindowLong и SetWindowLong, что можно сделать через библиотеку Jawin.
Мне нужно что-то очень точное, чтобы я мог передать ссылку на JDialog или JFrame и получить дескриптор окна.
Прозрачность качелей с использованием JNI может быть связано.




Этот небольшой метод 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 это немного проще. Я сделал небольшой пример, который нашел дескриптор и использовал его, чтобы вывести программу на передний план.
Это недостаточно точно. Я бы не стал надеяться, что заголовок окна не используется другим окном.
Вы можете заменить «NULL» на имя класса, чтобы сделать поиск более точным. Вы определяете имя класса окна с помощью специального инструмента, такого как SPY ++ или WinID.
Небольшой пример - это круто
Следующий код позволяет передать компонент, чтобы получить для него дескриптор окна (HWND). Чтобы убедиться, что у компонента есть соответствующий дескриптор окна, вызовите isLightWeight () для компонента и убедитесь, что он равен 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;
}
Извините, что затронул здесь очень старую тему, но я продолжаю получать EXCEPTION_ACCESS_VIOLATION в jvm.dll всякий раз, когда пытаюсь получить поверхность рисования (GetDrawingSurface) компонента (в моем случае java.awt.Cavas). Я убедился, что нет легкий и он уже виден на экране. Изменилось ли что-нибудь в Java 1.6 или вам нужно еще что-нибудь сделать, прежде чем вы сможете получить поверхность для рисования?
Без понятия. Попробуйте задать новый вопрос, чтобы больше узнать о проблеме.
pdinklag, удалось ли вам решить эту проблему с помощью GetDrawingSurface? У меня сейчас та же проблема, и jvm вылетает в DSGetDrawingSurface. Пробовал с несколькими jvms (1.6 и 1.7) - все равно вылетает.
Вам не нужно писать код C / JNI. С Java:
import sun.awt.windows.WComponentPeer;
public static long getHWnd(Frame f) {
return f.getPeer() != null ? ((WComponentPeer) f.getPeer()).getHWnd() : 0;
}
Предостережения:
mike rodent спросил: «Спасибо, выглядит действительно хорошо ... но с WComponentPeer я получаю:« Ограничение доступа к необходимой библиотеке, rt.jar »- rt.jar является частью моего импорта OpenOffice API. Учитывая, что sun.awt. классы Windows не являются общедоступными, как вы их используете? "
@mike: отражение может помочь: comments.gmane.org/gmane.comp.video.mplayer.user/58067 @Jared, возможно, вы сможете скомпилировать его в Windows, только тогда никогда не запускайте этот конкретный код в других ОС, и он может сработать.
getPeer () устарел с версии 1.1 JDK.
Нашел вот это: http://jna.java.net/javadoc/com/sun/jna/Native.html#getWindowID(java.awt.Window)
JNA позволяет вызывать собственные библиотеки без необходимости писать собственный код jni. Оказывается, сама библиотека имеет метод, который принимает Window и создает int, предположительно дескриптор (или указатель?), Который, надеюсь, работает на всех платформах.
На самом деле getWindowPointer () предназначен для Windows. Согласно их документам, метод getWindowID () предназначен для X11.
В библиотеке JNA мы видим, что использование Native AWT в Java 5 и 6 UnsatisfiedLinkError при запуске без заголовка, поэтому используйте динамическое связывание. См. Метод Java_com_sun_jna_Native_getWindowHandle0 в https://github.com/twall/jna/blob/master/native/dispatch.c.
Это то же самое, что и ответ Джареда Макда, но он использует отражение, чтобы код мог компилироваться и загружаться на компьютере, отличном от 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);
}
}
просто не забудьте установить заголовок окна на что-то действительно, действительно уникальное перед вызовом (чтобы вы случайно не выбрали hwnd для другого окна с тем же заголовком - вызов FindWindow не зависит от процесса)