JNI Hello World Unsatisfied Link Error

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)

Java class

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);
    }
}

Generated header file

/* 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

The C DLL code

#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;
}

Compile instructions

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

Leave a Comment