分享

Java Native Access (JNA)

 miqi05 2010-04-05

JNA provides Java programs easy access to native shared libraries (DLLs on Windows) without writing anything but Java code—no JNI or native code is required. This functionality is comparable to Windows' Platform/Invoke and Python's ctypes. Access is dynamic at runtime without code generation.

JNA allows you to call directly into native functions using natural Java method invocation. The Java call looks just like it does in native code. Most calls require no special handling or configuration; no boilerplate or generated code is required.

The JNA library uses a small native library stub to dynamically invoke native code. The developer uses a Java interface to describe functions and structures in the target native library. This makes it quite easy to take advantage of native platform features without incurring the high overhead of configuring and building JNI code for multiple platforms.

While some attention is paid to performance, correctness and ease of use take priority.

The JavaDoc is available online, which includes detailed descriptions of JNA usage in different situations.

This library is provided under the LGPL, version 2.1 or later.

NOTE: Sun is not sponsoring this project, even though the package name (com.sun.jna) might imply otherwise.

Top

Features

Automatic mapping from Java to native functions, with simple mappings for all primitive data types

Runs on most platforms which support Java

Automatic conversion between C and Java strings, with customizable encoding/decoding

Structure and Union arguments/return values, by reference and by value

Function Pointers, (callbacks from native code to Java) as arguments and/or members of a struct

Auto-generated Java proxies for native function pointers

By-reference (pointer-to-type) arguments

Java array and NIO Buffer arguments (primitive types and pointers) as pointer-to-buffer

Nested structures and arrays

Wide (wchar_t-based) strings

Native long support (32- or 64-bit as appropriate)

Demo applications

Supported on 1.4 or later JVMs (earlier VMs may work with stubbed NIO support)

Customizable marshalling/unmarshalling (argument and return value conversions)

Customizable mapping from Java method to native function name, and customizable invocation to simulate C preprocessor function macros

Support for automatic Windows ASCII/UNICODE function mappings

Varargs support

Type-safety for native pointers

VM crash protection (optional)

Optimized direct mapping for high-performance applications.

Top

How To Get Started Using JNA

Java Native Access (JNA) has a single component, jna.jar; the supporting native library (jnidispatch) is included in the jar file. JNA is capable of extracting and loading the native library on its own, so you don't need additional configuration. JNA falls back to extraction if the native library is not already installed on the local system somewhere accessible to System.loadLibrary (see information on library loading). The native library is also available in platform-specific jar files for use with Java Web Start.

Download jna.jar from the download page.

Compile and run this short example, which maps the printf function from the standard C library and calls it. Be sure to include jna.jar in the classpath:

Identify a native target library that you want to use. This can be any shared library with exported functions. Some examples of mappings for common system libraries may be found in the unix and win32 examples subdirectories.

Make your target library available to your Java program. There are two ways to do this:

The preferred method is to set the jna.library.path system property to the path to your target library. This property is similar to java.library.path but only applies to libraries loaded by JNA.

Change the appropriate library access environment variable before launching the VM. This is PATH on Windows, LD_LIBRARY_PATH on Linux, and DYLD_LIBRARY_PATH on OSX.

Declare a Java interface to hold the native library methods by extending the Library interface.

Following is an example of mapping for the Windows kernel32 library.

Within this interface, define an instance of the native library using the Native.loadLibrary(Class) method, providing the native library interface you defined in step (5).

The INSTANCE variable is for convenient reuse of a single instance of the library. Alternatively, you can load the library into a local variable so that it will be available for garbage collection when it goes out of scope. A Map of options may be provided as the third argument to loadLibrary to customize the library behavior; some of these options are explained in more detail below. The SYNC_INSTANCE is also optional; use it if you need to ensure that your native library has only one call to it at a time.

Declare methods that mirror the functions in the target library by defining Java methods with the same name and argument types as the native function (refer to the basic mappings below or the detailed table of type mappings). You may also need to declare native structures to pass to your native functions. To do this, create a class within the interface definition that extends Structure and add public fields (which may include arrays or nested structures).

You can now invoke methods on the library instance just like any other Java class. For a more extensive example, see the WindowUtils and ShapedWindowDemo classes.

Alternatively, you may declare a class to hold your native methods, declare any number of methods with the "native" qualifier, and invoke Native.register(String) in the class static initializer with your library's name. See JNA direct mapping for an example.

If the C header files for your library are available, you can auto-generate a library mapping by using Olivier Chafik's excellent JNAerator utility. This is especially useful if your library uses long or complicated structures where translating by hand can be error-prone.

