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   
GeneralRe: Thanks! Comments on getting to run under GNU/Linuxmemberajalilqarshi12 Apr '10 - 10:53 
Thanks Laurence,
 
The information you provided is very useful for other people because 80% of people who try to use this code face compilation problem. Your comments will help them.
 
Thanks again.
Ahmad Jalil Qarshi
GeneralRe: Thanks! Comments on getting to run under GNU/LinuxmemberLaurence Finston12 Apr '10 - 21:13 
Thank you, Ahmad.
 
I've started working through your example slowly.   If I think of anything I think might be helpful, I'll post it here.
 
One thing I'm not sure about is how it would work to call the non-static methods.   (I'm much more familiar with C and C++ than Java.)
 
Correction:
 
I wrote:
 
"`find' searches starting in the working directory and working its way downward."
 
This is false.   It starts at the directory given in the first argument and works its way downward.
In the example, I wrote `find . -name "<name>"', where `.' refers to the working directory.   An absolute or relative path could be used instead, e.g., `find /usr/local/ -name "some.file"'.
 
Laurence
GeneralRe: Thanks! Comments on getting to run under GNU/LinuxmemberLaurence Finston12 Apr '10 - 22:54 
A couple more notes on compiling under GNU/Linux with GCC:
 
There are some things that are specific to Microsoft (or .NET?) and can be removed:
 
In CTest.cpp:
 
The line
 
#include "StdAfx.h"
 
can be removed or commented-out.
 
The following files are not needed:
 
CTest.dsp
CTest.dsw
CTest.ncb
CTest.plg
StdAfx.cpp
StdAfx.h
CTest.opt
 
Nor is the directory `Debug/'.
 
I got the following warning:
 
In function ‘JNIEnv* create_vm(JavaVM**)’:
   CTest.cpp:39: warning: deprecated conversion from string constant to ‘char*’
 
To get rid of it, all you have to do is add the following line outside of any function before the
definition of `create_vm':
 
char temp_str[] = "-Djava.class.path=<Your path>";
 
e.g.,
 
char temp_str[] = "-Djava.class.path=/home/some_user/jni_test/Java_Src/TestStruct";
 
Then, in the definition of `create_vm', set `options.optionString' this way:
 
options.optionString = temp_str; // Path to the java source code
 
`JavaVMOption' is declared like this in `jni.h':
 
typedef struct JavaVMOption {
      char *optionString;
      void *extraInfo;
} JavaVMOption;
 
That is, `JavaVMOption.optionString' is a pointer to `char' and no memory has been reserved for the string it's supposed to point to.   Declaring `temp_str' as a character array causes memory to be reserved in static storage, which will exist until the process finishes.   The assignment `options.optionString = temp_str;' stores the _address_ of `temp_str' in the pointer object `options.optionString'.
 
Laurence
GeneralRe: Thanks! Comments on getting to run under GNU/LinuxmemberLaurence Finston13 Apr '10 - 0:20 
I wrote:   "One thing I'm not sure about is how it would work to call the non-static methods."
 
This is no problem at all!
 
In `class ControlDetail', I added following method:
 
public int test_func()
{
   System.out.println("\nThis is `ControlDetail::test_func'.\n");
   return 202;
}
 

Then, get the method ID in the `main' function of the C or C++ program.   The following lines can be put near the similar declarations and calls to functions for the |ControlDetail| class or the |jobject jobjDet| object, respectively.
 
jmethodID mid_CtrlDet_test_func = NULL;   /* |ControlDetail::test_func|   */
 
mid_CtrlDet_test_func = env->GetMethodID(clsC, "test_func", "()I");
 
jint i = env->CallIntMethod(jobjDet, mid_CtrlDet_test_func);
 
cerr << "Return value of `mid_CtrlDet_test_func' is " << i << endl;   /* Using C++ stream output here   */
 
Thanks again for your very helpful example, Ahmad.
 
Laurence
GeneralRe: Thanks! Comments on getting to run under GNU/Linuxmemberkna261118 Aug '10 - 12:04 
Hello,
Should I create a header file and a .so file linking Java and C libraries to run this?
Because, I compiled the Java file, got its .class and compiled the C file and got its .o file. Now, when I try running the.o file (to get a .out file), I am getting an error like below,
 
CTest.o: In function `create_vm(_Jv_JavaVM**)':
CTest.cppFrown | :( text+0x41): undefined reference to `JNI_CreateJavaVM'
CTest.oFrown | :( eh_frame+0x12): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
 
