Java Native Interface JNI Example Using Visual C++ Cl.exe

Aim
The aim of this JNI tutorial is to use the Java Native Interface JNI to call a pure java callback from a native C++ function. It is slightly more complicated that just calling a native function, but will better demonstrate some of the JNI functionality. We will be using the Visual C++ cl.exe without the IDE to compile the C++ DLL that will contain the JNI implementations. Leave any questions or problems as comments and I will endeavour to answer them.

Assumptions
This article assumes that you have a compatible JDK installed. For purposes of this example the the project directory is JNIExample. Also it is assumed that you have VC++ installed and configured. See Problems and Solutions Installing VC++ Express Edition, to install and run vcvars32.bat.


Versions used in this example
Sofware/ComponentImage
Windows XP SP2N/A
Java j2sdk 1.5N/A
Visual Studio Express Editions 2008 VC++N/A
Links to these files can be found here

The JDK is installed in the "D:\jdk1.5.0" for this example. Please remember to substitute your own directories for these.The files used in this are given below.

JNIExample
_|_JNIExample.java
_|_JNICppImplementation.cpp
_|_CommonDatabasePool.cpp

Write and compile the Java code
  1. Write the javacode and save it as JNIExample.java in your working directory. The SetCallback method will be in the C++ dll and it will in turn call the Callback method. The static keyword is to make sure the dll is loaded once.
     1. import java.util.*;
     2. 
     3. public class JNIExample{
     4.   static{
     5.      try{ 
     6.             System.loadLibrary("jnicpplib");
     7.         }catch(Exception e){
     8.             System.out.println(e.toString());
     9.         }
    10.     }
    11. 
    12.   public native void SetCallback(JNIExample jniexample);
    13. 
    14.   
    15.     public static void main(String args[]){
    16.         (new JNIExample()).go();
    17.     }
    18.     
    19.     public void go(){
    20.         SetCallback(this);
    21.     }
    22.     
    23.   //This will be called from inside the native method    
    24.   public String Callback(String msg){
    25.     return "Java Callback echo:" +msg;
    26.   } 
    27. }
    Hide line numbers
  2. `
  3. Now open a promt to this directory and compile the java code

    ..JNIExample>javac JNIExample.java

  4. Now run javah to create the required header file. This should create the JNIExample.h file.

    ..JNIExample>javah JNIExample

  5. Finally for completeness run the javap command. This command will give you the method signatures. You will need the method signature for Callback in your C++ file.

    ..JNIExample>javap -s JNIExample
    Compiled from "JNIExample.java"
    public class JNIExample extends java.lang.Object{
    public JNIExample();
    Signature: ()V
    public native void SetCallback(JNIExample);
    Signature: (LJNIExample;)V
    public static void main(java.lang.String[]);
    Signature: ([Ljava/lang/String;)V
    public void go();
    Signature: ()V
    public java.lang.String Callback(java.lang.String);
    Signature: (Ljava/lang/String;)Ljava/lang/String;
    static {};
    Signature: ()V
    }

Write and compile the C++ DLL
  1. Create the JNICppImplementation.cpp file. As you can see this maps to the SetCallback function. Also note that we will be calling the Callback funtion in our java class with the char array "hello jni." The this pointer is passed to this native function as classref.
     1. #include "JNIExample.h"
     2. 
     3. 
     4. JNIEXPORT void JNICALL Java_JNIExample_SetCallback (JNIEnv * jnienv, jobject jobj, jobject classref)
     5. {
     6.     jclass jc = jnienv->GetObjectClass(classref);
     7. 
     8.     jmethodID mid = jnienv->GetMethodID(jc, "Callback","(Ljava/lang/String;)Ljava/lang/String;");
     9. 
    10.     jstring result = (jstring)jnienv->CallObjectMethod(classref, mid, jnienv->NewStringUTF("hello jni"));
    11. 
    12.     const char * nativeresult = jnienv->GetStringUTFChars(result, 0); 
    13. 
    14.     printf("Echo from Setcallback: %s", nativeresult);
    15. 
    16.     jnienv->ReleaseStringUTFChars(result, nativeresult);
    17. 
    18. }
    Hide line numbers
    Note that we have included the JNIExample.h file that was generated from javah.

  2. Compile the dll using a command prompt and cl.exe. Make sure you have run vcvars32 prior to this. Also, remember to substitute your local jdk header file directories for the ones below.

    ..JNIExample>cl -o jnicpplib.dll JNICppImplementation.cpp /I D:\jdk1.5.0\include /I D:\jdk1.5.0\include\win32 /link /DLL

Run the example
  1. Open a prompt into your working directory and run the example.

    ..JNIExample>java JNIExample

  2. You should see a message Echo from SetCallback: Java Callback echo:hello jni on your screen. The native method SetCallback calls the java Callback method with the char array "hello jni." The Callback appends Java Callback echo: and returns. The SetCallback then appends Echo from SetCallback: to this and prints it out.

6 comments:

Anonymous said...

you have nice site. thanks for sharing this site. various kinds of ebooks are available here

http://feboook.blogspot.com

Sekar said...

Very good example. I'am impressed.

sharath said...

Hi,
thanks for giving clear explanation along with screen shots

Matthias B├╝chner said...

I created another tutorial about JNI.
It has a video and the JAVA and CPP projects are available for download.

I hope it can help:
http://codebazaar.blogspot.com/2010/08/package-codebazaar.html

Guru said...

very good example...

Dilkhush said...

Hello All,
I have followed all the steps but at the time of creating dll i am facing problem.
I am not able to create dll file using the given command.
For that i tried the following commonds:
used the java class path and execute the commond
C:\JDeveloper\mywork\JNIExample>cl -o jnicpplib.dll C:/JDeveloper/mywork/JNIExample/JNICppImplementation.cpp /C:/Program Files (x86)/Java/jdk1.6.0_30/include /IC:/Program Files (x86)/Java/jdk1.6.0_30/include/win32 /link /DLL

and also rite the path of visual studio and execute following command:
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin>cl -o jnicpplib.dll C:
/JDeveloper/mywork/JNIExample/JNICppImplementation.cpp /C:/Program Files (x86)/J
ava/jdk1.6.0_30/include /IC:/Program Files (x86)/Java/jdk1.6.0_30/include/win32
/link /DLL
I am using visual Studio 2008.
Please guide if i am going wrong.