Tuesday, July 3, 2012

NetBeans and Java Native Access

Accessing a native interface from Java is useful for a wide variety of reasons. The most common way to do this would be through the use of JNI. While it worked well, it did feel a little fiddly and heavy to get the job done. That was until the Java Native Access (JNA) platform came along. It does alot of the heavy lifting for you, allowing you to call native methods without doing any C/C++ development (unless you are writing your own dynamic library).

Below you can find my version of "HelloWorld" for JNA. This example calls the MessageBoxA function which is an export within User32.dll.

Firstly, create an interface for the native function:


1
2
3
4
5
6
7
8
package mywindows.java; 
       
import com.sun.jna.Library; 
       
public interface MyUser32 extends Library 
{ 
      public int MessageBoxA(int handle, String message, String title, int type);
}   

Then the invocation is straightforward:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package jnaworld;

import com.sun.jna.Native;
import mywindows.java.MyUser32;

public class JNAWorld {

    static {
        if (System.getProperty("jna.nosys") == null) {
            System.out.println("[*] Set new system property");
            System.setProperty("jna.nosys", "true");
        }
    }

    public static void main(String[] args) {

        String mytext = "Hello World!";
        String mytitle = "Title bar";

        String libName = "c";
        if (System.getProperty("os.name").contains("Windows")) {
            libName = "user32"; //loading user32.dll on the system
        }

        // Loading dynamically the library
        MyUser32 user32 = (MyUser32) Native.loadLibrary(libName, MyUser32.class);
        user32.MessageBoxA(0, mytext, mytitle, 0);
    }
}


Note: The code included in the static initializer may not be needed. I have included it in this example incase people are doing their development from NetBeans. As NetBeans ships with a version of JNA you will want to ensure that the jar file that is used is the one you intend to ship with. If you include the static initializer it will prevent you running into the following error that you would otherwise encounter:


Exception in thread "main" java.lang.Error: 

There is an incompatible JNA native library installed on this system.
To resolve this issue you may do one of the following:
 - remove or uninstall the offending library
 - set the system property jna.nosys=true
 - set jna.boot.library.path to include the path to the version of the 
   jnidispatch library included with the JNA jar file you are using

2 comments:

Laurent Marot said...

Hi Adam,

Do you you thing I could do the same invocating C function packaged in a public C API trough JNA

onur olce said...

Hi Adam,
how we can use a C# DLL file in Java through JNA ?
can you make a sample about it too?