Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: JavaSE6 JNI linker C++0x
Hi,
 
I am new to JNI and I have been trying to write a simple program to call Java code from C++.
 
I am facing problem in creating the JavaVM from C and am getting the Linker error. I have tried changing the GNU library files in dev C++ (I am using Dev c++ compiler) but no luck so far.
The JDK version is 1.6.27.
 
Can anybody help me and point out the error or recommend a step-by-step approach to write this program?
 
Here is the C code file I am trying to compile.
 
#include <jni.h>
#include <windows.h>
 
#define PATH_SEPARATOR ';' /* define it to be ':' on Solaris */
#define USER_CLASSPATH "." /* where Prog.class is */
 
main() {
    JNIEnv *env;
    JavaVM *jvm;
    jint res;
    jclass cls;
    jmethodID mid;
    jstring jstr;
    jclass stringClass;
    jobjectArray args;
 
#ifdef JNI_VERSION_1_2
    JavaVMInitArgs vm_args;
    JavaVMOption options[1];
    options[0].optionString =
        "-Djava.class.path=" USER_CLASSPATH;
    vm_args.version = 0x00010002;
    vm_args.options = options;
    vm_args.nOptions = 1;
    vm_args.ignoreUnrecognized = JNI_TRUE;
    /* Create the Java VM */
    // this should contain the path to the JVM DLL file
    HINSTANCE hVM = LoadLibrary("C:\\Program Files\\Java\\jdk1.6.0_27\\jre6\\bin\\client\\jvm.dll");
if (hVM == NULL)
{
    DWORD dwe = GetLastError();
    return -1;
}
typedef jint	
(CALLBACK *fpCJV)(JavaVM**, void**, JavaVMInitArgs*);
 
fpCJV CreateJavaVM = (fpCJV)::GetProcAddress(hVM, "JNI_CreateJavaVM");
res = CreateJavaVM(&jvm, (void**)&env, &vm_args);
#else
    JDK1_1InitArgs vm_args;
    char classpath[1024];
    vm_args.version = 0x00010001;
    JNI_GetDefaultJavaVMInitArgs(&vm_args);
    /* Append USER_CLASSPATH to the default system class path */
    sprintf(classpath, "%s%c%s",
            vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH);
    vm_args.classpath = classpath;
    /* Create the Java VM */
    res = JNI_CreateJavaVM(&jvm, &env, &vm_args);
#endif /* JNI_VERSION_1_2 */
 
    if (res < 0) {
        fprintf(stderr, "Can't create Java VM\n");
        exit(1);
    }
    cls = (*env)->FindClass(env, "Prog");
    if (cls == NULL) {
        goto destroy;
    }
 
    mid = (*env)->GetStaticMethodID(env, cls, "main",
                                    "([Ljava/lang/String;)V");
    if (mid == NULL) {
        goto destroy;
    }
    jstr = (*env)->NewStringUTF(env, " from C!");
    if (jstr == NULL) {
        goto destroy;
    }
    stringClass = (*env)->FindClass(env, "java/lang/String");
    args = (*env)->NewObjectArray(env, 1, stringClass, jstr);
    if (args == NULL) {
        goto destroy;
    }
    (*env)->CallStaticVoidMethod(env, cls, mid, args);
 
destroy:
    if ((*env)->ExceptionOccurred(env)) {
        (*env)->ExceptionDescribe(env);
    }
    (*jvm)->DestroyJavaVM(jvm);
}
Could you please check if it gives any compilation error to you?
Posted 3-Oct-11 21:11pm
Edited 4-Oct-11 23:50pm
v4
Comments
Dalek Dave at 4-Oct-11 4:54am
   
Edited for Readability.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

See here[^] to check your code is following the correct rules. Also, make sure you have defined your JNI calls within extern "C" {} blocks, to prevent name mangling by the compiler.
  Permalink  
Comments
Dalek Dave at 4-Oct-11 4:54am
   
Good Link
anktrive at 4-Oct-11 5:51am
   
Hi Richard, Thanks for the quick response.... I have used the exact same code given in the link and used Dev c++ to compile it, so it should follow the rules. In this code only I have received Linker error. I suspect it is not able to locate the java executables on my system.The environment variables on my system are:
PATH: C:\Program Files\Java\jdk1.6.0_27\bin;C:\Program Files\Java\jdk1.6.0_27\jre\bin\client
JAVA_HOME: C:\Program Files\Java\jdk1.6.0_27\bin
LD_LIBRARY_PATH= C:\Program Files\Java\jdk1.6.0_27\jre\bin\client
CLASSPATH= C:\data
 
