Click here to Skip to main content
Click here to Skip to main content

How to Call Java Functions from C Using JNI

By , 12 Jan 2008
 

Introduction

This article describes the methodology to use Java code in C/C++. I have not only discussed simple parameter passing and returning, but complex data structures such as structures and structure arrays to Java functions as well.

Background

A few days ago, my manager asked me to write code in C/C++ that will use Java classes in other projects. It took me a lot of time to grab some information on how to call simple functions as well as pass/return complex data types. I found many articles describing C/C++ function calls in Java using JNI, but very few discussing calling Java functions in C/C++ using JNI. At that time, I decided to write an article so that other people could get help from it.

Using the code

The CTest.cpp file contains the code that calls different functions from Java classes. Java classes that are used in this project are given here under:

  • HelloWorld.java
  • ControlDetail.java
  • WorkOrder.java
  • ReturnData.java

HelloWorld.java contains the functions that will be called from CTest.cpp. The other three Java classes are simply used in place of structures in Java. As there is no structure concept in Java, we can use classes for that purpose. That is what the other three .java files contain.

HelloWorld.java contains the following functions that will be called from C/C++ code:

public static void main(String args[])
{
}

public static void TestCall(String szArg)
{
} 

public static int DisplayStruct(ControlDetail ctrlDetail)
{
} 

public static void DisplayStructArray(WorkOrder ArrWO[])
{
} 

public static Object ReturnObjFunc()
{
}

To call these functions from C/C++, first you need to load the JVM using the following function:

JNIEnv* create_vm(JavaVM ** jvm) {
    
    JNIEnv *env;
    JavaVMInitArgs vm_args;

    JavaVMOption options; 
    //Path to the java source code     
    options.optionString = "-Djava.class.path=D:\\Java Src\\TestStruct"; 
    vm_args.version = JNI_VERSION_1_6; //JDK version. This indicates version 1.6
    vm_args.nOptions = 1;
    vm_args.options = &options;
    vm_args.ignoreUnrecognized = 0;
    
    int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
    if(ret < 0)
        printf("\nUnable to Launch JVM\n");       
    return env;
}

Kindly note that to use this code, you will have to modify the options.optionString variable. You will have to set the path of the Java code: where the Java classes are placed. Currently, it being set to D:\Java Src\TestStruct. You can modify it to you situation. You will also need to modify the JDK version information in the above code, as shown below:

vm_args.version = JNI_VERSION_1_6; //JDK version. This indicates version 1.6

Modify it if you have another JDK version installed.

To call a specific Java function from C, you need to do the following:

  1. Obtain the class reference using the FindClass(,,) method.
  2. Obtain the method IDs of the functions of the class that you want to call using the GetStaticMethodID and GetMethodID function calls.
  3. Call the functions using CallStaticVoidMethod, CallStaticIntMethod, and CallStaticObjectMethod.

One important thing to be noted here is specifying the function signatures while obtaining the method IDs.

To obtain the correct method signature, you can use the following Java command:

javap -s -p HelloWorld

It will display you the signature of each function in the HelloWorld class. These signatures can be used to obtain the method IDs. The result of the above command can be seen below:

