Sunday, September 28, 2014

How to reference C++ dll ( VS 2013 ) from Java (Eclipse LUNA) via JNI

Here is the work I have done for reference C++ dll from Java via JNI. It's a small coding journey I have been through to run C++ dll from Java with string Input/Output, I would like to share with people who would like to implement the same thing. Here are the steps I try.

  1. Writing a Java Code and Design the C++ dll name you would like to have from Eclipse LUNA. ( I would skip with HelloWorld and show you sting I/O directly, if you like to try basic HelloWorld you can reference here )
  2. Using javac compiler *.class to *.java in command line.
  3. Using javah to generate C++ header file *.h in command line.
  4. Import *.h header file and compose *.cpp to complete dll.
  5. Reference dll in Eclipse and Run the code.
  6. Others, such as adding package name in Java.
1. Java code to create the JNI interface. 

a. lunch eclipe and create a new java project 


















b. then right click create a java class.



















c. put the code as below:


import java.io.IOException;

public class clsJavaVariableChunk {
// native method that prints a return and reads a line
private native String getVariableChunkProfile(String prompt);
static {
System.loadLibrary("clsJavaVariableChunk");
}
public static void main(String args[]) throws IOException {
clsJavaVariableChunk vc = new clsJavaVariableChunk();
String input = vc.getVariableChunkProfile("C:\\JBox\\STS.zip");
System.out.println(input);
}
}

here, static function to load library is the name we would like to name for C++ dll.
static {
System.loadLibrary("clsJavaVariableChunk");
}

2. javac compiler *.class into *.java.








3. javah generate the C++ header.







Now you should have these files.











4. Generate C++ class project in VS2013 and Import *.h file.

a. Create a new C++ class Project
























b. Import *.h file into header




*h, header file should look like this.

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class clsJavaVariableChunk */

#ifndef _Included_clsJavaVariableChunk
#define _Included_clsJavaVariableChunk
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     clsJavaVariableChunk
 * Method:    getVariableChunkProfile
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_clsJavaVariableChunk_getVariableChunkProfile
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

c. Compose the *.cpp file the embedded the function you like.

// This is the main DLL file.

#include "stdafx.h"

#include "clsJavaVariableChunk.h"

#include <jni.h>
#include <string>
#include <iostream>
#include <vector>

using namespace std;
/*
* Class:     clsJavaVariableChunk
* Method:    getVariableChunkProfile
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/

JNIEXPORT jstring JNICALL 
Java_clsJavaVariableChunk_getVariableChunkProfile(JNIEnv *env, jobject obj, jstring clsJavaVariableChunk)
{
string sEntry;
const char *str;
str = env->GetStringUTFChars(clsJavaVariableChunk, NULL);
if (str == NULL) {
return env->NewStringUTF("There is no File Path");
}
else{
cout << str;
//Frees native string resources
env->ReleaseStringUTFChars(clsJavaVariableChunk, str);

//reads n-consecutive words from the 
//keyboard and store them in string
getline(cin, sEntry);

return env->NewStringUTF(sEntry.c_str()); //finally return the string
}
}

d. Add jni reference with in project property





















find the jni.h location which is under include/ and include/win32/

























e. either you run in JVM 32 bit or you can change the compiler for dll into 64 bit.

































f. Now compiler C++ dll





g. Back to Eclipse, create a folder under the project call dll
















h. Drag and drop the dll file to this folder.










i. Change the load dll path with dll folder.
System.loadLibrary("dll//clsJavaVariableChunk");

j. Finally run  the Java to reference C++ dll







6. Others: if you refectory the package name from default to the one you like, you just go to C++ dll source code to change the interface as below.
























If you rename the package name from default to e.g. clsCityHashCalc, you just need to go back VS 2013 and change the interface function name as below.

From:JNIEXPORT jstring JNICALL Java_clsJavaVariableChunk_getVariableChunkProfile



To: JNIEXPORT jstring JNICALL Java_clsCityHashCalc_clsJavaVariableChunk_getVariableChunkProfile

























And re-compiler and the copy & paste new *.dll to eclipse dll folder and it should work with new package name in Java.