Open source Java projects: Java Native Access

An easier way to access native code

1 2 3 4 5 Page 2
Page 2 of 5

Get local time

If you look under "How To Get Started Using JNA" on the Java Native Access homepage you will see a simple JNA usage example based on the Windows GetSystemTime() API function. The example focuses only on the essentials of JNA, and so it is somewhat incomplete. I'll start this introduction to JNA with a more complete Windows-based example that builds on that one.

This first example is based on the Windows GetLocalTime() API function, which returns the current local time and date. Unlike GetSystemTime(), which returns time/date information expressed in Coordinated Universal Time (UTC), GetLocalTime() returns time/date information expressed according to the current time zone.

Before using JNA to access GetLocalTime() from a Java program, you need to know the name (and possibly location) of this function's Windows Dynamic Link Library (DLL). As it turns out, GetLocalTime() is located in the same DLL as GetSystemTime(), which happens to be kernel32.dll. You also need to know the C-based declaration for GetLocalTime(). The declaration is shown in Listing 1.

Listing 1. The C-based declaration for GetLocalTime()

typedef struct
{
   WORD wYear;
   WORD wMonth;
   WORD wDayOfWeek;
   WORD wDay;
   WORD wHour;
   WORD wMinute;
   WORD wSecond;
   WORD wMilliseconds;
}
SYSTEMTIME, *LPSYSTEMTIME;

VOID GetLocalTime(LPSYSTEMTIME lpst);

The C-based declaration reveals the number and types of arguments passed to the function. In this example, there is only one argument -- a pointer to the Windows SYSTEMTIME structure. Furthermore, each structure member's type happens to be a 16-bit unsigned integer. Using this information, you can create an interface that fully describes GetLocalTime(), as shown in Listing 2.

Listing 2. Kernel32.java

// Kernel32.java

import com.sun.jna.*;
import com.sun.jna.win32.*;

public interface Kernel32 extends StdCallLibrary
{
   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 GetLocalTime (SYSTEMTIME result);
}

The Kernel32 interface

Because JNA requires a library's functions to be declared via an interface, Listing 2 reveals an interface that declares GetLocalTime(). According to convention, I named the interface Kernel32 because GetLocalTime() is located in the Windows kernel32.dll library.

A type-mapping problem
JNA's mapping of a Windows/C language unsigned integer type to a Java signed integer type could be problematic when comparing an API function's returned integer value to another integer value. If you are not careful when making the comparison, the wrong execution path could be taken in a decision statement. This is due to forgetting that any value whose most significant bit is set, is interpreted as positive from the unsigned integer perspective, and negative from the signed integer perspective.

The interface must extend the com.sun.jna.Library interface. Because Windows API functions adhere to the stdcall calling convention, the interface for declaring Windows API functions extends the com.sun.jna.win32.StdCallLibrary interface. This latter interface extends Library and com.sun.jna.win32.StdCall.

Earlier, you learned that GetLocalTime() requires a pointer to a SYSTEMTIME structure as its only argument. Because Java does not support pointers, JNA's alternative is to declare a structure class as a subclass of com.sun.jna.Structure. According to this abstract class's Javadoc, Structure corresponds to a C struct * in a parameter context.

The field members within the SYSTEMTIME class declaration are in the same order as those in the equivalent C struct. Keeping the field order consistent is important. For example, I discovered that swapping the order of wYear and wMonth resulted in the year being placed in wMonth and the month being placed in wYear.

Each field member has Java's short integer type. According to the "Default Type Mappings" section of the JNA homepage, this is the appropriate type to use. However, keep in mind this important difference: the Windows WORD type maps to C's 16-bit unsigned short integer type, whereas Java's short integer type is a 16-bit signed integer.

Access the local time with Kernel32

The GetSystemTime() example on the JNA homepage reveals that you must allocate an instance of the native library using the previously declared interface. You can accomplish this task via the com.sun.jna.Native class's public static Object loadLibrary(String name, Class interfaceClass) method, as shown in Listing 3.

Listing 3. LocalTime.java

// LocalTime.java

import com.sun.jna.*;

public class LocalTime
{
   public static void main (String [] args)
   {
      Kernel32 lib = (Kernel32) Native.loadLibrary ("kernel32",
                                                    Kernel32.class);
      Kernel32.SYSTEMTIME time = new Kernel32.SYSTEMTIME ();
      lib.GetLocalTime (time);
      System.out.println ("Year is "+time.wYear);
      System.out.println ("Month is "+time.wMonth);
      System.out.println ("Day of Week is "+time.wDayOfWeek);
      System.out.println ("Day is "+time.wDay);
      System.out.println ("Hour is "+time.wHour);
      System.out.println ("Minute is "+time.wMinute);
      System.out.println ("Second is "+time.wSecond);
      System.out.println ("Milliseconds are "+time.wMilliseconds);
   }
}

Listing 3 executes Kernel32 lib = (Kernel32) Native.loadLibrary ("kernel32", Kernel32.class) to allocate a Kernel32 instance and load kernel32.dll. A path to this library is not needed because kernel32.dll is a standard Windows DLL. However, if the DLL could not be found, loadLibrary() would throw an UnsatisfiedLinkError.

Kernel32.SYSTEMTIME time = new Kernel32.SYSTEMTIME (); creates a SYSTEMTIME structure instance. This instantiation is immediately followed by lib.GetLocalTime (time);, which populates this instance with local time/date values, and several System.out.println() calls that output these values.

1 2 3 4 5 Page 2
Page 2 of 5