Could you please let me know if any of these system variables should be defined differently?
Richard MacCutchan at 4-Oct-11 7:18am
   
That looks OK, you should also check that the jvm.dll file is accessible in C:\Program Files\Java\jdk1.6.0_27\jre\bin\client.
anktrive at 4-Oct-11 7:32am
   
I have already checked it since i found it as one of the possible reasons why JVM could not be created. JVM.dll is there. Is there a possibility that it is not accesible at runtime even if it is at the correct location?
Richard MacCutchan at 4-Oct-11 8:04am
   
Not that I can think of; if you have linked it with the correct .lib file, and the dll is in the Windows path then it should all work. Unfortunately I don't have a ready made test program to try this on my system at the moment. If I get time later I may give it a go.
anktrive at 5-Oct-11 1:26am
   
When you say linking with the correct .lib file, does it mean giving the library path for jvm.lib to C compiler or setting it as LD_LIBRARY_PATH in the environment variables?
Richard MacCutchan at 5-Oct-11 3:23am
   
Please ignore this, see my 'proper' solution below.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

It's customary to locate the java runtime trough settings from the registry, and then load the dll dynamically.
 
Have look at:
Jace[^]
Jace offers some additional features you might find interesting too.
 
[Update]
The _imp__ prefix indicates that you have a problem with your library - I assume you are using MinGW with Dev c++, it's been a while since I played around with it - but if I remember correctly there is a tool provided with MinGW that allows you to create *.a files for dll's based on def files ...
 
If you're unfamiliar with def files take a look at:
Visual C++ 2010 Express [^] - it's free too.
 
[Update 2]
Have you read The Java™ Native Interface[^]?
 
MinGW dlltool[^]
 
Stdcall and DLL tools of MSVC and MinGW[^]
 
Best regards
Espen Harlinn
  Permalink  
v3
Comments
Richard MacCutchan at 4-Oct-11 7:16am
   
I've used JNI quite a bit and never had to do that.
Espen Harlinn at 4-Oct-11 10:24am
   
It's how the java.exe, Eclipse, and many other tools load the java runtime - and you don't need to have the %JAVA_HOME%\bin directory in your path.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

I don't know why this happens BUT:
In your C code, if you replace the line:
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
with
// this should contain the path to the JVM DLL file
HINSTANCE hVM = LoadLibrary("C:\\Program Files (x86)\\Java\\jre6\\bin\\client\\jvm.dll");
if (hVM == NULL)
{
    DWORD dwe = GetLastError();
    return -1;
}
typedef jint	(CALLBACK *fpCJV)(JavaVM**, void**, JavaVMInitArgs*);
fpCJV CreateJavaVM = (fpCJV)::GetProcAddress(hVM, "JNI_CreateJavaVM");
res = CreateJavaVM(&jvm, (void**)&env, &vm_args);
it should work; at least it does on my system. I will continue to investigate further as time permits.
  Permalink  
Comments
Espen Harlinn at 4-Oct-11 11:35am
   
5'ed - "HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment" contains a value called "CurrentVersion" = 1.6 - indicating that one should look at the RuntimeLib value under HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.6 - it contains the full path to the jvm.dll, like "C:\Program Files (x86)\Java\jre6\bin\client\jvm.dll"
Richard MacCutchan at 4-Oct-11 12:02pm
   
You are correct, of course, it's just that I have always done it like this, without recourse to the registry.
anktrive at 5-Oct-11 3:41am
   
The following line gives a compilation error as "syntax error before ':' token "
fpCJV CreateJavaVM = (fpCJV)::GetProcAddress(hVM, "JNI_CreateJavaVM");
Am I missing any import header file?
Sorry for the dumb question but i am new to C programming as well.
Richard MacCutchan at 5-Oct-11 4:11am
   
Did you put the typedef line before it?
anktrive at 5-Oct-11 4:14am
   
Here is the C code file I am trying to compile.
 
#include
#include

#define PATH_SEPARATOR ';' /* define it to be ':' on Solaris */
#define USER_CLASSPATH "." /* where Prog.class is */

