JNI_OnLoad
.For this example, we will use the class
com.moesol.bindings.platform_sdk.base_services.Process
.
We used h-gen to generate
src/com/moesol/bindings/platform_sdk/base_services/Process.h
.
For more information about calling h-gen see its
usage.
Next, we created a new file called:
src/com/moesol/bindings/platform_sdk/base_services/Process.cpp
.
Since
we used VC++ with pre-compiled headers we first include
"StdAfx.h"
. Our "StdAfx.h" includes jni.h
,
some standard C++ headers, j.h
, and
jcom.h
. Note that, j.h
is required for h-gen
generated classes to work:
#include <jni.h> #include <sstream> #include <memory> using namespace std; #include "com/moesol/bindings/j.h" #include "com/moesol/bindings/jcom.h"Next we include the generated
"Process.h"
.
Next, we enclose most of the remaining file in the necessary namespace:
namespace com { namespace moesol { namespace bindings { namespace platform_sdk { namespace base_services { ... } } } } }Next, copy the declaration for
jni_GetEnvironmentVariable_impl
.
::java::lang::String * Process::jni_GetEnvironmentVariable_impl( IRMIFL::jni_env &e, jclass self, ::java::lang::String * p0 );Remove the trailing
';'
and add the member function implementation
{ ... }In this case we want
jni_GetEnvironmentVariable_impl
to call the
PlatformSDK global function
::GetEnvironmentVariable
. To do this we will need
to convert the incoming Java String into a string usable by
C/C++. h-gen generates the string parameter as
::java::lang::String *
. Normally, we would
need to include "java/lang/String.h"
to get the
h-gen C++ declaration for
::java::lang::String
, but j.h
already has
this include. String has a helper method str
that
returns a std::string
. So we use that to extract
the string.
std::string name = p0->str(e);The full listing for
jni_GetEnvironmentVariable_impl
is below. But, here
we focus on getting the resulting char *
returned
back to java. String has another helper method that will
create a new String *
from a char *
,
fromCStr
.
return ::java::lang::String::fromCStr(e, value.get());And here's the full listing:
::java::lang::String * Process::jni_GetEnvironmentVariable_impl( IRMIFL::jni_env &e, jclass self, ::java::lang::String * p0 ) { std::string name = p0->str(e); DWORD len; len = ::GetEnvironmentVariable(name.c_str(), NULL, 0); if (len == 0) { return NULL; } std::auto_ptrvalue(new char[len]); len = ::GetEnvironmentVariable(name.c_str(), value.get(), len); _ASSERT(len); return ::java::lang::String::fromCStr(e, value.get()); }
We have to make sure the JNI methods get registered with Java. These lines need to be added to Process.cpp outside of the namespace {}.
#define include_Process_registration #include "Process.h"These lines define the global data needed for the registration. When include_Process_registration is defined Process.h only emits these lines:
#ifdef include_Process_registration namespace com { namespace moesol { namespace bindings { namespace platform_sdk { namespace base_services { JNINativeMethod Process_reg_methods[] = { { "jni_GetEnvironmentVariable", "(Ljava/lang/String;)Ljava/lang/String;", Process::jni_GetEnvironmentVariable_thunk }, { "jni_SetEnvironmentVariable", "(Ljava/lang/String;Ljava/lang/String;)Z", Process::jni_SetEnvironmentVariable_thunk }, }; IRMIFL::jni_registration Process_registration("com/moesol/bindings/platform_sdk/base_services/Process", Process_reg_methods, sizeof(Process_reg_methods)/sizeof(Process_reg_methods[0])); } } } } } #endif
Add Process.cpp to the .dsp and .vcproj files via the corresponding IDE's
IRMIFL::jni_registration
maintains a global list of methods
that need to be registered. This list is registered on the
JNI_OnLoad
method (see
com_moesol_bindings.cpp):
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { LOG("JNI_OnLoad %s\n", __FILE__); IRMIFL::java_vm::on_load(vm); return JNI_VERSION_1_4; }Note: the package name
IRMIFL
is a legacy package
name that we expect to rename to ::com::moesol::bindings in
the future (that's why it's listed as beta).
On the Java side you will still need to load the native
library. We've built Process.cpp
into
com_moesol_bindings.dll
, so in Java we added these
lines to Process.java
.
static { NativeLibraryLoader.loadLibrary("com_moesol_bindings"); }
NativeLibraryLoader
is a Java class that calls
System.loadLibrary
to load the DLL and if that fails
it tries to find the location of the DLL via a system property
that is the name of the library plus the suffix
".library.path"
. For example:
com_moesol_bindings.library.path=C:/cygwin/home/robert/jSegue/sf/jSegue/src/lib/com_moesol_bindings/Debug