This is my first attempt at JNI. My ultimate goal is to get all tasks currently running on a machine, but need to get even a simple example running. I keep getting this erro
I just removed -MD option and compiled it worked like charm
cl -I"C:\Program Files\Java\jdk1.6.0_21\include" -I"C:\Program Files\Java\jdk1.6.0_21\include\win32" -LD HelloWorld.c -FeHelloWorld.dll
If you change the location (package) of your native function declaration from the java side without updating the h file, and the signature of the method in the c++ side, It won't resolve to the method and will throw unsatisfied..
package x;
public class A {
private native void print();
...
}
moved to:
package x.y;
public class A {
private native void print();
...
}
This will require regeneration of the H file (to something like Java_x_y_A_print ).
Note you can change those signatures manually but I won't recommend
The Unsatisfied Link Error can mean many things went wrong. I would use
System.loadLibrary("HelloWorld");
Instead of
System.load();
As TwentyMiles suggested.
Also, when invoking your program you need to (assuming your DLL is on the same directory as your class files:
java -Djava.library.path=. HelloWorld
Here's a simple demo I made that calls a Win32 API function (MessageBox)
class CallApi{
private native String showMessageBox(String msg);
private native double getRandomDouble();
static{
try{
System.loadLibrary("CallApi");
System.out.println("Loaded CallApi");
}catch(UnsatisfiedLinkError e){
//nothing to do
System.out.println("Couldn't load CallApi");
System.out.println(e.getMessage());
}
}
public static void main(String args[]){
CallApi api = new CallApi();
double randomNumber = api.getRandomDouble();
String retval = api.showMessageBox("Hello from Java!\n"+
"The native random number: "+randomNumber);
System.out.println("The native string: "+retval);
}
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class CallApi */
#ifndef _Included_CallApi
#define _Included_CallApi
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: CallApi
* Method: showMessageBox
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_CallApi_showMessageBox
(JNIEnv *, jobject, jstring);
/*
* Class: CallApi
* Method: getRandomDouble
* Signature: ()D
*/
JNIEXPORT jdouble JNICALL Java_CallApi_getRandomDouble
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
#include "CallApi.h"
#include <windows.h>
#include <stdlib.h>
#include <time.h>
#pragma comment(lib,"user32.lib")
JNIEXPORT jstring JNICALL Java_CallApi_showMessageBox
(JNIEnv *env, jobject thisObject, jstring js)
{
//first convert jstring to const char for use in MessageBox
const jbyte* argvv = (*env)->GetStringUTFChars(env, js, NULL);
char* argv =(char *) argvv;
//Call MessageBoxA
MessageBox(NULL, argv, "Called from Java!", MB_ICONEXCLAMATION | MB_OK);
return js;
}
JNIEXPORT jdouble JNICALL Java_CallApi_getRandomDouble
(JNIEnv *env, jobject thisObject)
{
double num1;
srand((unsigned)(time(0)));
num1 = ((double)rand()/(double)RAND_MAX);
return num1;
}
I compile with the Visual C++ express 2008 cl, removing the -ML flag since it causes an exception when the Java code tries to call the native code:
cl /I"c:\Program Files\Java\jdk1.6.0_10\include" /I"c:\Program Files\Java\jdk1.6.0_10\include\win32" -LD CallApi.c -FeCallApi.dll
Then, to run the code:
java -Djava.library.path=. CallApi
I'm not claiming to understand the situation enough to explain it, however some users reported the error when using the "-MD" compiler flag.
For more information see Java Native Interface (JNI) - Impossible to use VS2005 with Java? which discusses this problem and offers possible work-arounds and think techie blog for alternatives.
I believe that you should be using
System.loadLibrary("HelloWorld");
instead of System.load. LoadLibrary will check your system path (not the Java library path) so make sure that HelloWorld.dll is in a directory where it can found. Also note that it does not require the full path, and you don't need to add the dll extension to the end.