views:

5046

answers:

4

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

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?

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

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

+5  A: 

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

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

bye.

RealHowTo
just be sure to set the window title to something really, really unique before the call (so you don't accidentally pick up the hwnd for another window with the same title - the FindWindow call is not process specific)
Kevin Day
This is not precise enough. I'd rather not hope that the window title is not in use by another window.
sjbotha
You can replace the "NULL" with a class name to make the search more precise. You determine the window class name with a special tool like SPY++ or WinID.
RealHowTo
+4  A: 

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

Java code:

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

Header file 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:

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

}
sjbotha
+3  A: 

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)

luke
Thank you very much.
sjbotha
+1  A: 

You don't have write any C/JNI code. From 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).
  • This will compile and run on Windows only. You would need to turn this into reflection code for this to be portable.
Jared MacD.