Dynamically Loading and Invoking DLLs

There may be times when you need more control over the loading and linking process than the @dll.import directive normally provides. For instance, your requirements might include:

  • Loading a library whose name or path must be computed at run time or generated from user input.

  • Freeing a library prior to process termination.

  • Executing a function whose name or ordinal must be computed at run time.

The Win32 APIs have always provided the ability to control loading and linking. The LoadLibrary, LoadLibraryEx, and FreeLibrary functions allow you to have explicit control over the loading and freeing of DLLs. The GetProcAddress function allows you to link to a specific export. The GetProcAddress function returns a function pointer, so any language that can call through a function pointer can implement dynamic invocation without a problem.

J/Direct allows Java programmers to declare the requisite functions in the following way:

Note   If you are using the com.ms.win32 package, these declarations also appear in the Kernel32 class.

/** @dll.import("KERNEL32",auto) */
public native static int LoadLibrary(String lpLibFileName);

/** @dll.import("KERNEL32",auto) */
public native static int LoadLibraryEx(String lpLibFileName,
                                       int hFile, int dwFlags);

/** @dll.import("KERNEL32",auto) */
public native static boolean FreeLibrary(int hLibModule);

/** @dll.import("KERNEL32",ansi) */
public native static int GetProcAddress(int hModule, String lpProcName);

Notice that GetProcAddress is declared with the ansi modifier, not auto. This is because GetProcAddress is one of the few Windows functions without a Unicode equivalent. If we were to use the auto modifier, this function would fail on Microsoft Windows NT systems.

That only leaves the problem of invoking a function obtained by GetProcAddress. For your convenience, msjava.dll, (the DLL that implements the Microsoft VM) exports a special function named call. The call function's first argument is a pointer to a second function. All call does is invoke the second function, passing it the remaining arguments.

The following is an example of how an application could load a DLL and call AFunction exported by the DLL:

BOOL AFunction(LPCSTR argument);

  /** @dll.import("msjava") */
  static native boolean call(int funcptr,String argument);

  int hmod = LoadLibrary("...");
  int funcaddr = GetProcAddress(hmod, "AFunction");
  boolean result = call(funcaddr, "Hello");
  FreeLibrary(hmod);