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_ptr value(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