Menu Zamknij

Invoking an external native DLL from Java application

Introduction

Many functionalities in today’s applications are delivered in a form of libraries. Thanks to that, programmers don’t need to write whole program from scratch.  They can combine different, already prepared parts of compiled code in bigger application instead. That of course shortens time and lowers the effort needed to prepare an application.  Windows operating system delivers lots of functionalities in shared libraries. In this post I show how to access them from Java application.

Short history of libraries

Since first computers appeared on the market, programmers started to think how to simplify their job. Quickly after first programs had been written, it occurred that those programs have some common functionalities. For example all accounting applications perform the same math operations. If one could take those common parts out and put into a new application, that would very much speed up the process of making new programs. The solution to that challenge was to use functions and procedures. Both represent a part of the application that can be reused in another one. The programmer that developed such part can share it to other programmers. They get fully functional and tested code, and they don’t have to create it from scratch. That saves time, effort and money needed to make new software. To ensure that programmer who got function or procedure can use it in a consistent way (predicted by the author) there had to emerge a standard way of describing its attributes. There were defined 4 basic elements of description of a function or procedure:

    • name,
    • list of input parameters,
    • list of output values (for functions),
    • description what the function or procedure does.

Description what the function or procedure does is rather for humans than for computers so they understand when to use which. In effect developers started to treat name, input parameters and return values as basic attributes that are needed to effectively use delivered function (or procedure). It also occurred that there is rarely a need to distribute single function or procedure. It was a common requirement to distribute a set of those. For instance, if one person developed mathematical function (like a sum) and another wants to use it, there is high possibility that the other person also needs another mathematical functions. Hence, the concept of library of functions and procedures has emerged. From that moment, programmers started to distribute fully functional parts of programs grouped in sets called libraries, and others could use those libraries in their applications. There are two ways of using a library in application.

Statically linked libraries

Initial concept was to distribute library in a form of compiled files (object files). Such libraries are called „static link libraries” and need to be linked into the application right after compilation phase. In the effect of linking process, libraries become inseparable part of the application. Library’s compiled code is actually copied directly in the compiled executable. The resulting executable file has all the instruction, both from the developer’s code and libraries, inside itself.

Shared libraries (also called dynamically linked libraries)

Another approach is to prepare application with assumption that required libraries will be available on the computer on witch the application is to be executed. That is how dynamic link libraries work. In spite of being copied into the the application, they are attached during run time. The end user of the application should be aware of that there is a set of libraries that are required by the application. That information usually comes in installation manual (e.g. DirectX or OpenGL for games). The libraries will be attached during application startup by the operating system. To do so, the OS need to know how to read information about functions and procedures delivered by each library. In the next paragraph I show basics of accessing functions in native shared library from Java code. Those libraries also called dynamic linked library and have .dll extension in Windows environment.

Invoking functions from DLL libraries in Java application

In Java there as a library called JNA (Java Native Access – https://github.com/java-native-access/jna) that makes accessing native DLLs quite easy. As it was mentioned earlier, it should be enough to use name, list of input parameters and return value to effectively invoke a function. Let’s see how it works with JNA. We will prepare a simple application that finds window title of running Eclipse IDE. Firstly, we need to import required packets.

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.win32.StdCallLibrary;

Then, we need to define an interface that will be a facade to the the DLL. That interface has to extend StdCallLibrary. We don’t have to define all methods in the interface that are available in DLL. In our application we want to read windows titles. For that we have to use two functions delivered by user32.dll:

    • EnumWindows – enumerates over windows created in the system,
    • GetWindowsTextA – getting window title.

In result, the interface may look as follows:

public interface User32 extends StdCallLibrary {

    User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
       
    WinDef.BOOL EnumWindows(WinUser.WNDENUMPROC enumFunc, Pointer arg);
        
    int GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount);
}

First field of the interface loads DLL library. Pay attention to the fact that name of the library is provided without extension. Having the User32 interface defined, we can now prepare the main class. We can name it WinApiWrapper.

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinUser.WNDENUMPROC;

public class WinApiWrapper {

	private final User32 user32;
	
	public WinApiWrapper() {
        	user32 = User32.INSTANCE;
    	}

	public void run () {
		user32.EnumWindows(new WNDENUMPROC() {
	         
	        public boolean callback(HWND hWnd, Pointer arg1) {
	            byte[] windowTitleBuffer = new byte[512];
	            user32.GetWindowTextA(hWnd, windowTitleBuffer, 512);
	            String windowTitle = Native.toString(windowTitleBuffer);

	            if (!"".equals(windowTitle) && windowTitle.contains("Eclipse IDE"))
	            	System.out.println("Found window with title: " + windowTitle + " (" + hWnd + ")");
	            return true;
	         }
	      }, null);
	}
	
	public static void main(String[] args) {
		WinApiWrapper winApi = new WinApiWrapper();
		winApi.run();
	}

}

For the above example to work, both class and the interface have to be defined in the same package. The class constructor sets user32 variable that gives access to methods from the User32 interface. We can then work on those methods in the same way as on any other Java method.

After running the application, the result is as follows:

If you want to practice on your own, one hint from my side. Passing arguments and getting results from methods invoked from DLL libraries may require additional memory management. You have to manage memory associated with variables by yourself (see how the callback in the run method does it). Otherwise, you will get memory run-time errors.

Happy coding.