11

I'm using Java for a small app. It's a rewrite of an existing MFC project. There is an existing dll that I need to change to enable access from Java using JNI. All of this Java stuff is new to me, so I'm having a little trouble and feeling rather dense when I read other forum posts. In the existing dll I have a function like this:

extern "C" __declspec(dllexport) bool Create()
{
     return TRUE;
}

Dumb question time. How do I properly set it up to be called by Java?

I tried this:

JNIEXPORT jboolean JNICALL Create()
{
     return TRUE;
}

I'm including jni.h and everything compiles fine. However, when I call it from Java I get UnsatisfiedLinkError. I'm calling it from Java using this:

public static native boolean CreateSession();

System.load("D:\\JavaCallTest.dll");
Create();

Could someone kindly push me in the proper direction? I sincerely appreciate any help.

Thanks,

Nick

nickfinity
  • 1,119
  • 2
  • 15
  • 29
  • 1
    Have you looked at the Sun example? http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html – Etienne Feb 28 '12 at 16:42
  • 1
    Alternatively, you can use JNA instead of JNI since you have a C dll that can be loaded by JNA. – ecle Feb 28 '12 at 16:46
  • Please post the exception that is thrown... – quaylar Feb 28 '12 at 16:49
  • Use javah to generate the C headers, as Jörn Horstmann mentions below -- or avoid JNI entirely. An easy alternative is JNA. – Andy Thomas Feb 28 '12 at 17:10
  • Thanks for the help. I had thought about using JNA, but I want to keep any extras to a minimum, so I thought I'd better use JNI. – nickfinity Feb 28 '12 at 17:35

3 Answers3

7

You need to include the Java class name and path in your native code, for example if your native method was declared in Java as:

public class NativeCode {
    public static native boolean CreateSession();
}

and the class path was (for example) com.example.NativeCode you would declare your method in native as follows:

extern "C"
JNIEXPORT jboolean JNICALL Java_com_example_NativeCode_CreateSession(JniEnv* env, jclass clazz)
{
    return JNI_TRUE;
}

All JNI methods have a JNIEnv pointer and class as their first two parameters.

GooseSerbus
  • 1,249
  • 11
  • 15
  • That was it. It seems to be working now. We'll see what kind of issues I run into when I'm not dealing with a simple function like this. I appreciate the help. – nickfinity Feb 28 '12 at 17:33
  • @GooseSerbus what about parameters used public static native boolean CreateSession(?,?); – Aniket Jan 21 '13 at 09:35
  • @Aniket parameters are added onto the parameters in the C method e.g.: `public static native boolean CreateSession(boolean, Object);` would be `JNIEXPORT jboolean JNICALL Java_com_example_NativeCode_CreateSession(JniEnv* env, jclass clazz, jboolean b, jobject o)` – GooseSerbus Jan 22 '13 at 10:48
2

A static native method still needs at least two parameters:

JNIEnv *env
jclass clazz

The function name also has to correspond the the java package structure.

JNIEXPORT jboolean JNICALL Java_com_example_CreateSession(JNIEnv *env, jclass clazz)

Ideally, you would use the javah tool to create a header file from the java class declaring the native method and then implement the declared function prototypes.

Jörn Horstmann
  • 33,639
  • 11
  • 75
  • 118
  • +1 for mentioning that javah should be used to generate the function signatures. – Andy Thomas Feb 28 '12 at 17:10
  • Found this (http://stackoverflow.com/a/3452258/978528) and setup Eclipse to run javah. Working good now. Now I have to implement the rest of the stuff. Hopefully will be straightforward. – nickfinity Feb 28 '12 at 18:37
1

I had a similar problem - an existing C-Codebase which i needed to access from Java. It paid off for me, to get familiar with SWIG, a tool to generate an intermediate C++ DLL (which calls the C-Code), plus Java-Code that is calling into the C++ DLL.

If you have more than just 1 function of the DLL to wrap, it might pay off to check out this tool, otherwise you'd have to get familiar with JNI...

EDIT:

It seems like your DLL is not found by the System.load() call. You might want to try System.loadLibrary(), but note that your DLL must then be located in the path denoted by the Java system property java.library.path. Also dont pass the full filename in this case, but just the filename without extension.

quaylar
  • 2,617
  • 1
  • 17
  • 31
  • It was finding the DLL, but I didn't have my function properly declared. I'll have to look into SWIG. Thanks for the tip. – nickfinity Feb 28 '12 at 17:33