Microsoft SDK for Java

Callbacks in Java

Write callbacks in Java by extending the system class com.ms.dll.Callback.

Declaring a Method that Takes a Callback

To represent a callback parameter in Java, declare the Java type to be either type com.ms.dll.Callback or a class that derives from Callback. For example, the Microsoft® Win32® EnumWindows function is prototyped as follows.

  BOOL EnumWindows(WNDENUMPROC wndenumproc, LPARAM lparam);

The corresponding Java prototype is shown in the following example.

  import com.ms.dll.Callback;
  /** @dll.import("USER32") */
  static native boolean EnumWindows(Callback wndenumproc,
                                    int lparam);

Invoking a Function that Takes a Callback

To invoke a function that takes a callback, you need to define a class that extends Callback. The derived class must expose one non-static method, callback (all lowercase). Continuing with the EnumWindows previous example, the C language definition of WNDENUMPROC looks like this:

  BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lparam);

To author an EnumWindowsProc in Java, declare a class that extends Callback as follows.

  class EnumWindowsProc extends Callback
  {
    public boolean callback(int hwnd, int lparam)
    {
      StringBuffer text = new StringBuffer(50);
      GetWindowText(hwnd, text, text.capacity()+1);
         
      if (text.length() != 0) {
        System.out.println("hwnd = " + Integer.toHexString(hwnd) +
                           "h: Text = " + text);
      }
      return true;  // Return TRUE to continue enumeration.
    }
 
  /** @dll.import("USER32") */
  private static native int GetWindowText(int hwnd, StringBuffer text,
                                          int cch);
  }

Invoke EnumWindows with this callback as follows.

  boolean result = EnumWindows(new EnumWindowsProc(), 0);

Restrictions on Types Accepted by the Callback Method

The return type of the Callback method must be void, int, boolean, char, or short. The only parameter type currently allowed is the int type. Fortunately, this is not as restrictive as it sounds. You can use the DllLib methods ptrToStringAnsi, ptrToStringUni, and ptrToString to treat a parameter as an LPTSTR. You can use the ptrToStruct method to treat a parameter as a pointer to an @dll.struct class.

Associating Data with a Callback

Passing data from the caller of the function to the callback is frequently necessary. This explains why EnumWindows takes an extra lparam argument. Most Win32 functions that take callbacks accept one extra 32-bit parameter passed to the callback without interpretation. With the callback mechanism, it is unnecessary to pass data using the lparam argument. Because the callback method is non-static, you can store your data as fields in the EnumWindowsProc object.

The Lifetime of a Callback

Ensure that the callback is not reclaimed by garbage collection before the native function is finished with it. If the callback is short-term (callable for only the duration of one function call), no special action is required because a Callback passed to a DLL function is guaranteed to be ignored by garbage collection while the call is in progress.

If a callback is long-term (used across function calls), protect the callback from being reclaimed by storing a reference to it in a Java data structure. You can also store references to callbacks within native data structures by using the com.ms.dll.Root class to wrap the callback inside a root handle. The root handle is a 32-bit handle that prevents the callback from being reclaimed until the handle is explicitly freed. For example, a root handle to a WndProc can be stored in the application data area of an HWND structure, and then explicitly freed on the WM_NCDESTROY message.

Embedding a Callback Inside a Structure

To embed a callback inside a structure, you can first call the com.ms.dll.Root.alloc method to wrap the callback in a root handle. Then pass the root handle to the com.ms.DllLib.addrOf method to obtain the actual (native) address of the callback. Then, store this address as an integer.

For example, the WNDCLASS structure can be declared in Java as follows.

  /** @dll.struct() */
  class WNDCLASS {
    int style;
    int   lpfnWndProc; // CALLBACK
    ... /* <Other fields deleted for brevity.> */
  }

Callback has been extended as follows.

  class WNDPROC extends Callback
  {
    public int callback(int hwnd, int msg, int wparam, int lparam)
    {   
   ...
    }
  }

To store a pointer to the Callback inside the WNDCLASS object, use the following sequence.

  import com.ms.dll.*;

  WNDCLASS wc = new WNDCLASS();
  int callbackroot = Root.alloc(new WNDPROC());
  wc.lpfnWndProc = DllLib.addrOf(callbackroot);

© 1999 Microsoft Corporation. All rights reserved. Terms of use.