See the JavaDoc overview for more detailed information about JNA usage.

Top

Default Type Mappings

Java primitive types (and their object equivalents) map directly to the native C type of the same size.

Native Type

Size

Java Type

Common Windows Types

char

8-bit integer

byte

BYTE, TCHAR

short

16-bit integer

short

WORD

wchar_t

16/32-bit character

char

TCHAR

int

32-bit integer

int

DWORD

int

boolean value

boolean

BOOL

long

32/64-bit integer

NativeLong

LONG

long long

64-bit integer

long

__int64

float

32-bit FP

float

double

64-bit FP

double

char*

C string

String

LPTCSTR

void*

pointer

Pointer

LPVOID, HANDLE, LPXXX

Unsigned types use the same mappings as signed types. C enums are usually interchangeable with "int". A more comprehensive list of mappings may be found here.

Top

Using Pointers and Arrays

Primitive array arguments (including structs) are represented by their corresponding Java types. For example:

NOTE: if the parameter is to be used by the native function outside the scope of the function call, you must use Memory or an NIO Buffer. The memory provided by a Java primitive array will only be valid for use by the native code for the duration of the function call.

Arrays of C strings (the char* argv[] to the C main, for example), may be represented by String[] in Java code. JNA will pass an equivalent array with a NULL final element.

Top

Using Structures/Unions

When a function requires a pointer to a struct, a Java Structure should be used. If the struct is passed or returned by value, you need only make minor modifications to the parameter or return type class declaration.

Typically you define a public static class derived from Structure within your library interface definition. This allows the structure to share any options (like custom type mapping) defined for the library interface.

If a function requires an array of struct (allocated contiguously in memory), a Java Structure[] may be used. When passing in an array of Structure, it is not necessary to initialize the array elements (the function call will allocate, zero memory, and assign the elements for you). If you do need to initialize the array, you should use the Structure.toArray method to obtain an array of Structure elements contiguous in memory, which you can then initialize as needed.

Unions are generally interchangeable with Structures, but require that you indicate which union field is active with the setType method before it can be properly passed to a function call.

Top

Using By-reference Arguments

When a function accepts a pointer-to-type argument you can use one of the ByReference types to capture the returned value, or subclass your own. For example:

Alternatively, you could use a Java array with a single element of the desired type, but the ByReference convention better conveys the intent of the code.

The Pointer class provides a number of accessor methods in addition to getByteArray() which effectively function as a typecast onto the memory.

Type-safe pointers may be declared by deriving from the PointerType class.

Top

Customized Mapping from Java to Native (Types and Function Names)

The TypeMapper class and related interfaces provide for converting any Java type used as an argument, return value, or structure member to be converted to or from a native type. The example w32 API interfaces use a type mapper to convert Java boolean into the w32 BOOL type. A TypeMapper instance is passed as the value for the TYPE_MAPPER key in the options map passed to Native.loadLibrary.

Alternatively, user-defined types may implement the NativeMapped interface, which determines conversion to and from native types on a class-by-class basis.

You may also customize the mapping of Java method names to the corresponding native function name. The StdCallFunctionMapper is one implementation which automatically generates stdcall-decorated function names from a Java interface method signature. The mapper should be passed as the value for the OPTION_FUNCTION_MAPPER key in the options map passed to the Native.loadLibrary call.

Refer to this table in the overview for a complete list of built-in type mappings.

Top

Callbacks/Closures (Function Pointers)

Callback declarations consist of a simple interface that extends the Callback interface and implements a callback method (or defines a single method of arbitrary name). Callbacks are implemented by wrapping a Java object method in a little bit of C glue code. The simplest usage resembles using anonymous inner classes to register event listeners. Following is an example of callback usage:

Here is a more involved example, using the w32 APIs to enumerate all native windows:

If your callback needs to live beyond the method invocation where it is used, make sure you keep a reference to it or the native code will call back to an empty stub after the callback object is garbage collected.

Proxy wrappers are automatically generated for function pointers found within structs initialized by native code. This facilitates calling those functions from Java.

Top

Invocation from Dynamically-Typed Languages

Languages such as Jython or JRuby may find it more convenient to access the NativeLibrary and Function classes directly rather than establishing a dedicated interface.

Here's a brief example of using JNA from JRuby:

Top

Frequently Asked Questions (FAQ)

Should I use Structure.ByReference, Structure.ByValue, or Structure[]?

How do I read back a string?

How do I map a native long type?

My library mapping causes an UnsatisfiedLinkError

My library sometimes causes a VM crash

My Windows library mapping causes a VM crash on every call

How do I get an arbitrary Pointer value?