D:\Java Src\TestStruct>javap -s -p HelloWorld
Compiled from "HelloWorld.java"
public class HelloWorld extends java.lang.Object{
public HelloWorld();
  Signature: ()V
public static void main(java.lang.String[]);
  Signature: ([Ljava/lang/String;)V
public static void TestCall(java.lang.String);
  Signature: (Ljava/lang/String;)V
public static int DisplayStruct(ControlNEDetail);
  Signature: (LControlNEDetail;)I
public static void DisplayStructArray(WorkOrder[]);
  Signature: ([LWorkOrder;)V
public static java.lang.Object ReturnObjFunc();
  Signature: ()Ljava/lang/Object;
}

Kindly note that while specifying the method name in the GetMethodID function, if the method is a constructor, then its method name will be <init>.

Prerequisites

Before traveling down a difficult path, it is important to understand the basic concepts and to have various frameworks and tools installed on your computer.

  1. You will need the Sun Java Developer Kit (JDK). I recommend Java 1.6.0.
  2. Any C/C++ compiler installed.

How to run

To use this code, follow the instructions below:

  • Compile the *.java files using the javac command.
  • Compile the CTest.cpp file using any C++ compiler; I used MSVC++ 6.

Converting this code to pure C from C++

The attached code is written in C++. To convert this code into pure C, you will have to modify the following in the CTest.cpp file:

Use:

(*env)->FunctionName(env,args,..);

instead of:

env->FunctionName(args,..);

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

ajalilqarshi
Software Developer (Senior) Assured Information Systems
United Kingdom United Kingdom
Member
Ahmad Jalil Qarshi is a Software Engineer in Assured Information Systems (a Software solution provider to Pharmaceutical industry, FDA USA and EMEA) in different technologies like .NET, Delphi 2007, XSLT/Schematron.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionCalling Java from C (Mac version)memberJuan Carlos Kuri Pinto5 Apr '13 - 10:49 
Calling Java from C:
https://dl.dropbox.com/u/46434672/Code/JniTest.zip
Questionunable to launch JVM..memberMember 969404429 Jan '13 - 1:58 
HI,
 

I am getting error unable to launch JVM in this code after compiling.
Please tell me where i did wrong ..
QuestiongETTING Error jvm.dll is missing from your computermemberMember 969404429 Jan '13 - 1:10 
Hi
 

When i Compiled VC++ code I got An error "program can't start becouse jvm.dll is missing from your computer " Please tell me what should i do to resolve it .
java 6 and VC++ 2008 are already installed in MY pC.
 

 
Regards
Gupta Rahul
GeneralMy vote of 5memberolivier gg28 Jan '13 - 4:58 
Very easy for getting started. congratulations and thank you.
QuestionUnable to Load native librarymembergupta111saurabh15 Jan '13 - 18:37 
I have set my path variable as below..
 
PATH=D:\oracle\product\10.2.0\client_1\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WIN
DOWS\System32\Wbem;C:\Program Files\IBM\RationalSDLC\ClearCase\bin;C:\Program Fi
les\IBM\RationalSDLC\common;C:\Program Files\TortoiseSVN\bin;D:\jdk1.6.0_31\lib;
D:\jdk1.6.0_31\jre\bin\client;D:\jdk1.6.0_31\bin
 

I have set my include and library path in my project setting...
 
My program has been compiled successfully but unable to execute.
 
It gives the following error while executing the following.
----------------------------------------------------------------
Error occurred during initialization of VM
Unable to load native library: Can't find dependent libraries
----------------------------------------------------------------
 
suggest me the changes...
 
ggggggggggggggggggggggggggggggggggggggggggggggggg
QuestionFindclass fails with a java file including a package in itmemberSadafule24 Apr '12 - 22:42 
The example provided by you is very useful and it has worked wonders for me . Now the problem is that if I am using a Java file with a package included in it but then the findclass function returns nothing so what changes should a make in the java file as its important for me to include the package.
QuestionJNI_CreateJavaVM fails with -1memberAnneanne124 Nov '11 - 5:33 
I get -1 when i`m trying to run the
JNI_CreateJavaVM,
I feel like i have tried everything with pats, please help me figure this out! That would be appreciated!Smile | :)
 

code:
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
 
args.version = JNI_VERSION_1_4; // JNI_VERSION_1_2 is interchangeable for this example
args.nOptions = 1;
options[0].optionString = "-Djava.class.path=:C://i have put the Path to the java sourcecode here
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
int en = JNI_CreateJavaVM(&jvm, (void **)&env, &args) // THIS RETURNS -1
 
PATH:
C:\Program Files\Java\jdk1.6.0_27\jre\bin\client;C:\Modeltech_pe_edu_10.0c\win32pe_edu;C:\Program Files\Java\jdk1.6.0_27\bin;;C:\Windows\System32\jvm.lib;C:\Program Files\Java\jdk1.6.0_27\jre\bin;C:\Program Files\Java\jre6\bin\client\jvm.dll;C:\Program Files\Java\jdk1.6.0_27\lib;C:\Program Files\Java\jre6\bin\client;\jvm.lib
 
system Path: C:\Program Files\Java\jdk1.6.0_18\jre\bin\client; Live\Shared;C:\VXIPNP\WinNT\Bin\VXIPNP\WinNT\Binnnn;%ANT_HOME%\binVXIPNP\WinNT\Bin\VXIPNP\WinNT\Bin;%ANT_HOME%\binVXIPNP\WinNT\Bin\VXIPNP\WinNT\Binn;%ANT_HOME%\binVXIPNP\WinNT\Bin\VXIPNP\WinNT\Bin;%ANT_HOME%\binVXIPNP\WinNT\Bin\VXIPNP\WinNT\Binnnn;%ANT_HOME%\binVXIPNP\WinNT\Bin\VXIPNP\WinNT\Bin;%ANT_HOME%\binVXIPNP\WinNT\Bin\VXIPNP\WinNT\Binn;%ANT_HOME%\binVXIPNP\WinNT\Bin\VXIPNP\WinNT\Bin;%ANT_HOME%\bin;%JAVA_HOME%\bin;%ANT_HOME%\bin;%JAVA_HOME%\bin;%ANT_HOME%\bin;%JAVA_HOME%\bin;%ANT_HOME%\bin;%JAVA_HOME%\bin;%SystemRoot%\System32;%SystemRoot%;%SystemRoot%\System32\Wibem\;C:\Program Files\Java\jdk1.6.0_27\jre\bin\client
 
JAVA_HOME: C:\Program Files\Java\jdk1.6.0_27;C:\Program Files\Java\jdk1.6.0_27\jre\bin\server;C:\Program Files\Java\jdk1.6.0_27\jre\bin\client
 
Regards Ann
AnswerRe: JNI_CreateJavaVM fails with -1memberMember 839413515 Nov '11 - 2:59 
Have you created your java classes? options[0].optionString should have the location of the java class files rather than java sources.
QuestionJNI_CreateJavaVM doesn't workmemberAngryCats27 Sep '11 - 20:45 
I've compiled and built the program without errors, but the program quits when it gets to the line:
 
int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
 
which is in the method:
 
JNIEnv* create_vm(JavaVM ** jvm)
 
There are no error messages of any kind, it just doesn't work. I've used some print statements which appear in the console box and break points to find where exactly it stops and I'm pretty sure it's that line. The Output tab shows this:
 
'CTest.exe': Loaded 'G:\UniPrograms\VsProjects\src_CJNIJava\CTest\Debug\CTest.exe', Symbols loaded.
'CTest.exe': Loaded 'C:\Windows\System32\ntdll.dll'
'CTest.exe': Loaded 'C:\Windows\System32\kernel32.dll'
'CTest.exe': Loaded 'G:\UniPrograms\VsProjects\src_CJNIJava\CTest\jvm.dll'
'CTest.exe': Loaded 'C:\Windows\System32\user32.dll'
'CTest.exe': Loaded 'C:\Windows\System32\gdi32.dll'
'CTest.exe': Loaded 'C:\Windows\System32\advapi32.dll'
'CTest.exe': Loaded 'C:\Windows\System32\rpcrt4.dll'
'CTest.exe': Loaded 'C:\Windows\System32\wsock32.dll'
'CTest.exe': Loaded 'C:\Windows\System32\ws2_32.dll'
'CTest.exe': Loaded 'C:\Windows\System32\msvcrt.dll'
'CTest.exe': Loaded 'C:\Windows\System32\nsi.dll'
'CTest.exe': Loaded 'C:\Windows\System32\winmm.dll'
'CTest.exe': Loaded 'C:\Windows\System32\ole32.dll'
'CTest.exe': Loaded 'C:\Windows\System32\oleaut32.dll'
'CTest.exe': Loaded 'C:\Windows\System32\oleacc.dll'
'CTest.exe': Loaded 'C:\Windows\System32\psapi.dll'
'CTest.exe': Loaded 'C:\Windows\System32\msvcr100.dll', Symbols loaded.
'CTest.exe': Loaded 'C:\Windows\System32\imm32.dll'
'CTest.exe': Loaded 'C:\Windows\System32\msctf.dll'
'CTest.exe': Loaded 'C:\Windows\System32\lpk.dll'
'CTest.exe': Loaded 'C:\Windows\System32\usp10.dll'
The program '[5096] CTest.exe: Native' has exited with code 1 (0x1).
 
I'm using Microsoft Visual Studio 2008 and Windows Vista.
 
If anyone has any ideas, please let me know.
AnswerRe: JNI_CreateJavaVM doesn't workmembercarterza11 Jan '12 - 14:39 
I have the exact same problem... Using VS 2010 and Windows 7.
GeneralRe: JNI_CreateJavaVM doesn't workmemberlingjia zeng7 Dec '12 - 3:37 
I'm having the same problem too.
VS 2010 and Windows 7.
AnswerRe: JNI_CreateJavaVM doesn't workmemberm2e10 Dec '12 - 13:07 
Hello,
i have a guess why
try "ret = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);" i think there have to be a "&" before "jvm"
Please let me know if it helps you out.
best regards m2e
GeneralRe: JNI_CreateJavaVM doesn't workmemberMoorthy Rajendran19 Feb '13 - 18:48 
tcc: undefined symbol JNI_CreateJavaVM@12 .i m getting this issue. please help me out.
QuestionGood but need other fixesmemberMember 369901527 Sep '11 - 6:35 
1- After some other bugs already discussed in this thread, there are also other memory leak problems:
 
All references to env->NewStringUTF or similar construction must be released after used, or a memory leak will occur
 
snippet 1:
 
            jstring StringArg = env->NewStringUTF("\nTestCall:Called from the C Program\n");
     //Calling another static method and passing string type parameter
     env->CallStaticVoidMethod(clsH,midCalling,StringArg);
 
snippet 1 workaround should be:
 
            jstring StringArg = env->NewStringUTF("\nTestCall:Called from the C Program\n");
     //Calling another static method and passing string type parameter
     env->CallStaticVoidMethod(clsH,midCalling,StringArg);
            env->DeleteLocalRef(StringArg);
 
The memory leak can be easily seen if looping this snippet 1 sequence for a long long time, the NewStringUTF will return null after some times (after 2,700,000 loops on my system). This can also be seen under windows by looking at free memory melting constantly under task manager. When the workaround is used, this problem does not happens anymore...
GeneralMy vote of 4memberMember 369901527 Sep '11 - 6:18 
Very good but some bugs to fix
GeneralIs there a wrapper generator (like swig but the other way round)?memberEulenspiegel5 May '11 - 22:01 
The example gave me the missing link while searching for a way to use Java-classes/code from inside C/C++-programs. Thanks!
 
Now I'm still searching for a wrapper-generator that is able to generate the C++-Interface and mapping-code from a set of Java-classfiles.
The other way round (calling C/C++ from inside Java) 'swig' ist the tool to do this.
There are many more wrapper-generator besides swig but they all only wrap native code to Java.
 
Does anyone have any suggestions?
 
Thanks
Ulf
GeneralA good sample but need fix a few pointsmemberMember 257456113 Apr '11 - 16:12 
thank you for your sample.
But I meet some problem while compiling the sample code under WindowsXp though at last success run it.
So I just write here for others:
1. ControlNEDetail.java should be rename to ControlDetail.java
2. under "Java Src\TestStruct" directory, call "javac *.java" to generate class files
3. add include and link path to the project settings
4. add jvm.dll path(like d:\Java\jdk1.6.0_24\jre\bin\client) to PATH
GeneralRe: A good sample but need fix a few pointsmemberAngryCats28 Sep '11 - 1:25 
I noticed that too.
 
By the way I don't THINK the jvm.dll is needed. Including the path seems to give errors - memory location (of file) is corrupted and similar. No idea what to do about it though. My program suddenly started compiling successfully without including the jvm, but I've got a different error now (see post above).
QuestionUnable to find the requested classmemberarnott0722 Mar '11 - 5:23 
I am trying to run this example in linux and am getting the error message:
 
Unable to find the requested class.
 
It looks the classpath is not being set correctly. Is this is a valid path : "/home/username/java/JNI/JavaSrc/TestStruct/src" ? I got previous classpath (getenv("CLASSPATH");) from and added it to the classpath when creating the JVM, and am still getting the above error message when accessing the HelloWorld class (clsH = env->FindClass("HelloWorld");), clsH is null.
 
what am I doing wrong ? How do I debug this ?
 
Thanks
arnott
AnswerRe: Unable to find the requested classmemberMember 257456113 Apr '11 - 16:06 
you need call javac to compile these .java files to generate .class files
and don't forget to rename ControlNEDetail.java to ControlDetail.java
QuestionHow to debug jni code [modified]memberG Mahesh Babu31 Jan '11 - 22:04 
how can i debug jni code....so that i can see variable values at run time Smile | :)
One more doubt..
if my signature of java method is as shown below
Signature: (Ljava/lang/String;)[Ljava/lang/String;
 
then how to call that method like for example CallVoidMethod
how to handle return values

modified on Wednesday, February 2, 2011 2:01 AM

GeneralI can´t compile the cpp codememberrolotandil5 Oct '10 - 9:51 
Hi,
I have the .c code from the example.
I run this command for compile:g++ -o Invoke -I<.h files path> -L\jvm.lib -L\jvm.dll Invoke.cpp
 
I tried without -L\jvml.dll or put only -L
 
And I get the same error:
reference to _imp_JNI_CreateJavaVM@12 is undefined
 
reference to WinMain@16 is undefined
 
I use minGW as a gcc compiler for windows.
 
Regards
Rodrigo
GeneralMy vote of 5memberT.Balaji4 Aug '10 - 19:51 
Excellent explanation of his code...
GeneralMy vote of 5membercdk28 Jul '10 - 7:06 
This is by far one of the best articles I have ever come across.
GeneralMy vote of 2member-midiman-19 Apr '10 - 5:25 
not great

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 13 Jan 2008
Article Copyright 2008 by ajalilqarshi
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid