jna.boot.library.path
. If that fails and jna.nosys=false
is set, it will fall back to loading from the system library paths. Finally it
will attempt to extract the stub library from from the JNA jar file, and load it.
The jna.boot.library.path
property is mainly to support
jna.jar being included in -Xbootclasspath, where
java.library.path
and LD_LIBRARY_PATH are ignored. It is also
useful for designating a version of the library to use in preference to any
which may already be installed on the system.
Loading from the system may be enabled by jna.nosys=false
,
and unpacking from the jar file may be disabled by
jna.nounpack=true
.
The library name used to search for JNA's native library may be altered
by setting jna.boot.library.name
, which defaults to
"jnidispatch". It may be useful to set this value if your system
requires unique names for shared libraries (rather than unique paths),
or if your system must store different versions of the JNA shared
library (e.g. for different architectures) in the same directory.
Top
// Alternative 1: interface-mapped class, dynamically load the C library
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)Native.load("c", CLibrary.class);
}
// Alternative 2: direct-mapped class (uses a concrete class rather than an
// interface, with a slight variation in method
// declarations).
public class CLibrary {
static {
Native.register("c");
}
}
The String
passed to the
{@link com.sun.jna.Native#load(String,Class)}
(or {@link com.sun.jna.NativeLibrary#getInstance(String)}) method
is the undecorated name of the shared library file. Here are some examples of
library name mappings.
OS | Library Name | String |
---|---|---|
Windows | user32.dll | user32 |
Linux | libX11.so | X11 |
Mac OS X | libm.dylib | m |
Mac OS X Framework | /System/Library/Frameworks/Carbon.framework/Carbon | Carbon |
Any Platform | <current process> | null |
Any given native library with a unique filesystem path is represented by a single instance of {@link com.sun.jna.NativeLibrary} and obtained via {@link com.sun.jna.NativeLibrary#getInstance(String)}. The native library will be unloaded when no longer referenced by any Java code.
If the library name is null
, your mappings will apply to the
current process instead of a separately loaded library. This may help avoid
conflicts if there are several incompatible versions of a library available.
The search path for loaded native libraries may be modified by
setting jna.library.path
and a few other properties. You may
also bundle native libraries in a jar file and have JNA automatically extract
them for loading. See {@link com.sun.jna.NativeLibrary} for details.
public interface CLibrary extends Library {
int atol(String s);
}
Alternatively, you can map directly to a declared native method
(with some restrictions):
public class CLibrary {
public static native int atol(String s);
}
If you prefer to rename the Java methods to conform to Java coding conventions, then you can provide an entry ({@link com.sun.jna.Library#OPTION_FUNCTION_MAPPER}/{@link com.sun.jna.FunctionMapper}) in the options {@link java.util.Map} passed to {@link com.sun.jna.Native#load(String,Class,java.util.Map) Native.load()} which maps the Java names to the native names. While this keeps your Java code a little cleaner, the additional mapping of names may make it a little less obvious the native functions being called.An instance of the {@link com.sun.jna.Function} class is obtained through the {@link com.sun.jna.NativeLibrary} instance corresponding to the containing native library. This {@link com.sun.jna.Function} instance handles argument marshalling and delegation to the native function.
C Type | Native Representation | Java Type |
---|---|---|
char | 8-bit integer | byte |
wchar_t | platform-dependent | char |
short | 16-bit integer | short |
int | 32-bit integer | int |
int | boolean flag | boolean |
enum | enumeration type | int (usually) |
long long, __int64 | 64-bit integer | long |
float | 32-bit floating point | float |
double | 64-bit floating point | double |
pointer (e.g. void*) | platform-dependent (32- or 64-bit pointer to memory) | {@link java.nio.Buffer} {@link com.sun.jna.Pointer} |
pointer (e.g. void*), array | 32- or 64-bit pointer to memory (argument/return) contiguous memory (struct member) | <P>[] (array of primitive type) |
In addition to the above types, which are supported at the native layer, the JNA Java library automatically handles the following types. All but NativeMapped and NativeLong are converted to {@link com.sun.jna.Pointer} before being passed to the native layer. | ||
long | platform-dependent (32- or 64-bit integer) | {@link com.sun.jna.NativeLong} |
const char* | NUL-terminated array (native encoding or jna.encoding ) | {@link java.lang.String} |
const wchar_t* | NUL-terminated array (unicode) | {@link com.sun.jna.WString} |
char** | NULL-terminated array of C strings | {@link java.lang.String String[]} |
wchar_t** | NULL-terminated array of wide C strings | {@link com.sun.jna.WString WString[]} |
void** | NULL-terminated array of pointers | {@link com.sun.jna.Pointer Pointer[]} |
struct* struct | pointer to struct (argument or return) ({@link com.sun.jna.Structure.ByReference or explicitly}) struct by value (member of struct) ({@link com.sun.jna.Structure.ByValue or explicitly}) | {@link com.sun.jna.Structure} |
union | same as Structure | {@link com.sun.jna.Union} |
struct[] | array of structs, contiguous in memory | {@link com.sun.jna.Structure Structure[]} |
void (*FP)() | function pointer (Java or native) | {@link com.sun.jna.Callback} |
pointer (<T> *) | same as Pointer | {@link com.sun.jna.PointerType} |
other | integer type | {@link com.sun.jna.IntegerType} |
other | custom mapping, depends on definition | {@link com.sun.jna.NativeMapped} |
NOTES
Structure
and Union
are not converted to Pointer
when passed by value.
To map a native multi-dimensional array, use a single-dimensional Java array with a number of elements equivalent to the full native array, e.g.
// Original C code
#define DIM0 2
#define DIM1 3
int array[DIM0][DIM1];
int i,j;
for (i=0;i < DIM0;i++) {
for (j=0;j < DIM1;j++) {
array[i][j] = i*DIM1 + j;
}
}
// Equivalent JNA code
final int DIM0 = 2;
final int DIM1 = 3;
int[] array = new int[6];
for (int i=0;i < DIM0;i++) {
for (int j=0;j < DIM1;j++) {
array[i*DIM1 + j] = i*DIM1 + j;
}
}
Type-safe pointers may be defined by deriving from the {@link com.sun.jna.PointerType} class. Any such user-defined type will be treated the same as a {@link com.sun.jna.Pointer}.
String
s perform the same function as the native types
const char*
and const wchar_t*
(NUL
-terminated arrays). In order to use the proper type when
calling a native function, we have to introduce some sort of annotation to
identify how the java String
should be converted.
Java String
s are normally converted to char*
since this is the most common usage of strings. Strings are automatically
converted to a NUL
-terminated array of char
across
the function call. Returned char*
values are automatically
copied into a String
if the method signature returns
String
(strdup
, for example).
If the native method returns char* and actually allocates memory, a return type of {@link com.sun.jna.Pointer} should be used to avoid leaking the memory. It is then up to you to take the necessary steps to free the allocated memory.
When converting Java unicode characters into an array of char
,
the default platform encoding is used, unless the system property
jna.encoding
is set to a valid encoding. This property may be
set to "UTF8", for example, to ensure all native strings use that encoding.
Arrays of String
passed to native code (either as a function argument or callback return value) will be converted into a NULL-terminated array of char*
(or wchar_t*
in the case of an array of WString
.
char
array to a native wchar_t
array.
A native method cannot return a Java array, since there is no canonical way to indicate the intended length of the returned array. Instead, use one of the array access methods in the Pointer class, supplying the length of the returned array.
{@link java.nio.Buffer}s may also be used as a memory buffer input argument; direct byte buffers can often provide much improved performance over primitive arrays. A pointer provided by native code may be converted to a {@link java.nio.Buffer} by calling {@link com.sun.jna.Pointer#getByteBuffer}.
If you need to pass in a subset of a primitive array, you can do so by wrapping it in a {@link java.nio.Buffer} subclass, such as {@link java.nio.ByteBuffer}, using the {@link java.nio.ByteBuffer#wrap(byte[],int,int)} method. Wrapping an array in a buffer also allows you to pass only a subset of a Java array to the native function.
callback
method with a signature that matches the
function pointer required by the native code. The name of the method
may be something other than "callback" only if there is only a single method
in the interface which extends Callback or the class which implements
{@link com.sun.jna.Callback}. The arguments and return value follow the same
rules as for a direct function invocation.
When accessing Windows APIs, sometimes the documentation indicates that a
function pointer parameter must refer to a function that resides in a
DLL. In these instances, add the {@link com.sun.jna.win32.DLLCallback}
interface to your callback definition. The function pointer as seen by
Windows will be located in the jnidispatch.dll
module.
If the callback returns a String
or String[]
, the
returned memory will be valid until the returned object is GC'd.
If your native code initializes function pointers within a struct, JNA will
automatically generate a Callback
instance matching the declared
type. This enables you to easily call the function supplied by native code
using proper Java syntax.
// Original C code
struct _functions {
int (*open)(const char*,int);
int (*close)(int);
};
// Equivalent JNA mapping
public class Functions extends Structure {
public static interface OpenFunc extends Callback {
int invoke(String name, int options);
}
public static interface CloseFunc extends Callback {
int invoke(int fd);
}
public OpenFunc open;
public CloseFunc close;
}
...
Functions funcs = new Functions();
lib.init(funcs);
int fd = funcs.open.invoke("myfile", 0);
funcs.close.invoke(fd);
Callbacks may also be used as return values. Native function pointers are wrapped in a proxy implementing the declared Callback type, to facilitate calling from Java.
// Original C code
typedef void (*sig_t)(int);
sig_t signal(int signal, sig_t sigfunc);
// Equivalent JNA mapping
public interface CLibrary extends Library {
public interface SignalFunction extends Callback {
void invoke(int signal);
}
SignalFunction signal(int signal, SignalFunction func);
}
If you need control over the thread context in which a Callback
operates, you can install a {@link com.sun.jna.CallbackThreadInitializer} for
any given callback object. The first time the callback is called on a thread
that is not currently attached to the VM, the initializer will be queried to
determine how the thread should be set up. You can indicate the desired name,
thread group, and daemon state for the thread, as well as indicating whether
the thread should be left attached to the VM after callback exit. The latter
improves performance if you know you will be getting multiple callbacks on the
same thread, avoiding the need for the VM to generate multiple Java Thread
objects for the same native thread. If you do leave the native thread
attached, you should either ensure you detach it at some later point (by
calling {@link com.sun.jna.Native#detach} from within the callback just prior
to return) or return true from your
{@link com.sun.jna.CallbackThreadInitializer#isDaemon(Callback)} method so
that the native thread will not prevent the VM from exiting.
If you don't need to otherwise customize the callback thread, you can simply
call {@link com.sun.jna.Native#detach(boolean)} from within your callback to
indicate whether the thread attachment should be maintained or not.
// Original C code
extern int printf(const char* fmt, ...);
// Equivalent JNA mapping
interface CLibrary extends Library {
int printf(String fmt, ...);
}
Varargs are not supported when using Direct mapping.
struct
. By default, this type is treated as a pointer to structure (struct *
) on the native side when used as a parameter or return value. When used as a structure field, the structure is interpreted as by value. To force the complementary interpretation, the tagging interfaces {@link com.sun.jna.Structure.ByValue} and {@link com.sun.jna.Structure.ByReference} are provided.
The data within a Java Structure
is automatically written to
native memory just before a native function call with a struct parameter, and
automatically read from native memory after the function returns.
struct
s.
// Original C code
typedef struct _Point {
int x, y;
} Point;
Point* translate(Point* pt, int dx, int dy);
// Equivalent JNA mapping
class Point extends Structure { public int x, y; }
Point translate(Point pt, int x, int y);
...
Point pt = new Point();
Point result = translate(pt, 100, 100);
ByValue
class as the argument or return type.
// Original C code
typedef struct _Point {
int x, y;
} Point;
Point translate(Point pt, int dx, int dy);
// Equivalent JNA mapping
class Point extends Structure {
public static class ByValue extends Point implements Structure.ByValue { }
public int x, y;
}
Point.ByValue translate(Point.ByValue pt, int x, int y);
...
Point.ByValue pt = new Point.ByValue();
Point result = translate(pt, 100, 100);
// Original C code
void get_devices(struct Device[], int size);
// Equivalent JNA mapping
int size = ...
Device[] devices = new Device[size];
lib.get_devices(devices, devices.length);
Alternatively, you can reallocate a single Structure instance into an array as
follows:
Device dev = new Device();
// As an array of Structure
Structure[] structs = dev.toArray(size);
// As an array of Device
Device[] devices = (Device[])dev.toArray(size);
struct
// Original C code
struct Display* get_displays(int* pcount);
void free_displays(struct Display* displays);
// Equivalent JNA mapping
Display get_displays(IntByReference pcount);
void free_displays(Display[] displays);
...
IntByReference pcount = new IntByReference();
Display d = lib.get_displays(pcount);
Display[] displays = (Display[])d.toArray(pcount.getValue());
...
lib.free_displays(displays);
// Original C code
typedef struct _Point {
int x, y;
} Point;
typedef struct _Line {
Point start;
Point end;
} Line;
// Equivalent JNA mapping
class Point extends Structure {
public int x, y;
}
class Line extends Structure {
public Point start;
public Point end;
}
Explicit initialization of nested structures is not required; the objects will
be created as needed and properly mapped to the parent structure's memory.If you need a pointer to a structure within your structure, you can use the {@link com.sun.jna.Structure.ByReference} tagging interface to indicate the field should be treated as a pointer instead of inlining the full structure.
// Original C code
typedef struct _Line2 {
Point* p1;
Point* p2;
} Line2;
// Equivalent JNA mapping
class Point extends Structure {
public static class ByReference extends Point implements Structure.ByReference { }
public int x, y;
}
class Line2 extends Structure {
public Point.ByReference p1;
public Point.ByReference p2;
}
The more general case is just a pointer to memory. This allows you to define
the field without necessarily defining the inner structure itself, similar to
declaring a struct without defining it in C:
// Original C code
typedef struct _Line2 {
Point* p1;
Point* p2;
} Line2;
// Equivalent JNA mapping
class Line2 extends Structure {
public Pointer p1;
public Pointer p2;
}
Line2 line2;
Point p1, p2;
...
line2.p1 = p1.getPointer();
line2.p2 = p2.getPointer();
typedef struct _Buffer {
char buf1[32];
char buf2[1024];
} Buffer;
class Buffer extends Structure {
public byte[] buf1 = new byte[32];
public byte[] buf2 = new byte[1024];
}
Calculation of the native size of the structure is deferred until the
structure is actually used.
// Original C code
typedef struct _Header {
int flags;
int buf_length;
char buffer[1];
} Header;
require a constructor which establishes the required size for the structure
and initializes things appropriately. For example:
// Equivalent JNA mapping
class Header extends Structure {
public int flags;
public int buf_length;
public byte[] buffer;
public Header(int bufferSize) {
buffer = new byte[bufferSize];
buf_length = buffer.length;
allocateMemory();
}
}
Structure
prior
to a function call and read back from native memory after the function call.
Sometimes a structure field is not intended for client use, gets modified
asynchronously by hardware, or otherwise is effectively read-only.
If you expect any fields of the structure to be modified by any agent outside
your Java program, you should mark the field volatile
. This
prevents JNA from automatically updating the native memory from the Java
value. You can still force an update of the native memory from the Java value
by calling {@link com.sun.jna.Structure#writeField(String)} for the field in
question.
class Data extends com.sun.jna.Structure {
public volatile int refCount;
public int value;
}
...
Data data = new Data();
In the above example, the field refCount
will only be written
to native memory based on the Java value with a call to
data.writeField("refCount")
. To obtain the current state of
native memory, call {@link com.sun.jna.Structure#read()} (to update the entire
structure) or {@link com.sun.jna.Structure#readField(String)
data.readField("refCount")} (to update just the refCount
field).
Structure
's contents, you may mark its
fields final
. Structure reads can still overwrite the values
based on native memory contents, but no Java code will be able to modify any
of the fields.
class ReadOnly extends com.sun.jna.Structure {
// Do not initialize the field here, or the compiler will inline the value!
public final int refCount;
{
// Initialize fields here, to ensure the values are not inlined
refCount = -1;
read();
// refCount might now have a different value
}
}
...
ReadOnly ro = new ReadOnly();
// Will not compile!
ro.refCount = 0;
Make certain you attend to the following:
errno
or
GetLastError()
),
the error code will be thrown as a {@link com.sun.jna.LastErrorException} if you
declare the exception in your JNA mapping. Alternatively, you can use
{@link com.sun.jna.Native#getLastError()} to retrieve it. Throwing an exception
is preferred since it has better performance.
{@link com.sun.jna.Native#setProtected Native.setProtected(true)}
. Not all platforms support this protection; if not, the value of {@link com.sun.jna.Native#isProtected} will remain false
.
NOTE: When protected mode is enabled, you should make use of the jsig library, if available (see Signal Chaining) to avoid interfering with the JVM's use of signals. In short, set the environment variable LD_PRELOAD
(or LD_PRELOAD_64
) to the path to libjsig.so
in your JRE lib directory (usually ${java.home}/lib/${os.arch}/libjsig.so) before launching your Java application.
false
parameter.
It is then up to you to use {@link com.sun.jna.Structure#readField(String)}
and {@link com.sun.jna.Structure#writeField(String)} or {@link
com.sun.jna.Structure#writeField(String,Object)} to synch with just the fields
of interest.