Submitted By : by Vitaly Shelest and Danny Katz
Java Platform Invoke SDK (J/Invoke®) vs. Java Native
Interface
The SDK design for direct native function call from Java code
The Java Native Interface is used to write native methods to handle situations when an application cannot be written entirely in the Java programming language. In some cases
Java Developer needs to use standard platform specific libraries. Having experience more
than five years in JNI coding I realized that Java should have a friendly SDK that makes native function/class calls easy.
Does Java Developer use JNI?
The standard Java technology does not give any option to access native code but through JNI (Java
Native Interface). It’s also worth noting that Platform Invoke, or native code invocation, is vastly
easier in .Net than JNI in Java. Unlike .Net, the JNI requires the compilation of a separate, wrapper
DLL to use a native library.
Look at the Java developer’s poll that responded on the question: “How often do you write Java
Native Interface (JNI) code?” are
|
|
|
| Frequently |
2.2% |
|
| Occasionally |
8.1% |
|
| Rarely |
29.6% |
|
| I've never written JNI |
59.9% |
|
From my experience I guess that only 2.2% of Java developers know JNI perfectly well. About
60% does not know JNI at all. And if Java Programmer should call some functions from a native
library he has a great pain. Any unhandled exception in JNI code benumbs him. At Sun's Java
Forum you can find a great number of questions with JVM Exception listing that starts with
# An unexpected error has been detected by HotSpot Virtual Machine:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=., pid=., tid=.
If the Java programmer knows C/C++ well he has a chance to fix the problem. The most Java
developers do not like or do not know Microsoft .NET Framework. But look at how Microsoft
solves such problem in .NET languages. To call native export function from any library you can
use .NET Platform Invoke (P/Invoke) SDK. The main idea of it is "declare" a prototype of a native
function in .NET language code and "use" it without a specific SDK like JNI.
JNI Mediators and bridges do not solve the problem
Now in WEB there are a number of products which authors claim: Call native code functions
from Java without JNI! But while using them you find out that the life has not become easy. Let
take a look at some of such products.
xFunction
Enables you to call any operating system APIs or functions exported from DLLs/shared libraries
from Java code. But a simple function call takes more efforts than you guess:
import com.excelsior.xFunction.*;
...
/* Call Beep() from KERNEL32.DLL */
xFunction f = new xFunction("kernel32", "int Beep(int,int)");
f.invoke(new Argument(1770), new Argument(100))
But if you call a function with a structure as a parameter the Java code become huge and unclear
Let you have to call an export C function from some dll:
struct Point
{
int x, y;
};
__declspec(dllexport)
int *func(int *a, struct Point *b)
{
b->x = 1;
*a = 2;
int *arr = new int[100];
return(arr);
}
Its call from a Java program would look as follows:
public class Point extends Structure
{
int x, ;
int y;
public String defineLayout()
{
return("int x, int y");
}
}
...
try
{
xFunction f = new xFunction("somedll",
"int* _func@8(int*, Point*)");
Point p = new Point();
p.x = 10;
p.y = 20;
Pointer arg1 = Pointer.create("int*");
Pointer arg2 = Pointer.createPointerTo(p);
Pointer result = (Pointer) (f.invoke(arg1, arg2));
if(((Integer) arg1.deref()).intValue() != 2)
{
throw new Error();
}
p = (Point) arg2.deref();
if(p.x != 1)
{
throw new Error();
}
}
catch( ..
J2Native
This is the software development kit for working with native code from any Java application
without using Java Native Interface (JNI) technology. But when I get the documentation I see that
should learn a number of Java classes to be used like:
AnsiString, Argument, ArrayArgument, ArrayType, Bool, Callback, Char, Const,
DelegatedArgument, DoubleFloat, FloatArgument,FloatType, Function,
FunctionExecutionException, FunctionNotFoundException,
llegalMemoryAccessException, Int, Int16, Int32, Int64, Int8, IntegerArgument,
IntegerType, J2NativeContext, Library, LibraryLoader, LibraryNotFoundException,
MemoryException, NumericArgument, NumericType, OutOnly, Pointer, Pointer.Const,
Pointer.OutOnly, Pointer.Void, PointerArgument, PointerType, SimpleFloat,
StringType, StructuralArgument, Structure,TypedPointer, UInt, UInt16, UInt32,<
UInt8, Union, WideChar, WideString, ZeroTerminatedString
They will help you to marshal and unmarshal parameters and make indirect call to a native
function. As for me it is better to write JNI code than use such SDK.
JNIWrapper
This is another well-known SDK that also enters a number of new types, pointers, allocators in
Java code. Native functions are called indirectly that makes Java code unclear and bulky. Using
specific types you can define C structures:
typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}
MSG, *PMSG;
and
typedef struct tagPOINT
{
LONG x;
LONG y;
}
POINT, *PPOINT;
in Java code as follows
private static class POINT extends Structure
{
public LongInt _x = new LongInt();
public LongInt _y = new LongInt();
public POINT()
{
init(new Parameter[] {_x, _y});
}
}
and
private static class MSG extends Structure
{
Pointer.Void _hwnd = new Pointer.Void();
UInt _message = new UInt();
UInt32 _wParam = new UInt32();
UInt32 _lParam = new UInt32();
UInt32 _time = new UInt32();
POINT _pt = new POINT();
public MSG()
{
init(new Parameter[]{_hwnd, _message,
_wParam, _lParam, _time, _pt});
}
}
No natural means to define C/C++ Union. Regular Java arrays should be converted to some array
classes. So this is another language in Java to make JNI calls indirectly.
There are other JNI bridges that enter C++ paradigm into Java code like Neva. Java code written
with Neva looks like regular C++ coding.
Why Platform Invoke?
In Microsoft .NET Framework unmanaged (native) functions can be consumed in two ways - with
managed C++ that includes unmanaged extensions (that has something common with JNI) and
Platform Invoke (P/Invoke). Like the Java Native Interface (JNI) and J/DirectR before it, P/Invoke
uses a managed method declaration to describe the stack frame, but assumes the method body will
be provided by an external, native DLL. Unlike JNI, however, P/Invoke is useful for importing "heritage" DLLs that were not written with the CLR in mind. P/Invoke enables managed code to
call functions exported from an unmanaged dynamic link library (DLL), such as Win32 API and
custom DLLs. To consume exported DLL functions you.
- Identify functions in DLLs.
Minimally, you must specify the name of the function and name of the DLL that contains it.
- Create a class to hold DLL functions.
You can use an existing class, create an individual class for each unmanaged function, or
create one class that contains a set of related unmanaged functions.
- Create function prototypes in managed code.
- Call a DLL function.
Call the method on your managed class as you would any other managed method. Passing
structures and implemented callback functions.
In function prototypes standard types used according C/C++ to .NET type conventions. P/Invoke
supports implicit and explicit marshaling. In most cases it is enough implicit marshaling use. The
code written with P/Invoke is clear and simple. All information used in marshalling is defined with attributes of function prototypes and structures/classes fields. For example, to define MessageBox
function in C# you write its prototype in some class.
[DllImport("User32.dll", EntryPoint="MessageBox")]
static extern int msgbox(int hwnd, string msg,
string caption, int msgtype)
DllImport Attribute defines DLL and the original function name. .NET Framework use this
attribute values defined explicitly and implicitly (for example, string conversion is Ansi by default)
to marshal parameters while the function calls. Then this function called like any managed method:
msgbox(0, "MessageDialog called", "DllImport Demo", 0);
Platform Invoke can be developed for SUN Java :
The Java new features and Platform Invoke
Starting with JSE 1.5.x SUN added to Java language standard annotations to eliminate use of
custom attributes in a Java class. Annotations provide data about Java classes and theirs members
that is not part of the program itself. They have no direct effect on the operation of the code but
only annotate. Annotations have a number of uses and among them:
- Information for the compiler - Annotations can be used by the compiler to detect errors
or suppress warnings.
- Compiler-time and deployment-time processing - Software tools can process
annotation information to generate code, XML files, and so forth.
- Runtime processing - Some annotations are available to be examined at runtime.
Annotations for runtime processing resemble attributes in .NET languages that define information
stored as metadata. You can annotate classes, methods, method parameters and class fields.
Annotations can keep default values like .NET attributes. Comparing Java and .NET I realized that .NET Platform Invoke paradigm can be implemented in Java one-to-one. All platform specific code
can be hidden in JNI module that implements:
- Marshaling of native function parameters and structures.
- Creation callback functions by wrapping Java methods representing prototypes of callback
functions.
- Late binding Java native methods (those present native function prototypes) to the library
functions at runtime.
- Converting of JNI function stack to the real native function stack call and vise versa.
The following example demonstrates how to define and call the MessageBox function in
User32.dll, passing simple strings as arguments. The function prototype:
@ImportLibrary(libName = "user32")
public class UserLib extends CNativeLibrary
{
@Function(entryPoint = "MessageBoxW")
public native int MessageBox(int hwnd, String msg,
String caption, int msgtype);
}
When J/InvokeR calls a native function, it performs the following sequence of actions:
- Locates the library containing the function.
- Loads the library into memory.
- Locates the address of the function in the memory and pushes its arguments (passed by
JVM while the native function prototype calls) onto the stack, marshaling data as required.
- Transfers control to the native function.
- Gets results returned, unmarshaling them as required and passes the results back to Java
code.
Custom marshaling
J/InvokeR will support implicit and explicit marshaling. In 90% J/InvokeR engine can do right
parameter marshaling while a native function call. The algorithm of converting the data from java
object to a native function parameters code and moving the result returned back to Java code are related to a number of memory allocations and deletions. But some data types can be allocated with
different allocators. For example, in one hand, text data memory in MS Windows can be allocated with malloc, CoTaskMemAlloc, SysStringAlloc, etc. and marshaling algorithm should "know"
how the data pointer to be created. In this case marshaling type should be defined explicitly. In
other hand, some pointers returned by a native function may not be deleted, etc.
There is another problem with implicit marshaling - by default all function parameters are
marshaled and unmarshaled and this reduces application performance. In custom marshaling you
can define which parameters marshaled and which unmarshaled.
With custom marshaling the call to MessageBox function above can be declared as follows
@ImportLibrary(libName = "user32")
public class UserLib extends CNativeLibrary
{
@Function(entryPoint = "MessageBoxA", charSet = CharSet.Ansi)
public native int MessageBox(int hwnd, @In String msg,
@In String caption,int msgtype);
}
Only the second and the third parameters are marshaled. While mapping java.lang.String type
to the native pointer wchar_t* the marshaler uses CoTaskMemAlloc and CoTaskMemFree.
Custom marshalling plays key role in C Structure map to Java Class. For example, MSG and POINT
structures can be defined with J/InvokeR in a very simple way:
@StructLayout(layout = LayoutKind.Sequential)
public class POINT extends CStructure {
public int x;
public int y;
}
@StructLayout(layout = LayoutKind.Sequential)
public class MSG extends CStructure {
public int hwnd;
public int message;
public int wParam;
public int lParam;
public int time;
public POINT pt = new POINT();
}
Then the class instance can be passed to a native function (for instance, GetMessage) as a structure:
// Initialize the native library class instance
// with the native function GetMessage
User32 user32 = new User32();
// Create the structure object
MSG msg = new MSG();
int hWnd;
.
// Call the native function
user32.GetMessage(@Out msg, hWnd, 0, 0);
Compare this example with one from JNIWrapper - here Java coding style is natural.
J/InvokeR development results for SUN Java in MS Windows :
The first version of J/InvokeR was developed for MS Windows and an ix86 compatible processor.
The all algorithms of native function call and marshaling are implemented in the native part of Java
Platform Invoke SDK to preserve Java code written with J/InvokeR portable. In future Author
plans to rewrite the native part of J/InvokeR for Linux.
The main features implemented in J/ Invoke SDK:
- Native function prototypes used in Java code declared as regular Java native methods in a
Java class bound to a corresponding native module.
- Implicit and explicit marshaling of parameters in function call;
- Implicit and explicit marshaling of Java classes to/from C structures;
- Wrapping a Java method to a C callback function and converting it to a parameter in a
native function call;
- Special means for implementing algorithms of custom marshaling in Java code (native
pointers and complex data structures).
- Mapping a C++ class virtual function table to a Java class that supports easy calls to native
virtual functions in the corresponding C++ class object.
References :
- JAVA.NET, POLL RESULTS: How often do you write Java Native Interface (JNI) code?
http://www.java.net/pub/pq/78
- Java Platform Invoke SDK, Javain Ltd..2007;
http://www.sharewareplaza.com/Java-Platform-Invoke-API-Demo- versiondownload_49212.html
- xFunction, Excelsior LLC;
http://www.excelsior-usa.com/xfunction.html
- J2Native, Smardec;
http://www.smardec.com/products/j2native.html
- JNIWrapper, TeamDev Ltd.;
http://www.teamdev.com/java_integration.jsf
- Neva, Neva Object Technology, Inc.;
http://www.nevaobject.com/products.htm
- Consuming Unmanaged DLL Functions, Microsoft Corporation;
http://msdn2.microsoft.com/en-us/library/default.aspx
Author contact information
www.javain.com
vitaly.s@javain.com