"Unsatisfied Link" exception when trying to use JNI

D

Dag Sunde

I have the following Java class:

package no.gaiasoft.fotoboks;
public class Capture {
// native method declaration
native byte[] grabImage();
// Load the library
static {
System.loadLibrary("canoncapture");
}

public static void main( String args[]) {
byte buf[];
Capture img = new Capture();
buf = img.grabImage();
String s = new String(buf);
System.out.println(s);
}
}


This I run thru javah to get this header file:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class no_gaiasoft_fotoboks_Capture */

#ifndef _Included_no_gaiasoft_fotoboks_Capture
#define _Included_no_gaiasoft_fotoboks_Capture
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: no_gaiasoft_fotoboks_Capture
* Method: grabImage
* Signature: ()[B
*/
JNIEXPORT jbyteArray JNICALL Java_no_gaiasoft_fotoboks_Capture_grabImage
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif


I implement "canoncapture.dll" in visual studio like this:
#include "stdafx.h"
#include "jni.h"

JNIEXPORT jbyteArray JNICALL Java_no_gaiasoft_fotoboks_Capture_grabImage
(JNIEnv * env, jobject jobj) {

jbyteArray jb;

jb = env->NewByteArray(15);
env->SetByteArrayRegion(jb,0,14, (jbyte *)'A');
return (jb);
}


I put "canoncapture.dll" in java.library.path, and run Capture.
this gives me the error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: grabImage
at no.gaiasoft.fotoboks.Capture.grabImage(Native Method)
at no.gaiasoft.fotoboks.Capture.main(Capture.java:17)

Can anyone shed som light on what i might be doing wrong here?

TIA...
 
G

Gordon Beaton

Exception in thread "main" java.lang.UnsatisfiedLinkError: grabImage
at no.gaiasoft.fotoboks.Capture.grabImage(Native Method)
at no.gaiasoft.fotoboks.Capture.main(Capture.java:17)

Can anyone shed som light on what i might be doing wrong here?

Your native source file doesn't seem to include the generated header
file. That's important for the extern "C" declaration that prevents
your C++ compiler from mangling the symbol names.

After fixin that, confirm with a tool like dumpbin, depends or
quickview that the symbol in the dll actually matches the generated
name.

/gordon
 
D

Dag Sunde

Gordon said:
Your native source file doesn't seem to include the generated header
file. That's important for the extern "C" declaration that prevents
your C++ compiler from mangling the symbol names.

After fixin that, confirm with a tool like dumpbin, depends or
quickview that the symbol in the dll actually matches the generated
name.

Thanks!

That led to progress! ;-)

now i get:
# An unexpected error has been detected by HotSpot Virtual Machine:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6d76dc8a, pid=3488,
tid=3432
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_06-b05 mixed mode)
# Problematic frame:
# V [jvm.dll+0x8dc8a]
#
# An error report file with more information is saved as hs_err_pid3488.log


I'm on very thin ice when it comes to C/C++. Can this be because
the C dll is compiled with a c++ compiler (MS VS 6.0)?

....or maybe I'm not up to speed concerning the mapping of datatypes.
Will for example the statement:
"env->SetByteArrayRegion(jb,0,14, (jbyte *)'A');"
fill the jbyteArray with 15 'A' characters?


TIA...
 
G

Gordon Beaton

Will for example the statement:
"env->SetByteArrayRegion(jb,0,14, (jbyte *)'A');"
fill the jbyteArray with 15 'A' characters?

No.

SetByteArrayRegion() takes a start and length, so the length of the
region to fill is 14, not 15.

Also, 'A' is a char, not an array. Attempting to treat it as a pointer
is most likely the cause of your crash. You probably meant "A", which
is an array of two characters ('A' followed by a terminating 0) and
can be passed as a pointer.

However, the array you pass to SetByteArrayRegion() needs as many
elements as the number you specified, i.e. 14. So you'd need to pass
"AAAAAAAAAAAAAA" for this to work as you intend. You might consider
creating the native "AAA" buffer programmatically, or using
SetByteArrayElement() to set the elements one at a time in a loop.

/gordon
 
D

Dag Sunde

Gordon said:
No.

SetByteArrayRegion() takes a start and length, so the length of the
region to fill is 14, not 15.

Also, 'A' is a char, not an array. Attempting to treat it as a pointer
is most likely the cause of your crash. You probably meant "A", which
is an array of two characters ('A' followed by a terminating 0) and
can be passed as a pointer.

However, the array you pass to SetByteArrayRegion() needs as many
elements as the number you specified, i.e. 14. So you'd need to pass
"AAAAAAAAAAAAAA" for this to work as you intend. You might consider
creating the native "AAA" buffer programmatically, or using
SetByteArrayElement() to set the elements one at a time in a loop.

Gordon!

You're a genius!

Setting "AAAAAAAAAAAAAA" worked perfectly. But I can't find any
method named SetByteArrayElement(), so I wasn't able to test that loop.

On the other hand, I just needed to return something in a bytearray
to get this skeleton up and running. The byte array will eventually
be filled with jpeg data from a Canon PowerShot camera.

You have my eternal gratitude (well... for a long time, anyway)!

:)
 
G

Gordon Beaton

But I can't find any method named SetByteArrayElement(), so I wasn't
able to test that loop.

My bad, I was thinking of SetObjectArrayElement() (which doesn't apply
here).

Another suggestion is to use GetByteArrayElements() to get a native
array from the byte array, make any changes to the native
array, then use ReleaseByteArrayElements() with JNI_COMMIT in order to
propagate your changes back to the Java array.

/gordon
 
G

Gordon Beaton

The byte array will eventually be filled with jpeg data from a Canon
PowerShot camera.

BTW are you aware of libgphoto? Apparently there are Java bindings.
Base your application on that (except on Windows) and you'll be able
to support hundreds of different cameras: http://www.gphoto.org/ .

/gordon
 
D

Dag Sunde

Gordon said:
BTW are you aware of libgphoto? Apparently there are Java bindings.
Base your application on that (except on Windows) and you'll be able
to support hundreds of different cameras: http://www.gphoto.org/ .
Now, *That* is interesting!

I convinced the customer to use Win2000 for the time being,
because the selected camera and printer vendors have absolutely
*no* support for U*ix, whatsoever. The customer really want this to run
under Fedora core4/5 or Debian because of stability.

Do you know if libgphoto have support for Remote Capture for
the "Canon Powershot A640" camera?

And have your ever heard of any Linux drivers for a
"Mitsubishi 9559" printer too?
:)
 
D

Dag Sunde

Dag said:
Now, *That* is interesting!

I convinced the customer to use Win2000 for the time being,
because the selected camera and printer vendors have absolutely
*no* support for U*ix, whatsoever. The customer really want this to
run under Fedora core4/5 or Debian because of stability.

Do you know if libgphoto have support for Remote Capture for
the "Canon Powershot A640" camera?

And have your ever heard of any Linux drivers for a
"Mitsubishi 9559" printer too?
:)

A little bit triggerhappy there...

I checked myself, and found that libgphoto2 2.3.0 have
A640 support, but it isn't clear if it support the remote
capture feature...
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top