My knowledge of coding is not much but I have to link Fortran to Java through a C interface to complete my thesis.
Appreciate any help.
Thanks in advance,
With best regards,
KNA
(I am using linux fedora 64 bit machine and C compiler)
GeneralRe: Thanks! Comments on getting to run under GNU/LinuxmemberLaurence Finston18 Aug '10 - 21:36 
> Should I create a header file and a .so file linking
> Java and C libraries to run this?
 
No, you don't need to create a header file, nor is there   any need to create a shared library (.so) file.
 
The first message says that the function `JNI_CreateJavaVM' is undefined.   This probably means you're not linking with the library that contains the definition (presumably `libjvm').   It may be located in another place than on my system.   Just have a look around and/or use `find' (look for `libjvm*.so').
 
Linking with an object file created from FORTRAN code shouldn't be too difficult.   You just need to compile it separately from the C program and declare function in the latter, specifying "FORTRAN" linkage, i.e., including "Fortran" or "FORTRAN" in the declaration.   I've never actually done this, but only read how to do it, and I don't remember the exact syntax.   A quick search in the internet or the GCC manual should tell you how to do this.
 
Then, link the object files.   In the example I gave, I compiled and linked in one step, but it's not any more difficult to compile and link in two steps.   The `-I' and `-L' options are needed for compiling and the `-l' option for linking.
 
> CTest.oFrown | :( eh_frame+0x12): undefined reference to
> `__gxx_personality_v0'
 
I don't know what this is about.   I believe it has something to do with the fact that GCC is used to compile various languages, so one back-end has various "personalities", i.e., one for FORTRAN, one for Pascal, etc.   gxx is for C++.   C++ is a bit different, because a C++ compiler (and linker) must do considerably more compilicated things than a compiler and linker for C, Fortran or Pascal.   Are you sure gxx is installed?   Does it work to compile a trivial C++ program?
 
Otherwise, it's possible that this error might have something to do with the first one, and if you correct that one, this error might disappear.   Otherwise, I'd try searching the internet to see if this error has been discussed somewhere.
 
I hope this helps.
 
Laurence
GeneralRe: Thanks! Comments on getting to run under GNU/LinuxmemberLaurence Finston18 Aug '10 - 21:47 
CTest.oFrown | :( eh_frame+0x12): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
 
It just occurred to me that I've had a similar error message when the compiler couldn't tell from the extension of the filename whether it was C or C++.   In this case, I would expect it to recognize that `.cpp' should be C++, but it wouldn't do any harm to change it to `.cxx' or use the `-x <language>' option, i.e., `-x c++'.
 
Laurence
GeneralThanks!memberAlex Kolesnichenko6 Mar '10 - 12:05 
Your article gave me some ideas to fix my code, which I was struggling with for several hours already.
QuestionJNI load error - main class not foundmemberalien_invader1 Mar '10 - 11:17 
i have build a c++ dll via visual studio 2005, which i call by a jar-file and it works perfect on my computer also having the files on a usb-stick.
i tried several other computers and usually i get the message " main class not found ", which i suppose happens because the loading of the dll fails.
I´m not a professional programmer, but i´m quite sure the problem is connected with visual studio. the only other maschine my jar and dll worked was also equipped with visual studio.
there are loads of settings in the vc-project properties, which are hard for me to understand.
does anyone know, what is the problem and help me out.
AnswerRe: JNI load error - main class not foundmemberalien_invader26 Apr '10 - 9:27 
sorry, this was trivial. i just had to run the code in vs in release and not in debug mode.
GeneralMy application crashes while calling JNI_CreateJavaVM functionmemberKhalid Noor21 Feb '10 - 23:06 
I have resolved all errors by adding addition library & include files.
Application is compiling without errors but after execution it crashes while
making a call to JNI_CreateJavaVM function.
 
Please help me on urgent basis.
GeneralRe: My application crashes while calling JNI_CreateJavaVM functionmemberajalilqarshi22 Feb '10 - 2:28 
Could you please post the details of version of JDK and your working environment.
Also post the changes you made in the code.
Regards,
Qarshi
GeneralRe: My application crashes while calling JNI_CreateJavaVM functionmemberKhalid Noor23 Feb '10 - 1:15 
I placed my exe in same directory where jvm.dll is (C:\Program Files\Java\jdk1.6.0\jre\bin\client), now it is working.Y it is not working when i put the jvm.dll in my debug folder.?
 
Can u please also guide me how can i call my class & methods from .jar file.
GeneralRe: My application crashes while calling JNI_CreateJavaVM functionmemberajalilqarshi23 Feb '10 - 2:13 
Please add the jvm.dll file path in your environment variable (i.e. PATH ).
The reason now its working is because it found the jvm.dll file in the working folder.
All the executables (On Windows) search for some required library in following order:
 
The directory from which the application loaded. i.e. the Working folder.
The system directory.
The Windows directory.
The directories that are listed in the PATH environment variable.
 
As far as calling the class methods from a .jar method is concerned, yes you can. I haven't tried it personally but I am sure you can.
After making a .jar file execute the following command to see the contents of the jar file. Now while calling the FindClass function pass the path found the contents of following command:
jar tvf MyJar.jar
 
Suppose the path found for your class in the above jar file is "org/MyLibs/MyClass.class"
When you will be calling a FindClass function do as below:
(*env)->FindClass("org/MyLibs/MyClass");
 
I haven't tested it because I don't have any C compiler on my machine. So hopefully it will help.
 
Regards,
Ahmad Qarshi
GeneralRe: My application crashes while calling JNI_CreateJavaVM function [modified]memberKhalid Noor23 Feb '10 - 19:27 
Thankyou for all of your support.
 
We have a method in our java class with following signature
 
void SomeMethod(int systemId,set < java.io.file > files,int prefPos)
 
Can u please guide us how can we pass set < java.io.file > files parameter from c++ to java method.
modified on Wednesday, February 24, 2010 8:42 AM

GeneralRe: My application crashes while calling JNI_CreateJavaVM functionmemberMember 41280638 Mar '11 - 0:20 
Hi,
I tried with this example, But i am getting same issue. If i copy C exe in JDK Folder it works else it raise Exception JVM initilisation error.
I read the above thread and try setting environment veriables but same results.
Can you please help me out in understanding the
 
The directory from which the application loaded. i.e. the Working folder.
The system directory.
The Windows directory.
The directories that are listed in the PATH environment variable.
 
Where and what need to set.
I am using Visual studio 2005 VC++ Compiler professional edition.
Saurabh Vashistha

GeneralRe: My application crashes while calling JNI_CreateJavaVM functionmemberpratikmota9 May '11 - 22:55 
hi friend,
 

I am facing problem to call Java method from C++ project.
 

      JNIEnv *env;
      JavaVMInitArgs vm_args;
      JavaVMOption options;
      options.optionString = "-Djava.class.path=D:\\Java Src\\TestStruct";
      vm_args.version = JNI_VERSION_1_6;
      vm_args.nOptions = 1;
      vm_args.options = &amp;options;
      vm_args.ignoreUnrecognized = 0;
     
      int ret = JNI_CreateJavaVM(jvm, (void**)&amp;env, &amp;vm_args);   ///////Stop from here when running C++ proj.... what to do ???
 
      if(ret &lt; 0)
           printf("\nUnable to Launch JVM\n");       
     return env;
 

 

Need help...... plz
GeneralSOLVED: Error message: "Can't find dependent libraries" [modified]membertsjakkaa29 Jan '10 - 2:25 
(Solution is at the end of the article)
 
Hi,
 
first of all thank you for your effort to write this article.
I'm glad I found this one because it seems that not many articles
about this theme exist in the internet
 
I do have some third party java code which I'd like to include in
my cpp project so your example hits the problem very good.
 
Compiling your example however I get the following error message:
 
-------------------------------------------------------------
Error occurred during initialization of VM
Unable to load native library: Can't find dependent libraries
-------------------------------------------------------------
 
I did configure the options.optionString correctly.
 
What do you mean by:
#define USER_CLASSPATH "." /* where Prog.class is */
 
Do I have to adapt this somehow?
 
Thank you for your help!
 
Bye bye,
 
Roland
 

Bye the way, I'm using
- jdk1.6.0_18 and
- Microsoft Visual C++ 6.0 as you did in your example under
- Windows Vista XP Professional Version 2002 Service Pack 3
 

 
### Solution ###
 
So, the solution was to set "C:\Program Files\Java\jdk1.6.0_18\jre\bin\client"
in the PATH environment variable Smile | :)
 
Again, thank you for your article!!!
 
modified on Friday, January 29, 2010 9:16 AM

Generalhelp me to sort out the error [modified]membershariqmohd26 Jan '10 - 17:06 
I m trying to run the given program but one error comes that is
 
c:\users\mohd\documents\visual studio 2008\projects\ctest\ctest.cpp(3) : fatal error C1083: Cannot open include file: 'jni.h': No such file or directory
Confused | :confused:
 
the jni.h file is not found
 
please help me to sort out this problem...
 
tnx in advance...
 
modified on Tuesday, January 26, 2010 11:18 PM

GeneralRe: help me to sort out the errormemberajalilqarshi27 Jan '10 - 13:09 
HI,
 
Add the C:\Java\jdk1.6.0_18\include and C:\Java\jdk1.6.0_18\include\win32 in the "Additional Include Directories" of your project properties under C/C++\General.
 
Also add the jvm.lib to the additional libraries.
QuestionNot working for me ...... pls help!!!memberkumarmukt20 Jan '10 - 3:20 
hi friend ... I got a compile time error. its saying ....
 
/tmp/cc06USvM.o: In function `create_vm':
CTest.cFrown | :( text+0x3a): undefined reference to `JNI_CreateJavaVM'
collect2: ld returned 1 exit status
 
I am using your c version code(after making the suggested change ).
 
even for c++ code ... getting similar type of error. This is what i am getting in c++ ...
 
/tmp/cc1Vr5Ol.o: In function `create_vm(JavaVM_**)':
CTest.cppFrown | :( text+0x3a): undefined reference to `JNI_CreateJavaVM'
/tmp/cc1Vr5Ol.oFrown | :( eh_frame+0x11): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
 
I have jdk1.6.0_18. I compile the code with given command in linux os.
 
gcc -I /usr/java/jdk1.6.0_18/include -I /usr/java/jdk1.6.0_18/include/linux CTest.c
 
here is the modified code ......
 

#include "StdAfx.h"
#include <stdio.h>
#include "jni.h"
#include <string.h>
 
#define PATH_SEPARATOR ';' /* define it to be ':' on Solaris */
#define USER_CLASSPATH "." /* where Prog.class is */
 
struct ControlDetail
{
int ID;
char Name[100];
char IP[100];
int Port;
};
 
struct WorkOrder
{
char sumSerialId[20];
char accessNumber[18];
char actionType[4];
char effectiveDate[24];
char fetchFlag[2];
char reason[456];
char accessSource[100];
};
 

JNIEnv* create_vm(JavaVM ** jvm) {

JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options;
// options.optionString = "-Djava.class.path=D:\\Java Src\\TestStruct"; //Path to the java source code
options.optionString = "-Djava.class.path=/home/mukesh/c_room/Java Src/TestStruct"; //Path to the java source code
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;
}
 
int main(int argc, char* argv[])
{
JNIEnv *env;
JavaVM * jvm;
env = create_vm(&jvm);
if (env == NULL)
return 1;

struct ControlDetail ctrlDetail;
ctrlDetail.ID = 11;
strcpy(ctrlDetail.Name,"HR-HW");
strcpy(ctrlDetail.IP,"10.32.164.133");
ctrlDetail.Port = 9099;

printf("Struct Created in C has values:\nID:%d\nName:%s\n IP:%s\nPort:%d\n",ctrlDetail.ID,ctrlDetail.Name,ctrlDetail.IP,ctrlDetail.Port);
 
/********************************************************/
struct WorkOrder WO[2];
strcpy(WO[0].sumSerialId,"2000");
strcpy(WO[0].accessNumber,"2878430");
strcpy(WO[0].actionType,"04");
strcpy(WO[0].effectiveDate,"25-12-2007 12:20:30 PM");
strcpy(WO[0].fetchFlag, "0");
strcpy(WO[0].reason,"Executed Successfully");
strcpy(WO[0].accessSource,"PMS");
strcpy(WO[1].sumSerialId,"1000");
strcpy(WO[1].accessNumber,"2878000");
strcpy(WO[1].actionType,"T4");
strcpy(WO[1].effectiveDate,"25-12-2007 11:20:30 PM");
strcpy(WO[1].fetchFlag,"0");
strcpy(WO[1].reason,"");
strcpy(WO[1].accessSource,"RMS");
 

jclass clsH=NULL;
jclass clsC = NULL;
jclass clsW = NULL;
jclass clsR = NULL;
jmethodID midMain = NULL;
jmethodID midCalling = NULL;
jmethodID midDispStruct = NULL;
jmethodID midDispStructArr = NULL;
jmethodID midRetObjFunc = NULL;
jmethodID midCtrlDetConst = NULL;
jmethodID midWoConst = NULL;

jobject jobjDet = NULL;
jobject jobjRetData = NULL;
jobjectArray jobjWOArr = NULL;

//Obtaining Classes
clsH = (*env)->FindClass(env, "HelloWorld");
clsC = (*env)->FindClass(env, "ControlDetail");
clsW = (*env)->FindClass(env, "WorkOrder");

//Obtaining Method IDs
if (clsH != NULL)
{
midMain = (*env)->GetStaticMethodID(env, clsH, "main", "([Ljava/lang/String;)V");
midCalling = (*env)->GetStaticMethodID(env, clsH,"TestCall","(Ljava/lang/String;)V");
midDispStruct = (*env)->GetStaticMethodID(env, clsH,"DisplayStruct","(LControlDetail;)I");
midDispStructArr = (*env)->GetStaticMethodID(env, clsH,"DisplayStructArray","([LWorkOrder;)V");
midRetObjFunc = (*env)->GetStaticMethodID(env, clsH,"ReturnObjFunc","()Ljava/lang/Object;");
}
else
{
printf("\nUnable to find the requested class\n");
}
if(clsC != NULL)
{
//Get constructor ID for ControlDetail
midCtrlDetConst = (*env)->GetMethodID(env, clsC, "<init>", "(ILjava/lang/String;Ljava/lang/String;I)V");
}
else
{
printf("\nUnable to find the requested class\n");
}
 
if(clsW != NULL)
{
//Get Constructor ID for WorkOrder
midWoConst = (*env)->GetMethodID(env, clsW, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
}
else
{
printf("\nUnable to find the requested class\n");
}
 
/************************************************************************/
/* Now we will call the functions using the their method IDs */
/************************************************************************/
if(midMain != NULL)
(*env)->CallStaticVoidMethod(env, clsH, midMain, NULL); //Calling the main method.

if (midCalling!=NULL)
{
jstring StringArg = (*env)->NewStringUTF(env, "\nTestCall:Called from the C Program\n");
//Calling another static method and passing string type parameter
(*env)->CallStaticVoidMethod(env, clsH,midCalling,StringArg);
}

printf("\nGoing to Call DisplayStruct\n");
if (midDispStruct!=NULL)
{
if(clsC != NULL && midCtrlDetConst != NULL)
{
jstring StringArgName = (*env)->NewStringUTF(env, ctrlDetail.Name);
jstring StringArgIP = (*env)->NewStringUTF(env, ctrlDetail.IP);

//Creating the Object of ControlDetail.
jobjDet = (*env)->NewObject(env, clsC, midCtrlDetConst, (jint)ctrlDetail.ID, StringArgName, StringArgIP, (jint)ctrlDetail.Port);
}

if(jobjDet != NULL && midDispStruct != NULL)
(*env)->CallStaticIntMethod(env, clsH,midDispStruct,jobjDet); //Calling the method and passing ControlDetail Object as parameter
}
//Calling a function from java and passing Structure array to it.
printf("\n\nGoing to call DisplayStructArray From C\n\n");
if (midDispStructArr!=NULL)
{
if(clsW != NULL && midWoConst != NULL)
{
//Creating the Object Array that will contain 2 structures.
jobjWOArr = (jobjectArray)(*env)->NewObjectArray(env, 2,clsW,
(*env)->NewObject(env, clsW, midWoConst,
(*env)->NewStringUTF(env, ""),
(*env)->NewStringUTF(env, ""),
(*env)->NewStringUTF(env, ""),
(*env)->NewStringUTF(env, ""),
(*env)->NewStringUTF(env, ""),
(*env)->NewStringUTF(env, ""),
(*env)->NewStringUTF(env, "")));
//Initializing the Array
int i = 0;
for(i=0;i<2;i++)
{
(*env)->SetObjectArrayElement(env, jobjWOArr,i,
(*env)->NewObject(env, clsW, midWoConst,
(*env)->NewStringUTF(env, WO[i].sumSerialId),
(*env)->NewStringUTF(env, WO[i].accessNumber),
(*env)->NewStringUTF(env, WO[i].actionType),
(*env)->NewStringUTF(env, WO[i].effectiveDate),
(*env)->NewStringUTF(env, WO[i].fetchFlag),
(*env)->NewStringUTF(env, WO[i].reason),
(*env)->NewStringUTF(env, WO[i].accessSource)));
}
}
//Calling the Static method and passing the Structure array to it.
if(jobjWOArr != NULL && midDispStructArr != NULL)
(*env)->CallStaticVoidMethod(env, clsW,midDispStructArr,jobjWOArr);
}
//Calling a Static function that return an Object
if (midRetObjFunc != NULL)
{
//Calling the function and storing the return object into jobject type variable
//Returned object is basically a structure having two fields (string and integer)
jobjRetData = (jobject)(*env)->CallStaticObjectMethod(env, clsH,midRetObjFunc,NULL);
//Get the class of object
clsR = (*env)->GetObjectClass(env, jobjRetData);
//Obtaining the Fields data from the returned object
jint nRet = (*env)->GetIntField(env, jobjRetData,(*env)->GetFieldID(env, clsR,"returnValue","I"));
jstring jstrLog = (jstring)(*env)->GetObjectField(env, jobjRetData,(*env)->GetFieldID(env, clsR,"Log","Ljava/lang/String;"));
const char *pLog = (*env)->GetStringUTFChars(env, jstrLog,0);

printf("\n\nValues Returned from Object are:\nreturnValue=%d\nLog=%s",nRet,pLog);
//After using the String type data release it.
(*env)->ReleaseStringUTFChars(env, jstrLog,pLog);
}
//Release resources.
int n = (*jvm)->DestroyJavaVM(jvm);
return 0;
}
 

 
Thanking you
Mukesh Kumar
GeneralRE: How to Call Java functions from C Using JNImemberchinmaya.mishra961 Aug '09 - 6:46 
Hi,
 
I compiled the CTest.cpp. But I got error that "unable to open StdAfx.h and jni.h ". Can any body help me?
 

I am attaching the Source code:
 
CTest.cpp
===========
 
#include "StdAfx.h"
#include &lt;stdio.h&gt;
#include &lt;jni.h&gt;
#include &lt;string.h&gt;
 
#define PATH_SEPARATOR ';' /* define it to be ':' on Solaris */
#define USER_CLASSPATH "." /* where Prog.class is */
 
struct ControlDetail
{
     int ID;
     char Name[100];
     char IP[100];
     int Port;
};
 
struct WorkOrder
{
     char          sumSerialId[20];    
     char          accessNumber[18];
     char          actionType[4];
     char          effectiveDate[24];
     char          fetchFlag[2];
     char          reason[456];
     char          accessSource[100];    
};
 

JNIEnv* create_vm(JavaVM ** jvm) {
    
      JNIEnv *env;
      JavaVMInitArgs vm_args;
      JavaVMOption options;
      options.optionString = "-Djava.class.path=D:\\Java Src\\TestStruct"; //Path to the java source code
      vm_args.version = JNI_VERSION_1_5; //JDK version. This indicates version 1.5
      vm_args.nOptions = 1;
      vm_args.options = &amp;options;
      vm_args.ignoreUnrecognized = 0;
     
      int ret = JNI_CreateJavaVM(jvm, (void**)&amp;env, &amp;vm_args);
      if(ret &lt; 0)
           printf("\nUnable to Launch JVM\n");       
     return env;
}
 
int main(int argc, char* argv[])
{
     JNIEnv *env;
     JavaVM * jvm;
     env = create_vm(&amp;jvm);
     if (env == NULL)
          return 1;
         
     struct ControlDetail ctrlDetail;    
     ctrlDetail.ID = 11;
     strcpy(ctrlDetail.Name,"HR-HW");
     strcpy(ctrlDetail.IP,"10.32.164.133");
     ctrlDetail.Port = 9099;
    
     printf("Struct Created in C has values:\nID:%d\nName:%s\n IP:%s\nPort:%d\n",ctrlDetail.ID,ctrlDetail.Name,ctrlDetail.IP,ctrlDetail.Port);
 
     /********************************************************/
     struct WorkOrder WO[2];
     strcpy(WO[0].sumSerialId,"2000");
     strcpy(WO[0].accessNumber,"2878430");
     strcpy(WO[0].actionType,"04");
     strcpy(WO[0].effectiveDate,"25-12-2007 12:20:30 PM");
     strcpy(WO[0].fetchFlag, "0");
     strcpy(WO[0].reason,"Executed Successfully");
     strcpy(WO[0].accessSource,"PMS");
     strcpy(WO[1].sumSerialId,"1000");
     strcpy(WO[1].accessNumber,"2878000");
     strcpy(WO[1].actionType,"T4");
     strcpy(WO[1].effectiveDate,"25-12-2007 11:20:30 PM");
     strcpy(WO[1].fetchFlag,"0");
     strcpy(WO[1].reason,"");
     strcpy(WO[1].accessSource,"RMS");
 
    
      jclass clsH=NULL;
      jclass clsC = NULL;
      jclass clsW = NULL;
     jclass clsR = NULL;
      jmethodID midMain = NULL;
      jmethodID midCalling = NULL;
      jmethodID midDispStruct = NULL;
      jmethodID midDispStructArr = NULL;
     jmethodID midRetObjFunc = NULL;
      jmethodID midCtrlDetConst = NULL;
      jmethodID midWoConst = NULL;
     
      jobject jobjDet = NULL;
     jobject jobjRetData = NULL;
      jobjectArray jobjWOArr = NULL;
     
      //Obtaining Classes
      clsH = env-&gt;FindClass("HelloWorld");
      clsC = env-&gt;FindClass("ControlDetail");
      clsW = env-&gt;FindClass("WorkOrder");
    
     //Obtaining Method IDs
      if (clsH != NULL)
      {
          midMain         = env-&gt;GetStaticMethodID(clsH, "main", "([Ljava/lang/String;)V");
          midCalling      = env-&gt;GetStaticMethodID(clsH,"TestCall","(Ljava/lang/String;)V");
          midDispStruct = env-&gt;GetStaticMethodID(clsH,"DisplayStruct","(LControlDetail;)I");
          midDispStructArr = env-&gt;GetStaticMethodID(clsH,"DisplayStructArray","([LWorkOrder;)V");
          midRetObjFunc = env-&gt;GetStaticMethodID(clsH,"ReturnObjFunc","()Ljava/lang/Object;");
     }
     else
      {
           printf("\nUnable to find the requested class\n");          
      }
     if(clsC != NULL)
     {
          //Get constructor ID for ControlDetail
          midCtrlDetConst = env-&gt;GetMethodID(clsC, "&lt;init&gt;", "(ILjava/lang/String;Ljava/lang/String;I)V");         
     }
     else
      {
           printf("\nUnable to find the requested class\n");          
      }    
 
     if(clsW != NULL)
     {
          //Get Constructor ID for WorkOrder
          midWoConst = env-&gt;GetMethodID(clsW, "&lt;init&gt;", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");         
     }
     else
      {
           printf("\nUnable to find the requested class\n");          
      }
 
     /************************************************************************/
     /* Now we will call the functions using the their method IDs               */
     /************************************************************************/
     if(midMain != NULL)
          env-&gt;CallStaticVoidMethod(clsH, midMain, NULL); //Calling the main method.
    
     if (midCalling!=NULL)
     {
          jstring StringArg = env-&gt;NewStringUTF("\nTestCall:Called from the C Program\n");
          //Calling another static method and passing string type parameter
          env-&gt;CallStaticVoidMethod(clsH,midCalling,StringArg);
     }
    
     printf("\nGoing to Call DisplayStruct\n");
     if (midDispStruct!=NULL)
     {
          if(clsC != NULL &amp;&amp; midCtrlDetConst != NULL)
          {
               jstring StringArgName = env-&gt;NewStringUTF(ctrlDetail.Name);
               jstring StringArgIP = env-&gt;NewStringUTF(ctrlDetail.IP);
              
               //Creating the Object of ControlDetail.
               jobjDet = env-&gt;NewObject(clsC, midCtrlDetConst, (jint)ctrlDetail.ID, StringArgName, StringArgIP, (jint)ctrlDetail.Port);
          }
         
          if(jobjDet != NULL &amp;&amp; midDispStruct != NULL)
               env-&gt;CallStaticIntMethod(clsH,midDispStruct,jobjDet); //Calling the method and passing ControlDetail Object as parameter
     }
     //Calling a function from java and passing Structure array to it.
     printf("\n\nGoing to call DisplayStructArray From C\n\n");
     if (midDispStructArr!=NULL)
     {
          if(clsW != NULL &amp;&amp; midWoConst != NULL)
          {
               //Creating the Object Array that will contain 2 structures.
               jobjWOArr = (jobjectArray)env-&gt;NewObjectArray(2,clsW,env-&gt;NewObject(clsW, midWoConst,env-&gt;NewStringUTF(""),env-&gt;NewStringUTF(""),env-&gt;NewStringUTF(""),
                                                                         env-&gt;NewStringUTF(""),env-&gt;NewStringUTF(""),env-&gt;NewStringUTF(""),env-&gt;NewStringUTF("")));                
               //Initializing the Array
               for(int i=0;i&lt;2;i++)
               {
                    env-&gt;SetObjectArrayElement(jobjWOArr,i,env-&gt;NewObject(clsW, midWoConst,env-&gt;NewStringUTF(WO[i].sumSerialId),
                                                                      env-&gt;NewStringUTF(WO[i].accessNumber),
                                                                      env-&gt;NewStringUTF(WO[i].actionType),
                                                                      env-&gt;NewStringUTF(WO[i].effectiveDate),
                                                                      env-&gt;NewStringUTF(WO[i].fetchFlag),
                                                                      env-&gt;NewStringUTF(WO[i].reason),
                                                                      env-&gt;NewStringUTF(WO[i].accessSource)));    
               }
          }
          //Calling the Static method and passing the Structure array to it.
          if(jobjWOArr != NULL &amp;&amp; midDispStructArr != NULL)
               env-&gt;CallStaticVoidMethod(clsW,midDispStructArr,jobjWOArr);
     }
     //Calling a Static function that return an Object
     if (midRetObjFunc != NULL)
     {
          //Calling the function and storing the return object into jobject type variable
          //Returned object is basically a structure having two fields (string and integer)
          jobjRetData = (jobject)env-&gt;CallStaticObjectMethod(clsH,midRetObjFunc,NULL);
          //Get the class of object
          clsR = env-&gt;GetObjectClass(jobjRetData);
          //Obtaining the Fields data from the returned object
          jint nRet = env-&gt;GetIntField(jobjRetData,env-&gt;GetFieldID(clsR,"returnValue","I"));
          jstring jstrLog = (jstring)env-&gt;GetObjectField(jobjRetData,env-&gt;GetFieldID(clsR,"Log","Ljava/lang/String;"));
          const char *pLog = env-&gt;GetStringUTFChars(jstrLog,0);
         
          printf("\n\nValues Returned from Object are:\nreturnValue=%d\nLog=%s",nRet,pLog);
          //After using the String type data release it.
          env-&gt;ReleaseStringUTFChars(jstrLog,pLog);
     }
     //Release resources.
     int n = jvm-&gt;DestroyJavaVM();
      return 0;
}
 

 
Java Codes
***********
 
ControlNEDetail.java
====================
 

public class ControlNEDetail
{
     public int ID;
     public String Name;
     public String IP;
     public int Port;
 
     public ControlNEDetail(int nID, String szName, String szIP, int nPort)
     {
          this.ID = nID;
          this.Name = szName;
          this.IP = szIP;
          this.Port = nPort;
     }
}
 
ReturnData.java
================
 

public class ReturnData
{
     int returnValue;
     String Log;
    
     public ReturnData(int nRetVal, String szLog)
     {
          this.returnValue = nRetVal;
          this.Log = szLog;
     }
}
 
WorkOrder.java
===============
 

public class WorkOrder
{
     String          sumSerialId;    
     String          accessNumber;
     String          actionType;
     String          effectiveDate;
     String          fetchFlag;
     String          reason;
     String          accessSource;
     public WorkOrder(String szSumID,String szAccNum, String szActType, String szEffectDate, String fetchFlg, String szReason, String szAccSrc )
     {
          this.sumSerialId = szSumID;
          this.accessNumber = szAccNum;
          this.actionType = szActType;
          this.effectiveDate = szEffectDate;
          this.fetchFlag = fetchFlg;
          this.reason = szReason;
          this.accessSource = szAccSrc;              
     }    
};
 

HelloWorld.java
================
 
public class HelloWorld
{
         public static void main(String args[])
         {
            System.out.println("Hello World!");
            System.out.println("This is the main function in HelloWorld class");
         }
         public static void TestCall(String szArg)
         {
              System.out.println(szArg);
         }
         public static int DisplayStruct(ControlNEDetail ctrlDetail)
         {
              System.out.println("Structure is:\n-------------------------");
              System.out.println("Name:" + ctrlDetail.Name);
              System.out.println("IP:" + ctrlDetail.IP);
              System.out.println("Port" + ctrlDetail.Port);
              return 1;
         }
         public static void DisplayStructArray(WorkOrder ArrWO[])
         {
              System.out.println("WorkOrders are Given hereunder:\n----------------------------");
              for(int i = 0; i&lt; ArrWO.length;i++)
              {
                   System.out.println("&lt;---Work Order Number:" + String.valueOf(i+1) + "&lt;---");
                   System.out.println("Sum_Serial_ID: " + ArrWO[i].sumSerialId);
                   System.out.println("Access_Number: " + ArrWO[i].accessNumber);
                   System.out.println("Action_Type: " + ArrWO[i].actionType);
                   System.out.println("Effective_Date: " + ArrWO[i].effectiveDate);
                   System.out.println("Fetch_Flag: " + ArrWO[i].fetchFlag);
                   System.out.println("Reason: " + ArrWO[i].reason);
                   System.out.println("Access_Source: " + ArrWO[i].accessSource);
              }
 
         }
         public static Object ReturnObjFunc()
         {
              System.out.println("Going to return an object from java");
              ReturnData RetData = new ReturnData(1,"Successfull function call");
              return RetData;
         }
}
 

 
Thanks
 
Chinmaya
GeneralRe: RE: How to Call Java functions from C Using JNImemberMohammed Anees13 Aug '09 - 23:20 
You need to install the latest JDK, download from Sun
 
and set the path into Environment variable
GeneralVS 2008memberthusithagh5 Jul '09 - 8:47 
It seems like this isn't working with VS 2008/2005. It gets compiled but not running. Doesn't even give the 'jvm.dll' error. :(
GeneralMy vote of 2memberthusithagh5 Jul '09 - 6:54 
.

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.130523.1 | Last Updated 13 Jan 2008
Article Copyright 2008 by ajalilqarshi
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid