UnsatisfiedLinkError and Javah in JNI

T

tony_lincoln

Dear Friends,

I am using Visual C++ under Windows 2000 to call c++ from Java. Without
package name, I succeeded; but with package name, I used javah
carefully, but failed. UnsatisfiedLinkError always appears.


The native java code is like this:

*****************
//NatBE.java
package be;
public class NatBE{

private NatBE() {}

public static native double calculateBE (int i1, int i2);

static { System.loadLibrary("TEST4"); }

public static void main (String[] args) {
int i1 = 3;
int i2 = 5;
new NatBE().calculateBE (i1, i2);
}// end main().

}// end class NatBE().
*******************************

I used javac NatBE.java,
a subdir named "be" was created and a NatBE.class created in it.
Then I used
javah -jhi be.NatBE
and be_NatBE.h was created in the same dir as NatBE.java stays. I
called this dir as current dir.
With be_NatBE.h I compiled my C++ codes in Visual C++ 6 and created one
dll file: TEST4.DLL and put it in the current dir.

A subdir named "main" is created in this current dir, and in it, there
is one java code named NatBEMain.java:

*************************************
import be.NatBE;

public class NatBEMain{

public static void main (String[] args) {
int i1 = 3;
int i2 = 5;
System.out.println("result is : " + NatBE.calculateBE (i1, i2);
}

}// end class NatBEMain.

Then I compiled this java code:
Javac NatBEMain.java
There is no mistake, but when I run it,
Java NatBEMain
There is information:

Exception in thread "main" java.lang.UnsatisfiedLinkError: calculateBE
at be.NatBE.calculateBE (Native Method)
at NatBEMain.main (NatBEMain.java:26)

I tried a lot to solve this problem, but failed. I know that I am not
so far from the answer, but can not find the way. Where is wrong with
it? Thanks a lot.

Best wishes.
tony
 
J

Jim Sculley

Dear Friends,

I am using Visual C++ under Windows 2000 to call c++ from Java. Without
package name, I succeeded; but with package name, I used javah
carefully, but failed. UnsatisfiedLinkError always appears.


The native java code is like this:

*****************
//NatBE.java
package be;
public class NatBE{

private NatBE() {}

public static native double calculateBE (int i1, int i2);

static { System.loadLibrary("TEST4"); }

public static void main (String[] args) {
int i1 = 3;
int i2 = 5;
new NatBE().calculateBE (i1, i2);
}// end main().

}// end class NatBE().
*******************************

I used javac NatBE.java,
a subdir named "be" was created and a NatBE.class created in it.
Then I used
javah -jhi be.NatBE
and be_NatBE.h was created in the same dir as NatBE.java stays. I
called this dir as current dir.
With be_NatBE.h I compiled my C++ codes in Visual C++ 6 and created one
dll file: TEST4.DLL and put it in the current dir.

A subdir named "main" is created in this current dir, and in it, there
is one java code named NatBEMain.java:

*************************************
import be.NatBE;

public class NatBEMain{

public static void main (String[] args) {
int i1 = 3;
int i2 = 5;
System.out.println("result is : " + NatBE.calculateBE (i1, i2);
}

}// end class NatBEMain.

Then I compiled this java code:
Javac NatBEMain.java
There is no mistake, but when I run it,
Java NatBEMain
There is information:

Exception in thread "main" java.lang.UnsatisfiedLinkError: calculateBE
at be.NatBE.calculateBE (Native Method)
at NatBEMain.main (NatBEMain.java:26)

I tried a lot to solve this problem, but failed. I know that I am not
so far from the answer, but can not find the way. Where is wrong with
it? Thanks a lot.

Best wishes.
tony

Let's see the native code. Also, post the function names as exported
from the DLL.
 
T

tony_lincoln

The Native code is NatBE.java, as shown in my first message. And the
function name is : calculateBE (int i1, int i2).

Is this information enough? Or do you still need more? Thanks in
advance!
 
G

Gordon Beaton

The Native code is NatBE.java, as shown in my first message. And the
function name is : calculateBE (int i1, int i2).

Is this information enough? Or do you still need more? Thanks in
advance!

You need to post the real contents of the DLL, not what you expect it
to be. That's where the problem lies.

/gordon
 
T

tony_lincoln

I used the "Dependency Walker", and found there is nothing in DLL !
This is strange!

When there is no package information in Java codes, I succeeded calling
C++ from Java. The DLL produced is like this:

Ordinal: 1 (0x0001)
Hint: 0 (0x0000)
Funtion: _Java_NatBE_calculateBE@24
Entry Point: 0x00001573

With the package information in Java codes, the same C++ source codes
were used, except the h file produced by javah. One DLL was produced
but nothing in it. Why is it like this?

Thank you.
 
G

Gordon Beaton

I used the "Dependency Walker", and found there is nothing in DLL !
This is strange!

When there is no package information in Java codes, I succeeded calling
C++ from Java. The DLL produced is like this:

Ordinal: 1 (0x0001)
Hint: 0 (0x0000)
Funtion: _Java_NatBE_calculateBE@24
Entry Point: 0x00001573

With the package information in Java codes, the same C++ source codes
were used, except the h file produced by javah. One DLL was produced
but nothing in it. Why is it like this?

"Nothing" sounds strange and unexpected. However you should not expect
to use the exact same source in both cases, since the generated method
names will be different, and this difference needs to be reflected in
the names of your native methods.

The advice I have when using native methods with packages is this
(actually this holds even without packages):

- specify the fully qualified classname when you run javah.
- #include the generated header file in your C or C++ file.
- make sure your names and signatures are *exactly* identical with the
generated ones.

An alternative solution is to define a function JNI_OnLoad() in your
library, from which you invoke RegisterNatives() to register the set
of native methods for the class.

In that case your native methods don't need to obey the generated
names at all (in fact I usually prefer to give them shorter names that
more closely match the native declarations in the java source). You
still need the information from javah in order to create the table
mapping names and signatures to their corresponding methods though.

When using this mechanism, the *only* difference between the packaged
and packageless versions is the way you spell the classname in the
call to RegisterNatives().

/gordon
 
T

tony_lincoln

Perfect! Now I know where I was wrong:
In one of the C++ codes, the function name should be:

JNIEXPORT jdouble JNICALL Java_be_NatBE_calculateBE(...)
but not:
JNIEXPORT jdouble JNICALL Java_NatBE_calculateBE(...) !

Although the 2nd function name can be compiled as well, but the DLL
will be like this:
?Java_NatBE_calculateBE@@ghfsdhgfsd@@PAV_JClass@@gffdfd@@2@Z
This is wrong.

The correct DLL from the 1st function name above should be:
_Java_be_NatBE_calculateBE@24
This looks beautiful :)

Using this DLL I can be successful.
As for the reason why in some cases DLL is empty, it is very simple.
There are 15 C++ files, but I forgot one, I compiled only 14 C++ files
and there was no error when I compiled them. So I thought the DLL was
created in a correct way. But I should check this DLL using Dependency
Walker to see the function name.

Thank Jim Sculley, especially Gordon Beaton for the messages!
Tony Lincoln
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top