main() {
JNIEnv *env;
JavaVM *jvm;
jint res;
jclass cls;
jmethodID mid;
jstring jstr;
jclass stringClass;
jobjectArray args;

#ifdef JNI_VERSION_1_2
JavaVMInitArgs vm_args;
JavaVMOption options[1];
options[0].optionString =
"-Djava.class.path=" USER_CLASSPATH;
vm_args.version = 0x00010002;
vm_args.options = options;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = JNI_TRUE;
/* Create the Java VM */
// this should contain the path to the JVM DLL file
HINSTANCE hVM = LoadLibrary("C:\\Program Files\\Java\\jdk1.6.0_27\\jre6\\bin\\client\\jvm.dll");
if (hVM == NULL)
{
DWORD dwe = GetLastError();
return -1;
}
typedef jint
(CALLBACK *fpCJV)(JavaVM**, void**, JavaVMInitArgs*);
 
fpCJV CreateJavaVM = (fpCJV)::GetProcAddress(hVM, "JNI_CreateJavaVM");
res = CreateJavaVM(&jvm, (void**)&env, &vm_args);
#else
JDK1_1InitArgs vm_args;
char classpath[1024];
vm_args.version = 0x00010001;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
/* Append USER_CLASSPATH to the default system class path */
sprintf(classpath, "%s%c%s",
vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH);
vm_args.classpath = classpath;
/* Create the Java VM */
res = JNI_CreateJavaVM(&jvm, &env, &vm_args);
#endif /* JNI_VERSION_1_2 */

if (res < 0) {
fprintf(stderr, "Can't create Java VM\n");
exit(1);
}
cls = (*env)->FindClass(env, "Prog");
if (cls == NULL) {
goto destroy;
}

mid = (*env)->GetStaticMethodID(env, cls, "main",
"([Ljava/lang/String;)V");
if (mid == NULL) {
goto destroy;
}
jstr = (*env)->NewStringUTF(env, " from C!");
if (jstr == NULL) {
goto destroy;
}
stringClass = (*env)->FindClass(env, "java/lang/String");
args = (*env)->NewObjectArray(env, 1, stringClass, jstr);
if (args == NULL) {
goto destroy;
}
(*env)->CallStaticVoidMethod(env, cls, mid, args);

destroy:
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
}
(*jvm)->DestroyJavaVM(jvm);
}
Could you please check if it gives any compilation error to you?
anktrive at 5-Oct-11 4:16am
   
The include directives that are missing in the above code
#include jni.h
#include windows.h
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 4

My apologies but I was compiling as C++, which does not work for standard C. Modify the code between the lines #ifdef JNI_VERSION_1_2 and #else as follows:
#ifdef JNI_VERSION_1_2
// definitions required to get the proc address
	HINSTANCE hVM;
	typedef jint	(CALLBACK *fpCJV)(JavaVM**, void**, JavaVMInitArgs*);
 
	fpCJV CreateJavaVM;
	JavaVMInitArgs vm_args;
	JavaVMOption options[1];
	options[0].optionString =
		"-Djava.class.path=" USER_CLASSPATH;
	vm_args.version = 0x00010002;
	vm_args.options = options;
	vm_args.nOptions = 1;
	vm_args.ignoreUnrecognized = JNI_TRUE;
	/* Create the Java VM */
// load the Java VM dll
	hVM = LoadLibrary("C:\\Program Files (x86)\\Java\\jre6\\bin\\client\\jvm.dll");
	if (hVM == NULL)
	{
		DWORD dwe = GetLastError();
		return -1;
	}
// get the address of the first JNI call and create the VM
	CreateJavaVM = (fpCJV)GetProcAddress(hVM, "JNI_CreateJavaVM");
	res = CreateJavaVM(&jvm, (void**)&env, &vm_args);
#else
I have added some extra comment lines preceding the code that requires changing. You may also like to consider moving to C++ which offers lots of benefits over pure C.
 

We still have the issue of why the linker cannot find the JNI_CreateJavaVM call, which I may return to as time permits, but at least this solution should allow you to continue working with JNI.
 
I finally found the time to go and look at this properly, and realised that I have mixed mode libraries on my Windows 7 system. I downloaded the 32bit JDK and now I can link and run successfully. Please check that you are using all 32 bit (from C:\Program Files (x86)\Java) or all 64bit (from C:\Program Files\Java) for your projects.
  Permalink  
v2
Comments
anktrive at 7-Oct-11 3:01am
   
Thanks Richard.... I was able to get it working using the above code...I think I also have been using 64 bit JDK. will try with 32 bit JDK.

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

  Print Answers RSS
0 OriginalGriff 250
1 Jochen Arndt 155
2 PIEBALDconsult 150
3 DamithSL 125
4 Afzaal Ahmad Zeeshan 120
0 OriginalGriff 5,695
1 DamithSL 4,591
2 Maciej Los 4,012
3 Kornfeld Eliyahu Peter 3,480
4 Sergey Alexandrovich Kryukov 3,190


Advertise | Privacy | Mobile
Web02 | 2.8.141220.1 | Last Updated 5 Oct 2011
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100