Как в Java Swing получить ссылку дескриптора окна Win32 (hwnd) на окно?

В Java 1.4 вы могли использовать ((SunToolkit) Toolkit.getDefaultToolkit ()). GetNativeWindowHandleFromComponent (), но это было удалено.

Похоже, теперь для этого вам нужно использовать JNI. У вас есть код JNI и образец кода Java для этого?

Мне нужно это для вызова вызовов API Win32 GetWindowLong и SetWindowLong, что можно сделать через библиотеку Jawin.

Мне нужно что-то очень точное, чтобы я мог передать ссылку на JDialog или JFrame и получить дескриптор окна.

Прозрачность качелей с использованием JNI может быть связано.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
27
0
44 595
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Этот небольшой метод 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 это немного проще. Я сделал небольшой пример, который нашел дескриптор и использовал его, чтобы вывести программу на передний план.

просто не забудьте установить заголовок окна на что-то действительно, действительно уникальное перед вызовом (чтобы вы случайно не выбрали hwnd для другого окна с тем же заголовком - вызов FindWindow не зависит от процесса)

Kevin Day 27.12.2008 02:39

Это недостаточно точно. Я бы не стал надеяться, что заголовок окна не используется другим окном.

Sarel Botha 06.01.2009 00:52

Вы можете заменить «NULL» на имя класса, чтобы сделать поиск более точным. Вы определяете имя класса окна с помощью специального инструмента, такого как SPY ++ или WinID.

RealHowTo 10.02.2009 06:51

Небольшой пример - это круто

user2171669 15.03.2014 15:08
Ответ принят как подходящий

Следующий код позволяет передать компонент, чтобы получить для него дескриптор окна (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 14.03.2011 09:56

Без понятия. Попробуйте задать новый вопрос, чтобы больше узнать о проблеме.

Sarel Botha 14.03.2011 23:02

pdinklag, удалось ли вам решить эту проблему с помощью GetDrawingSurface? У меня сейчас та же проблема, и jvm вылетает в DSGetDrawingSurface. Пробовал с несколькими jvms (1.6 и 1.7) - все равно вылетает.

Archie 13.09.2012 13:30

Вам не нужно писать код 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. Но вряд ли это изменится (и я думаю, что меньше шансов сломаться, чем решения выше).
  • Это будет компилироваться и работать только в Windows. Вам нужно будет превратить это в код отражения, чтобы это было переносимым.

mike rodent спросил: «Спасибо, выглядит действительно хорошо ... но с WComponentPeer я получаю:« Ограничение доступа к необходимой библиотеке, rt.jar »- rt.jar является частью моего импорта OpenOffice API. Учитывая, что sun.awt. классы Windows не являются общедоступными, как вы их используете? "

rogerdpack 02.07.2011 07:48

@mike: отражение может помочь: comments.gmane.org/gmane.comp.video.mplayer.user/58067 @Jared, возможно, вы сможете скомпилировать его в Windows, только тогда никогда не запускайте этот конкретный код в других ОС, и он может сработать.

rogerdpack 02.07.2011 07:53

getPeer () устарел с версии 1.1 JDK.

glenneroo 11.11.2016 20:04

Нашел вот это: http://jna.java.net/javadoc/com/sun/jna/Native.html#getWindowID(java.awt.Window)

JNA позволяет вызывать собственные библиотеки без необходимости писать собственный код jni. Оказывается, сама библиотека имеет метод, который принимает Window и создает int, предположительно дескриптор (или указатель?), Который, надеюсь, работает на всех платформах.

На самом деле getWindowPointer () предназначен для Windows. Согласно их документам, метод getWindowID () предназначен для X11.

Sarel Botha 03.08.2012 21:46

В библиотеке 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);

    }


}

Другие вопросы по теме