Here is the Message Box example using RNI. Compare it with the J/Direct Message Box example.
class ShowMsgBox { public static void main(String [] args) { ShowMsgBox app = new ShowMsgBox(); app.ShowMessage("Generated with RNI"); } private native void ShowMessage(String msg); static { System.loadLibrary("USER32"); } }
Here, ShowMessage is declared native and the loadLibrary call is added in a static block to make sure the DLL that implements the API (USER32.DLL) will be loaded.
Compile this Java source into a class file shown as follows:
jvc ShowMsgBox
Next, use msjavah to produce a header file used by the native code:
msjavah ShowMsgBox
The result is shown as follows:
/* DO NOT EDIT - automatically generated by msjavah */ #include <native.h> #pragma warning(disable:4510) #pragma warning(disable:4512) #pragma warning(disable:4610) struct Classjava_lang_String; #define Hjava_lang_String Classjava_lang_String /* Header for class ShowMsgBox */ #ifndef _Included_ShowMsgBox #define _Included_ShowMsgBox #define HShowMsgBox ClassShowMsgBox typedef struct ClassShowMsgBox { #include <pshpack4.h> const long MSReserved; #include <poppack.h> } ClassShowMsgBox; typedef struct ClassArrayOfShowMsgBox { const int32_t MSReserved; const unsigned long length; HShowMsgBox * const body[1]; } ClassArrayOfShowMsgBox; #define HArrayOfShowMsgBox ClassArrayOfShowMsgBox #define ArrayOfShowMsgBox ClassArrayOfShowMsgBox #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) void __cdecl ShowMsgBox_ShowMessage (struct HShowMsgBox *, struct Hjava_lang_String *); #ifdef __cplusplus } #endif #endif /* _Included_ShowMsgBox */ #pragma warning(default:4510) #pragma warning(default:4512) #pragma warning(default:4610)
This header file defines a structure ClassShowMsgBox that represents data members and a declaration for the native API that is implemented. RNI reveals the binary layout of the objects; JNI does not. As a result, RNI allows you to directly access information without a field or method identifier. However, because binary layout of objects is VM-specific, RNI code may not be totally portable to non-Microsoft virtual machines.
As you can see by the #ifdef __cplusplus preprocessor directive, this file can be compiled either by a C or a C++ compiler.
In RNI, the functions for controlling virtual machine operations are directly available. They are defined in native.h and documented in the Raw Native Interface Reference.
One of the most unique and complex things about RNI is the garbage collection model. In Java Native Interface (JNI), garbage collection basically follows the same rules during native method execution that it follows for the Java code execution. In RNI, you must start and stop garbage collection during native method activity. By default, garbage collection is disabled upon entering the native method. You can assume that the objects being used will not be garbage-collected during that time. But if the native method is going to take a long time, you may enable garbage collection by calling the GCEnable RNI function.
To ensure that specific objects will not be garbage-collected when garbage collection is enabled, use the RNI functions and structures provided for this purpose. See GCFramePop, GCFramePush, and GCFrame for details. These are analogous to global handles.
Note One useful feature of msjavah is that primitive types (int, boolean, long, and so on) marked static and final become #defines in the resulting header file, making it much easier to share constants.
Write a C or C++ source file that includes the header file generated by msjavah and implements the native method, then compile it and generate a dynamic-link library (DLL). This part is platform-dependent, and assumes that you know how to create a DLL. Remember to use the following include statements in the C or C++ source file:
#include <varargs.h> #include <native.h> #include "ShowMsgBox.h"
Export the RNIGetCompatibleVersion method from your DLL. All RNI DLLs must export this method; otherwise, an UnsatisfiedLinkError exception is thrown when the method is called. Export this method in native code shown as follows:
DWORD __declspec(dllexport) __cdecl RNIGetCompatibleVersion() { return RNIVER; }