Skip to main content

Simplify Native Code Access with JNA

November 11, 2009


This article describes the
Java Native Access (JNA) approach to
integrating native libraries with Java programs.
It shows how JNA enables Java code to call native functions without requiring
glue code in another language.
The examples illustrate usage patterns, common pitfalls, and troubleshooting techniques.
The article also enables a comparison of JNA and JNI
Native Interface
) by describing the conversion of
sample JNI code from an earlier article to JNA.

It is useful to know JNA because the

Java APIs
, with their architecture-neutral emphasis, will never support
platform-specific functionality. So, for example, if that killer app you've just
invented needs to play the Windows

"Critical Stop" sound
you'll be stuck as the Windows

function can't be called via the standard APIs.

Though Java itself is architecture-neutral, the example code
used in this article is, perforce, platform-specific.
The code has been developed and tested on a Laptop PC running 32-bit
Microsoft Windows XP
Sun JRE 1.6.0 update 16.
However, the code is quite generic and should run on a range of
Windows and JVM versions. Features new in Java 1.6, Windows 2008, and Windows Vista
have not been used.

JNA Development First Steps

Here are a few things you have to take care of when starting a JNA project:

  • Download jna.jar from the
    JNA project site
    and add it to your project's build path.
    This file is the only JNA resource you need. Remember that
    jna.jar must also be included in the run-time classpath.

  • Find the names of the
    that your Java code will access. The DLL names are required to initialize JNA's


  • Create Java interfaces to represent the DLLs your application will access.
    The sample code accompanying this article contains example
    interfaces for three DLLs:
    user32.dll, and

  • Test linkage of your Java code to the native functions.
    The first example below, "Linkage: What's in a Name?",
    describes the exceptions to expect
    when JNA can't find a DLL or a function in a DLL.

If your project is large or complex, it may be a good idea to complete these steps
in an early phase. If a proof of concept (POC) is required,
consider including a significant portion of JNA interface code in the POC.
This helps to validate assumptions about JNA's suitability for the job, and
reduces overall project risk.

A Proxy for the DLL

JNA uses the
proxy pattern to
hide the complexity of native code integration. It provides a
factory method
that Java programs use to obtain a proxy object for a DLL.
The programs can then invoke the DLL's functions by calling
corresponding methods of the proxy object.
The sequence diagram in Figure 1 below depicts the creation and use of a proxy object.

UML sequence diagram
Figure 1. Creation of a Java proxy object for a DLL

JNA takes care of all run-time aspects, but it requires your help to
create the proxy's Java class.
So the first piece of code you need to create is a Java interface with
method definitions that match the DLL's
C functions.
To play with JNA's run-time correctly, the interface must
extend com.sun.jna.Library.
The code below shows an abbreviated view of a proxy interface for the
user32 DLL.
Note that there should be one such Java interface for each DLL.

package libs;
import com.sun.jna.win32.Library;

