|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 2 of 5
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.
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.
// 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);
}
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.
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.
// 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.
jna.jar and examples.jar from the JNA downloads page.
Archived Discussions (Read only)