My structure has the wrong contents. What did I do wrong?

Does JNA work with J2ME/Windows Mobile?

How does JNA performance compared to custom JNI?

I get an UnsatisfiedLinkError on OSX trying to include my custom library via Java Web Start

I need to use a COM/OCX/ActiveX object. Can JNA help me?

When should I use Structure.ByReference? Structure.ByValue? Structure[]?

Find your corresponding native declaration below:typedef struct _simplestruct {                                         int myfield;                                         } simplestruct;                                         typedef struct _outerstruct {                                         simplestruct nested; // use Structure                                         } outerstruct;                                         typedef struct _outerstruct2 {                                         simplestruct *byref; // use Structure.ByReference                                         } outerstruct2;                                         typedef struct _outerstruct3 {                                         simplestruct array[4]; // use Structure[]                                         } outerstruct3;                                         typedef struct _outerstruct4 {                                         simplestruct* ptr_array[4]; // use Structure.ByReference[]                                         } outerstruct4;                                         // Field is a pointer to an array of struct                                         typedef struct _outerstruct5 {                                         simplestruct* ptr_to_array; // use Structure.ByReference, and use                                         // Structure.toArray() to allocate array                                         } outerstruct5;                                         // struct pointers as return value or argument                                         // use Structure                                         outerstruct *myfunc();                                         void myfunc(outerstruct* data);                                         // struct (by value) as return value or argument                                         // use Structure.ByValue                                         simplestruct myfunc();                                         void myfunc(simplestruct);

If you need a ByValue or ByReference class, define them within your main Structure definition like this:public class MyStructure extends Structure {                                         public static class ByValue extends MyStructure implements Structure.ByValue { }                                         public static class ByReference extends MyStructure implements Structure.ByReference { }                                         }

How do I read back a function's string result?

Suppose you have a function:

// Returns the number of characters written to the buffer                                         int getString(char* buffer, int bufsize);

The native code is expecting a fixed-size buffer, which it will fill in with the requested data. A Java String is not appropriate here, since Strings are immutable. Nor is a Java StringBuffer, since the native code only fills the buffer and does not change its size. The appropriate argument type would be either byte[], Memory, or an NIO Buffer, with the size of the object passed as the second argument. The method Native.toString(byte[]) may then be used to convert the array of byte into a Java String.

How do I map a native long type?

Actually, no one ever asks this question, but they really need the answer. Do not use Java long!

On Windows, you can use a Java int, since the native long type is always 32 bits. On any other platform, the type may be 32 or 64 bits, so you should use the NativeLong type to ensure the proper size is used.

My library mapping causes an UnsatisfiedLinkError

Use a dump utility to examine the names of your exported functions to make sure they match (nm on linux, depends on Windows). On Windows, if the functions have a suffix of the form "@NN", you need to pass a StdCallFunctionMapper as an option when initializing your library interface (see here). In general, you can use a function mapper (FunctionMapper) to change the name of the looked-up method, or an invocation mapper (InvocationMapper) for more extensive control over the method invocation.

My library sometimes causes a VM crash

Double check the signature of the method causing the crash to ensure all arguments are of the appropriate size and type. Be especially careful with native pointer variations. See also information on debugging structure definitions.

My Windows library mapping causes a VM crash on every call

If your library uses the stdcall calling convention, your interface should extend the StdCallLibrary interface. Using the wrong calling convention for a library will usually cause a VM crash.

How do I get an arbitrary Pointer value?

First, you probably don't actually want an arbitrary value. Ask yourself what you're really trying to do. Remember, type safety is your friend.

Pointer.createConstant() should be used when you need a special value that is not really a pointer (NULL usually serves this purpose, but some C programmers like to check pointers for special integer values instead). The Pointer produced by this function can't actually be used to access memory.

Pointer.share() can be used to generate a new Pointer as an offset from an existing one

java.nio.Buffer can be used to wrap a Java array with a different offset and length than the original.

Clean up the sloppy C code by declaring an appropriate function interface. If your function in C takes either a Pointer or an integer type, simply declare both method signatures in your JNA interface. They will both invoke the same function, but you get the added benefit of type checking on the arguments.

If you really, really, HAVE to convert an integer value into a Pointer, you can do something like this:

new IntByReference(value).getPointer().getPointer(0)

Debugging Structure Definitions

Normally when you invoke toString on a Structure, it will print each defined field with its calculated memory offset. If when launching the VM, you pass it "-Djna.dump_memory=true", toString will also dump the contents of the corresponding native memory. This is useful to determine if you've added or omitted a field, or chosen an incorrect size. Viewing the memory as bytes usually makes it clear where field boundaries should be, assuming the memory has been initialized by native code.

Does JNA work with J2ME/Windows Mobile?

There is an implementation available, but it has not yet been integrated into the standard build.

I need to use a COM/OCX/ActiveX object. Can JNA do that?

Not really. Try JACOB or com4j, both of which can parse a COM interface definition and generate a Java object to match it.

I get an UnsatisfiedLinkError on OSX when I provide my native library via Java Web Start

Libraries loaded via the JNLP class loader on OSX must be named with a .jnilib suffix. The class loader won't find resources included with thetag if they have a .dylib suffix.

How does JNA performance compare to custom JNI?

JNA direct mapping can provide performance near that of custom JNI. Nearly all the type mapping features of interface mapping are available, although automatic type conversion will likely incur some overhead.

The calling overhead for a single native call using JNA interface mapping can be an order of magnitude (~10X) greater time than equivalent custom JNI (whether it actually does in the context of your application is a different question). In raw terms, the calling overhead is on the order of hundreds of microseconds instead of tens of microseconds. Note that that's the call overhead, not the total call time. This magnitude is typical of the difference between systems using dynamically-maintained type information and systems where type information is statically compiled. JNI hard-codes type information in the method invocation, where JNA interface mapping dynamically determines type information at runtime.

You might expect a speedup of about an order of magnitude moving to JNA direct mapping, and a factor of two or three moving from there to custom JNI. The actual difference will vary depending on usage and function signatures. As with any optimization process, you should determine first where you need a speed increase, and then see how much difference there is by performing targeted optimizations. The ease of programming everything in Java usually outweighs small performance gains when using custom JNI.

See the main method of this JUnit test for an example of how you might measure performance for the different mapping options in your situation.

See the JavaDoc for performance tips related to different types of type mapping.

Top

JNA Direct Mapping

JNA supports a direct mapping method which can improve performance substantially, approaching that of custom JNI. Method signatures are the same as they would be in a JNA interface mapping, but they can be any static or object methods. You only need register them within the static initializer of the defining class, as in the example below. The Native.register() method takes the name of your native library, the same as Native.loadLibrary() would.

As of version 3.2.0, direct mapping supports the same type mappings as interface mapping, except for arrays of Pointer/String/WString/NativeMapped as function arguments. You can easily convert from interface mapping to direct mapping by creating a direct mapping class which implements your library interface, with all methods defined as native methods. Then your library instance variable can be assigned an instance of this new class instead of the object returned by Native.loadLibrary().

Top

Examples

In the com.sun.jna.examples package are some examples of using the JNA library (and are pretty nifty utilities in and of themselves).

ShapedWindowDemo: Non-rectangular windows (a circular clock) (WindowUtils code).

BalloonManagerDemo: Speech-balloon windows (a la Google Maps) (BalloonManager code).

FileUtils: Cross-platform move-to-trash functionality

FileMonitor: Cross-platform file change notification (still needs inotify and kqueues implementations)

Top

Community

Please use the appropriate mailing list to ask for help, suggest ideas, contribute patches, etc. All contributions are welcome. When asking about how to do a library mapping, be sure to include C API definitions and example usage, as well as whatever Java mapping you've already tried.

All mailing lists are also available via RSS:

Announcements

Usage Questions and Discussion

Development Discussion

Bugs and Enhancements Issue Tracking

If you are interested in paid support, feel free to say so on one of the JNA mailing lists. Most simple questions will be answered on the list, but more complicated work, new features or target platforms can be negotiated with any of the JNA developers (this is how several of JNA's features came into being). You may even encounter other users with the same need and be able to cost share the new development.

Top

Projects Using JNA

IAXClient Applet (Wolfgang Pichler), providing VOIP for Java.

JRuby (Charles Nutter)

Rococoa Java bindings to the Mac OS X Cocoa framework (Duncan McGregor)

jna-posix Common POSIX Functions for Java

JNAerator (pronounced "generator") Autogenerates JNA mappings from C headers (Olivier Chafik)

Freedom for Media in Java (FMJ) (Ken Larson/Dieter Krachtus)

gstreamer for Java (Wayne Meissner)

Videolan JVLC Java Multimedia Library

SVNKit pure Java Subversion client library.

OmegaT Computer-Aided Translation, which makes use of the hunspell spell checker

IntelliJ IDEA (JetBrains)

NetBeans IDE

Drive Lego Mindstorm NXT (Emmanuel Pirsch)

Miscellaneous contributed mappings and utilities (including Windows NT Service, Registry, and User Account libraries).

A JavaFX Clock (Augusto Sellhorn)

Detect User Inactivity (Olivier Chafik)

Athena Backup (Doug Patriarche)

USB for Java (Mario Boikov)

Post to users AT jna DOT dev DOT java DOT net to include your project in this list, or if you'd like to contribute a library mapping you've written.

Top

Development Tasks

The library works fairly well now, but there are a number of tasks with which we'd appreciate help:

Build the jnidispatch library backend on new platforms (it should mostly work out of the box if we can just get access to the appropriate build platform).

More comprehensive documentation on using JNA, including examples of Java to native conversions of data types, function usage, and proper memory management.

Tips and recommended usage of JNA: Likely danger areas, failure modes, best practices, multithreading, etc.

Native library definitions for the more useful libraries on various platforms; for example, user32 on Windows. This is important not for having an exhaustive library definition but to illustrate all the different ways a native library may need to be mapped.

Testing on various JDK versions and platforms (linux flavors!).

See the TODO file in the project directory for more up-to-date items.

Top

Building and Multi-platform support

JNA has been built and tested on OSX (ppc, x86, x86_64), linux (x86, amd64), FreeBSD/OpenBSD (x86, amd64), Solaris (x86, amd64, sparc, sparcv9) and Windows (x86, amd64). It has also been built for windows/mobile and Linux/ppc64, although those platforms are not included in the distribution. The ant build script's test target will build and run the test suite, which has decent coverage and is a quick way to determine if your environment is set up correctly.

If you want to do a build yourself, you'll need ANT, GNU make and GCC. On windows, you will need either cygwin GCC or the MINGW32 version (MSVC is used to build the win64 target, so you could probably use it for win32 as well, but I doubt it's worth the effort). To rebuild jna.jar, and run the unit tests, do

% ant dist test

If JNA has not yet been built on for your platform, you may need to tweak the build.xml and native/Makefile build configurations so that your platform is recognized.

The project also includes NetBeans and Eclipse project configurations, if you're so inclined.

Top

History

Fragments of this project date back to a small shared stubs library originally written by Sheng Liang of the Sun JNI team and demoed at JavaOne circa 1999.

Todd Fast (also of Sun) first published JNA on dev. in the fall of 2006, which allowed calls with primitive type parameters and partial struct support (that code is still available in the SVN repo under the CVS HEAD tag). From the original project announcement:Headline        Initial JNA code checked in                                         Date            Nov 30, 2006                                         Contributed by  toddfastAnnouncement

Thanks everyone for your interest in the Java Native Access (JNA) project! I've just checked in the initial code. I've worked on this little project off-and-on for the better part of 6-7 years, and this release comes about a year after I last looked at it. Therefore, I'm only just now getting familiar with it again after refactoring and redesigning for JDK 5 last year, so there may be any number of issues or shortcomings leftover since my last time with it. Please look through the code and get involved!

The Java library code is contained in a NetBeans 5.x project. If you want to build it, please use NetBeans or use the Ant build script in the root of the jnalib/ directory. I will upload a binary at some point to make it a bit easier to get started.

I've checked in binaries of the jnidispatch library and the testlib library for Win32 (.dll's), but don't have convenient access to build these for other platforms. I would greatly appreciate help from others to compile and test versions for other platforms, particularly Mac OS.

To get an idea how to use JNA, please refer to the JUnit tests in the test/ directory. These are crufty and not meant to be examples, but will have to suffice until real samples are available (I would definitely appreciate community help with those as well). Note that you will need to modify your java.library.path system property to include the jnidispatch binary (and possibly the testlib binary) in order to use JNA or run the unit tests. For example: java -Djava.library.path=./native/testlib/Debug;./native/jnidispatch/Debug ...

Timothy Wall rebooted the project in February of 2007, introducing a number of critical features, adding linux and OSX ports, and making the library usable with more than just rudimentary functions. I was looking for a way to experiment with native libraries without having to carve out a new Makefile and build process (those of you who've never built multi-lingual projects involving C don't know what you're missing). Specifically I wanted some shaped windows and better file system access. After a few proof-of-concept tests, I scouted around for existing projects from which I could bootstrap (see the OTHERS file for some of the projects that are out there). JNA had the simplest, most straightforward architecture (as did NLINK, which likely had the same roots). It was also the least problematic to make work cross-platform with a consistent build process.

Wayne Meissner has contributed enormously ("a metric buttload of hard work") in getting libffi and the various additional native libraries working. His work on a Java interface to the gstreamer library has contributed a number of critical features to JNA.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多