public interface User32 extends Library {
    ... (lines deleted for clarity) ...
  boolean LockWorkStation();
  boolean MessageBeep(int uType);
    ... (lines deleted for clarity) ...

Many DLLs, such as those in the
Windows API,
host a large number of functions. But the proxy interface need only contain
declarations for the methods your application actually uses.

Linkage: What's in a Name?

Our first example ( is extremely simple, and locks the
workstation when it is run (same effect as pressing the
Windows logo + L
keys together). It uses the User32 interface shown above to
create a proxy for the Windows
user32 DLL.
It then calls the proxy's LockWorkStation() method -- which
in turn invokes the DLL's

function. The run-time mapping
of the proxy method to the DLL function is handled transparently by JNA --
the user just has to ensure that the method name matches the function name exactly.

import com.sun.jna.Native;  // JNA infrastructure
import libs.User32;  // Proxy interface for user32.dll

public class LockWorkStation {
  public static void main(String[] args) {

    // Create a proxy for user32.dll ...
    User32 user32 = (User32) Native.loadLibrary("user32", User32.class);

    // Invoke "LockWorkStation()" via the proxy ...


To compile and run this program follow the instructions at
"Running the Sample Code" below.

The absence of parameters and a return value in the LockWorkStation()
call eliminates the possibility of any programming errors. But there are still
two things that can go wrong with code as simple as this:

  • loadLibrary() throws a java.lang.UnsatisfiedLinkError
    with the message "Unable to load library ... The specified module could not be found."

    If this error occurs check the spelling of the DLL name, and verify that the DLL is in
    one of the searched directories (check JNA documentation).

  • A proxy method (such as LockWorkStation()) throws a
    java.lang.UnsatisfiedLinkError with the message
    "Error looking up function ... The specified procedure could not be found."

    If this error occurs check the spelling of the function name,
    and verify that the "function" is not actually a
    The Windows API DLLs contain quite a few such macros
    , defined in
    so read the DLL's documentation (and the associated header files) carefully.
    Macro names must be translated manually.

You shouldn't get either of these exceptions when running
But you can simulate these errors just by changing the name of a DLL or a function
and recompiling the code. JNA does, in fact, have mechanisms to allow you to
use a method name (in the proxy interface) that is different from the
function name (in the DLL). More information on this feature can be found
in the JNA documentation.

Parameter and Return Types

Our next example, shown below, uses the Windows
function to literally beep "Hello world" in
Morse code.

import com.sun.jna.Native;  // JNA infrastructure
import libs.Kernel32;  // Proxy interface for kernel32.dll

public class BeepMorse {
  private static Kernel32 kernel32 = (Kernel32)
      Native.loadLibrary("kernel32", Kernel32.class);
  private static void toMorseCode(String letter) throws Exception {
    for (byte b : letter.getBytes()) {
      kernel32.Beep(1200, ((b == '.') ? 50 : 150));

  public static void main(String[] args) throws Exception {
    String helloWorld[][] = {
      {"....", ".", ".-..", ".-..", "---"}, // HELLO
      {".--", "---", ".-.", ".-..", "-.."}  // WORLD
    for (String word[] : helloWorld) {
      for (String letter : word) {
Beep() takes two arguments, frequency and duration,
both of type DWORD which is
as unsigned long. Since an unsigned long occupies
32 bits in all current flavors of Windows, we use a Java int for
both arguments in the proxy interface definition shown below:

package libs;
import com.sun.jna.Library;

public interface Kernel32 extends Library {
  // ... (lines deleted for clarity) ...
  boolean Beep(int frequency, int duration);
  int GetLogicalDrives();
  //  ... (lines deleted for clarity) ...

It is important to deduce the argument types correctly as you can verify
by changing the type of Beep()'s arguments. Changing the definition to
Beep(long, long) or Beep(float, float)
does not cause any run-time error, but you will hear no sound at all.
The JNA web-site has
some information on translating
Windows types to Java types. More details can be found at wikibooks'

Windows Programming/Handles and Data Types
page and Microsoft's

Windows Data Types

To compile and run this program follow the instructions at "Running the Sample Code"
below, but remember to turn the volume down first!

Beep() returns a boolean value, although it is ignored in this example.
But if the value returned by a function has to be used, the return type must be
mapped to a suitable Java type using the same guidelines as for parameter types.
The code below ( illustrates the use of the
int value returned by

in the kernel32 DLL.

import com.sun.jna.Native;
import libs.Kernel32;

public class GetLogicalDrives {

  public static void main(String[] args) {
    Kernel32 kernel32 = (Kernel32)
        Native.loadLibrary("kernel32", Kernel32.class);
    int drives = kernel32.GetLogicalDrives();
    for (int i = 0; i < 32; ++i) {
      int bit = (1 << i);
      if ((drives & bit) == 0)
      System.out.printf("%c:\\%n", (char) ((int) 'A' + i));

Note, however, that in practice a Java program should never have to call
GetLogicalDrives() using JNA as
provides the same information.

To compile and run this program follow the instructions at "Running the Sample Code" below.

The article's introduction mentioned the use of Windows standard sounds for
indicating specific events. These sounds can be produced by calling the

MessageBeep(int type)
function. Example code showing the use of
MessageBeep() can be found in the file

C structs in Java

C Functions often use

s as arguments. But since Java does not have structs,
JNA uses classes instead. Classes are
closely related
to structs, so the associated Java code looks intuitive, and works well.
The following code extracted from, the proxy interface for
kernel32.dll, illustrates the conversion of


into a Java class to support the



import com.sun.jna.Library;
import com.sun.jna.Structure;

public interface Kernel32 extends Library {
  //  ... (other members deleted) ...
  public static class SYSTEMTIME extends Structure {
    public short wYear;
    public short wMonth;
    public short wDayOfWeek;
    public short wDay;
    public short wHour;
    public short wMinute;
    public short wSecond;
    public short wMilliseconds;
  void GetSystemTime(SYSTEMTIME st);
  //  ... (other members deleted) ...

Note that Java classes that substitute C structs must extend JNA's
com.sun.jna.Structure base class.
Embedding these classes inside the proxy interface helps to keep everything
neatly organized in a single file. This is particularly effective when the struct is
only used by functions in the same proxy interface. These classes can, however, also be
defined as standalone public classes (outside the proxy interface) if that is
required or preferred. The JNA web site has more information on these aspects.

The code shown below, in the sample code, illustrates
the use of structs. In this example the called function uses the struct to pass
information "out", but structs can be used to pass information "in" (as in the
function) or "in and out" as well.

import libs.Kernel32;
import libs.Kernel32.SYSTEMTIME;
import com.sun.jna.Native;

public class GetSystemTime {

  public static void main(String[] args) {
    Kernel32 kernel32 = (Kernel32)
        Native.loadLibrary("kernel32", Kernel32.class);
    System.out.printf("Year: %d%n", st.wYear);
    System.out.printf("Month: %d%n", st.wMonth);
    System.out.printf("Day: %d%n", st.wDay);
    System.out.printf("Hour: %d%n", st.wHour);
    System.out.printf("Minute: %d%n", st.wMinute);
    System.out.printf("Second: %d%n", st.wSecond);

To compile and run this program follow the instructions at "Running the Sample Code" below.

It is important to deduce the type of each member of a converted struct correctly.
Erring here usually has catastrophic consequences that you can sample by changing the
types in SYSTEMTIME. There are other JNA tweaks that can
be applied to specify whether a struct should be
passed by reference
(the default) or
by value, and also
how a struct embedded within another should be stored.
The JNA web-site has much guidance on these aspects.
The section titled "Converting from JNI to JNA" below has several examples of
the conversion of C structs to Java classes.

No discussion of struct portability across languages is complete without
also considering
requirements. Since this part of the article is dedicated
to JNA basics we defer discussion of alignment requirements to a later
section "Converting from JNI to JNA".

Pointers and Strings

Using pointers is a perfectly natural thing to do in C, C++, and certain
other languages.
But the use of pointers also proliferated certain errors and programming
malpractices that Java's inventors wanted to prevent.
So, although Java programs have an uncanny resemblance to C++ code,

Java has no pointers
. But pointers of one kind or another are
commonly used as parameters in native functions, so JNA programs
must be creative in working around this limitation.

The following example ( exploits a
language feature from Java's C heritage:

an array reference is a pointer to the array's first element

import libs.Kernel32;
import com.sun.jna.Native;

public class GetVolumeInformation {

  private static String b2s(byte b[]) {
    // Converts C string to Java String
    int len = 0;
    while (b[len] != 0)
    return new String(b, 0, len);

  public static void main(String[] args) {
    Kernel32 kernel32 = (Kernel32) Native.loadLibrary(
        "kernel32", Kernel32.class);
    int drives = kernel32.GetLogicalDrives();
    for (int i = 0; i < 32; ++i) {
      if ((drives & (1 << i)) == 0)
      String path = String.format("%c:\", (char) ((int) 'A' + i));
      byte volName[] = new byte[256], fsName[] = new byte[256];
      int volSerNbr[] = new int[1], maxCompLen[] = new int[1], fileSysFlags[] = new int[1];
      boolean ok = kernel32.GetVolumeInformationA(path, volName,
          256, volSerNbr, maxCompLen, fileSysFlags, fsName, 256);
      if (ok)
        System.out.printf("%s %08X '%s' %s %08X%n", path, volSerNbr[0],
            b2s(volName), b2s(fsName), fileSysFlags[0]);
        System.out.printf("%s (Offline)%n", path);

states that its
4th thru 6th arguments (highlighted above) are of type
LPDWORD which translates to "pointer to int".
We circumvent Java's lack of pointers by using int arrays for
these arguments instead. So in the proxy's method declaration these arguments
are defined to be of type int[], and at run-time (see
code above) we pass int arrays of one element. The values
returned by GetVolumeInformation() are left in the single
int that populates each array.

The output from this program is shown below.
On my computer D: is a CD-ROM drive that was not loaded at the time this
output was captured. The device at G: was a
USB flash drive.

C:\ 609260D7 'My-C-Drive' NTFS 000700FF
D:\ (Offline)
E:\ C8BCF084 'My-E-Drive' NTFS 000700FF
G:\ 634BE81B 'SDG-4GB-DRV' FAT32 00000006

To compile and run this program follow the instructions at "Running the Sample Code" below.

Another thing to notice in the above code is the way strings are passed to and
from native code. Java Strings can be passed "in" to the native code
without special effort (check variable path in code above). But
null-terminated strings
passed "out" to Java require careful handling.
Check the use of the variables volName
and fsName, and the method b2s(byte b[]) in the code above.
Finally, note that

is a macro whose "real" name
is GetVolumeInformationA(). Read the function's
specification for all the details.

Another approach to pointers in Java is based on the classes in the
package com.sun.jna.ptr and the class com.sun.jna.Pointer.
Examples of the use of these classes can be found in the code discussed under
"Converting from JNI to JNA" below.

Converting from JNI to JNA

Having covered the basics, it's now time to pit your wits against something more
substantial. The rest of this article describes issues faced in converting an
existing application (based on JNI) to JNA, Reviewing the converted code
(included with the sample code) should provide greater insight into how JNA
can be used to handle the complexities of a "real" application.
The JNI code used comes from the article

"Java Tech: Acquire Images with TWAIN and SANE, Part 1"
, which describes how the
TWAIN library is used
to obtain images from scanners webcams, and other imaging devices.

To run the TWAIN code you should ideally have a TWAIN device
(scanner, webcam, etc.) connected to your computer.
But if your computer does not have a TWAIN device,
you should download and install the
TWAIN Developer Toolkit
which contains a program that simulates an image source.
To understand the code you should also have the
TWAIN header file available.

To run the TWAIN demo program execute JTwainDemo.bat as described at
"Running the Sample Code" below.
To understand the overall flow of the program, follow the instructions starting
Let There Be TWAIN
in the original JNI article.

Figure 2 below depicts the changes that have been made to the sample code
from the JNI article.

Sample code structure
Figure 2. Changes to "" from the JNI article

jtwain.cpp and twain.h have been deleted as
they contained only JNI-specific code. has been deleted as
it was unrelated to TWAIN or JNI. has been modified to
contain a JNA implementation of the TWAIN functionality instead of the original
JNA code.
The package libs is new. Its three files (,, and are the proxy
interfaces discussed in this article.
The remaining 3 files stay unchanged. Observe that the package democode,
containing the simple example programs described above, is not shown in Figure 2.

Converting the TWAIN code to JNA provides the usual learning experiences of any
non-trivial project. But it also throws up a rare and elusive type of bug --
struct memory alignment error -- that is unique to Java projects using native-code.
Since memory alignment errors are difficult to detect, and they
may also be new to many Java users, the following sections provide a detailed guide
to handling these errors.

Detecting a Struct Memory Alignment Problem

The devil is in the details here, so there can no simple, non-intrusive, way of
concluding that a particular bug is caused by a memory alignment mismatch.
But the following, necessarily tedious, discussion describes one approach.
The affected code (shown below) is in,
and can be located by searching for "Memory Alignment Problem Demo".
The code creates an instance of TW_IDENTITY (a Java substitute
for a struct), and passes it to the TWAIN run-time. TWAIN then interacts with the
user to select a source device. The TW_IDENTITY instance is
uninitialized when passed from Java to TWAIN, but is returned populated with
information about the selected device. The printf()s, and the
dump() at the end of the code display parts of the struct
to help in detecting the problem.

// BEGIN: Memory Alignment Problem Demo
stat = SelectSource(g_AppID, srcID);
if (stat != TWRC_SUCCESS) {
  //... (lines deleted for clarity) ...
System.out.printf("ProtocolMajor: %02x%n", srcID.ProtocolMajor);
System.out.printf("ProtocolMinor: %02x%n", srcID.ProtocolMinor);
System.out.printf("SupportedGroups: %04x%n", srcID.SupportedGroups);
System.out.printf("Manufacturer: %s%n", new String(srcID.Manufacturer, 0, 34));
// END: Memory Alignment Problem Demo

The output from the printf() statements shown below give
a strong hint that a memory alignment problem exists:

ProtocolMajor: 01
ProtocolMinor: 09
SupportedGroups: 694d0000
Manufacturer: crosoft                         Tw

The first two values, ProtocolMajor and ProtocolMinor, are
correct but the next two are certainly corrupted. In a previous TWAIN call, the Java code
negotiated the value 0x0003 for SupportedGroups, so that same value
should have been returned. Also the value of Manufacturer certainly
looks like "Microsoft" with the first two characters lopped off.

Now let's look at the output from dump() shown below.
The "dump" displays the contents of the struct
as received from the native code, before separation by JNA into individual
member values.

000:  11 04 00 00 01 00 00 00 0d 00 01 00 32 36 20 4a 
000:  .  .  .  . .  . .  . .  . .  . 2  6     J

016:  75 6e 65 20 32 30 30 30 00 00 00 00 00 00 00 00
016:  u  n  e     2  0  0  0  .  .  .  .  .  .  .  .

032:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00
032:  .  .  .  .  .  .  .  .  .  .  .  .  .  . .  .

048:  09 00 03 00 00 00 4d 69 63 72 6f 73 6f 66 74 00
048:  .  . .  .  .  . M  i  c  r  o  s  o  f  t  .

064:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
064:  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

080:  00 00 00 00 00 00 00 00 54 77 61 69 6e 20 44 61
080:  .  .  .  .  .  .  .  . T  w  a  i  n     D  a
         ... (other lines deleted for clarity) ...

Each line of the dump displays the values of 16 bytes of "raw" memory.
The number at the beginning of each line (before the colon) is the line's
offset from the start of the struct. Each set of 16 bytes is printed twice
-- first as hexadecimal integers, and then as
ASCII characters.
The colors (assigned manually) serve to delimit adjacent members of the struct,
and the underlined part is the struct TW_VERSION embedded within
struct TW_IDENTITY (see
The location and extent of each member in the struct's memory space
is determined from the declaration order and size of each member.

Looking at the dump above, it is obvious that the information returned by the native code
is correct (remember that the PC's Intel processor is
little endian). Specifically,
the values of SupportedGroups and Manufacturer are also correct
in the dump:

  • ProtocolMajor (the 2 magenta bytes at offset 46) = 0x01
  • ProtocolMinor (the 2 cyan bytes at offset 48) = 0x09
  • SupportedGroups (the 4 magenta bytes at offset 50) = 0x0003
  • Manufacturer (the 34 cyan bytes at offset 54) = "Microsoft"
    (padded out to 34 bytes with 0-valued bytes)

Comparison of the values from the printf() statements and those
in the dump shows that JNA's sense of struct-member location has, mysteriously,
slipped by 2 bytes starting at SupportedGroups. This is the classic
symptom of a memory alignment issue.

The alignment error occurs because the native code strings together the values of
the struct's members without any intervening gaps, whereas the JNA code
expects to find them at memory offsets that are multiples of the member's length.
Thus, the native code places SupportedGroups at offset 50,
but JNA looks for it at offset 52 (a multiple of 4, the size of
SupportedGroups). The struct members following
SupportedGroups also get pushed back by 2 bytes, leading to the
corruption of Manufacturer's value shown above. You should now also
be able to explain how the "Tw" creeps in at the end of Manufacturer's value.

Finally, a short digression on another aspect of pointers: the code of
dump() shows how Structure.getPointer() can be used to
get a pointer to the beginning of a struct. The com.sun.jna.Pointer
object returned by getPointer() can be used to access
the struct as an array of bytes (a C programmer's void*).

Reproducing the Struct Alignment Error

The file actually contains the code with the
memory alignment error so that readers may explore this further if they wish. But
the TWAIN demo program still works correctly as it does not use the values in the struct.

To reproduce the memory alignment error compile the program as described at
"Running the Sample Code" below, then execute JTwainDemo.bat.
You should see the window titled "JTwain Demo" in Figure 3 below. At the menu bar
select "File" -> "Select Source..." as shown in the figure. The window titled
"Select Source" will pop up with a list of the installed TWAIN devices.
Choose any TWAIN device, and click the button labelled "Select".
This executes the code with the alignment error, and displays the
contents of the struct TW_VERSION in the command window.

Program output
Figure 3. Running JTwainDemo

Note that the struct TW_VERSION contents you see will likely differ
from the example values shown above (unless you have the same TWAIN device installed).
But you should be able to see the same kind of evidence of a memory alignment problem.

If the pop-up window titled "Select Source" displays no TWAIN devices,
you should download and install the
TWAIN developer toolkit.
The toolkit simulates an image source (the first entry in the
"Select Source" window in Figure 3 above) that returns an image of the TWAIN logo.

Preventing Struct Alignment Errors

Native libraries come in various memory alignment flavors (because of
differences between compilers and compiler options). So, since JNA is
typically used in situations where re-compiling the native code is not an option,
it has facilities for setting the alignment strategy used.

The alignment strategy for members of a Java class that extend Structure
can be set by invoking Structure.setAlignType(int alignType) method. There are
four options for alignment type as described in the table below.

Alignment Specification JNA Description
ALIGN_DEFAULT Use the platform default alignment.
ALIGN_GNUC validated for 32-bit x86 linux/gcc; align field size, max 4 bytes
ALIGN_MSVC validated for w32/msvc; align on field size
ALIGN_NONE No alignment, place all fields on nearest 1-byte boundary

The output from dump() shown above makes it clear that the TWAIN native code
uses no particular alignment strategy (ALIGN_NONE in the table
above). But since this is not also JNA's default setting, all of the Java classes
that substitute C structs have a default constructor that sets alignment type to
ALIGN_NONE (see The following code is an
abbreviated view of the Java class for struct TW_IDENTITY with the
default constructor.

public class TW_IDENTITY extends Structure {
  public TW_IDENTITY() {
  public int Id;
  public TW_VERSION Version = new TW_VERSION();
  public short ProtocolMajor;
  public short ProtocolMinor;
    . . .

In general, there is no way of knowing the alignment strategy used by any particular
native library. So, if a DLL's documentation does not specify this information some
experimentation will be required to determine the correct alignment setting to use.

Running the Sample Code

To run the sample code described in this article proceed as follows:

  • Download the zip containing the sample code,
    and extract it into a directory (say, samples)
  • Open a command window, and use the "CD" command to navigate to the
    samples\code directory.
  • Execute the batch file build.bat. This compiles all of the code
    (and is required to be run just once). The class files are located in a
    directory called samples\bin.
  • To run a program execute the batch file with the same name
    (e.g. LockWorkStation.bat, BeepMorse.bat, GetLogicalDrives.bat,
    GetSystemTime.bat, GetVolumeInformation.bat, or

The samples zip contains jna.jar, so you
don't have to download anything else. The batch files listed above also have the classpath
specified, so you don't have to change anything to compile and run the sample code.


width="1" height="1" border="0" alt=" " />
Sanjay Dasgupta has been using Java for telecom applications since 1996 (after many years of using many different languages in many industries).
Related Topics >> Programming   |   Featured Article   |   


I am developing a java

I am developing a java application where I want to call Third party DLL functions Then How to use JNA for such application. Please help me

There are no special steps to

There are no special steps to follow for third-party DLLs. Just ensure that the DLL is in a directory where the JNA application can find it. The JNA web-site has more details on this aspect.

Your Kernel32 interface (or

Your Kernel32 interface (or most other w32 mappings) should use StdCallLibrary, not Library, to ensure that the proper calling convention is used. There is a sample Kernel32 implementation included in JNA's examples, so there should be no confusion.

Thanks for the insight. That

Thanks for the insight. That will help users to code correctly with JNA.

&nbsp;I testing with jna code but in case feeder (ADF) not ...

I testing with jna code but in case feeder (ADF) not feed next paper,it stop after feed first paper I want to feed all paper please help me for setup.