Problems with JNI: calling a Java method from native method.

  • Thread starter Jabel D. Morales - VMan of Mana
  • Start date
J

Jabel D. Morales - VMan of Mana

Hello all.

I have been experimenting with JNI to make a bridge between a Java program and
Microsoft's Tablet PC SDK (meaning C++ with Managed Extensions). So far, not
much luck.

To this moment I have had no problems to calls native methods from Java, but the
problem is whenever I try to call a Java method from the native code. This is
what I am doing so far:

The main Java class (AppDemo) initializes a set of objects for a simple Swing
program. Including is a static class member called inkStrokeCollection. The
AppDemo constructor initializes the different objects, inlcuding
inkStrokeCollection. After initializing, I make an invocation of the native
method, sending inkStrokeCollection as a parameter. This is the reason why I am
making inkStrokeCollection a static member instead of just declaring it in the
constructor.

The native method is where I have been making JNI experiments. First, I create
two Java integer arrays, one of them is returned to the AppDemo.main() which
then sends it to inkStrokeCollection.addInkStrokeWithArray(). As expected, the
Swing app is refreshed with a curve using the array as bezier control points.
The problem is when I try to send the second array directly to
inkStrokeCollection.addInkStrokeCollectionArray() from the native method. I
think I am doing the right thing. First, I am obtaining the class of the
inkStrokeCollection object which was given as a parameter to the native method.
Then, I am obtaining the method ID of
inkStrokeCollection.addInkStrokeWithArray(), which is a void method that takes
an integer array. Then, I am making a call to the method. However, the program
crashes whenever I try to do this with the following error message:

-- begin quote --
An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : unknown exception code (0xe0434f4d) occurred at PC=0x77E7388
7
Function=RaiseException+0x50
Library=C:\WINDOWS\system32\kernel32.dll

Current Java thread:
at AppDemo.displayTabletCanvas(Native Method)
at AppDemo.main(AppDemo.java:55)
-- end quote --

Followed by a bunch of hexadecimal numbers and dlls.

After commenting line by line, I noticed that the crash happens whenever I do
the second step (obtaining the method id). However, I was also able to check
that the GetObjectClass function does seem to return something since the
variable containing the class ID is not NULL after calling the function.

The following are what I think are the relevant code snippets of my program:

-- begin InkStrokeCollection.java snippet --
/*
* addInkStroke
* This method adds the given InkStroke object to the ink stroke
* vector. Also, this method sends an update notification to any
* registered observers.
* Parameters:
* newInkStroke - the InkStroke object to add to the vector
* Returns:
* none.
*/
public void addInkStroke(InkStroke newInkStroke)
{
InkStrokes.add(newInkStroke);

// notifies observers
setChanged();
notifyObservers();
}

/*
* addInkStrokeWithArray
* This method adds a new InkStroke object created with the given
* integer array ink stroke vector.
* Parameters:
* intArray - the integer array to create the new InkStroke with.
* Returns:
* none.
*/
public void addInkStrokeWithArray(int[] intArray)
{
addInkStroke(new InkStroke(intArray));
}
}
-- end InkStrokeCollection.java snippet --

-- begin AppDemo.java --
[snip - imports]

public class AppDemo extends JFrame
{
// member declaration
static InkStrokeCollection inkStrokeCollection;

public static native int[] displayTabletCanvas(InkStrokeCollection
inkStrokeCollection);

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

[snip - constructor]

public static void main(String[] args)
{
// variable declaration
int[] stroke;

AppDemo appDemo = new AppDemo();
appDemo.setDefaultCloseOperation(EXIT_ON_CLOSE);
appDemo.setVisible(true);

stroke = displayTabletCanvas(inkStrokeCollection);
inkStrokeCollection.addInkStrokeWithArray(stroke);
}
}
-- end AppDemo.java --

-- begin TabletCanvasManager.cpp --
// This is the main DLL file.

[snip - includes and TabletPC SDK stuff - it works]

// second argument is jclass because of static method
// v2 - returning integer array
JNIEXPORT jintArray JNICALL Java_AppDemo_displayTabletCanvas (JNIEnv *jniEnv,
jclass appDemo, jobject inkStrokeCollection)
{
// variable declaration
jint stroke01Info[8]; // jint array containing stroke info
jintArray stroke01; // java int array for stroke
jint stroke02Info[8]; // jint array containing stroke info
jintArray stroke02; // java int array for stroke
jclass inkStrokeCollectionClass; // inkStrokeCollection class
jmethodID addInkStrokeWithArrayID; // method ID

// global variable initialization
// TabletCanvasManager *MyTabletCanvas = new TabletCanvasManager();

/*
Attempt to make call to Java application
step 1 - make a new java integer array which will contain stroke data
step 2 - call the AppDemo.inkStrokeCollection.addInkStrokeWithArray() method
step 3 - hope that the stroke is shown in AppDemo main window
*/

// step 1

// create data points
System::Console::WriteLine("> step 1");
stroke01Info[0] = 100;
stroke01Info[1] = 100;
stroke01Info[2] = 300;
stroke01Info[3] = 150;
stroke01Info[4] = 200;
stroke01Info[5] = 350;
stroke01Info[6] = 400;
stroke01Info[7] = 400;

stroke02Info[0] = 100;
stroke02Info[1] = 400;
stroke02Info[2] = 300;
stroke02Info[3] = 350;
stroke02Info[4] = 200;
stroke02Info[5] = 150;
stroke02Info[6] = 400;
stroke02Info[7] = 100;

// load data points to arrays
stroke01 = jniEnv->NewIntArray(8);
jniEnv->SetIntArrayRegion(stroke01, 0, 8, stroke01Info);

stroke02 = jniEnv->NewIntArray(8);
jniEnv->SetIntArrayRegion(stroke02, 0, 8, stroke02Info);

// step 2
System::Console::WriteLine("> step 2a");
inkStrokeCollectionClass = jniEnv->GetObjectClass(inkStrokeCollection);
System::Console::WriteLine("> step 2b");
addInkStrokeWithArrayID = jniEnv->GetMethodID(inkStrokeCollectionClass,
"addInkStrokeWithArray", "([I)V"); // <-- this is where it seems to crash
System::Console::WriteLine("> step 2c");
jniEnv->CallVoidMethod(inkStrokeCollection, addInkStrokeWithArrayID, stroke02);

return stroke01;
}
-- end TabletCanvasManager.cpp --

Any ideas? I am not sure if the reason of the crashes are because I am using
managed extensions, or because inkStrokeCollection is static. I am not sure if
its relevant, but something that I have noticed is that when it crashes, there
is no output on the console from the System::ConsoleWriteLine() calls.

System: Windows XP Pro SP1, Java 1.4.2, VisualStudio .net, TabletPC SDK

Thanks for your time.
 
J

Joseph Millar

System::Console::WriteLine("> step 2a");
inkStrokeCollectionClass = jniEnv->GetObjectClass(inkStrokeCollection);
System::Console::WriteLine("> step 2b");
addInkStrokeWithArrayID = jniEnv->GetMethodID(inkStrokeCollectionClass,
"addInkStrokeWithArray", "([I)V"); // <-- this is where it seems to crash
System::Console::WriteLine("> step 2c");
jniEnv->CallVoidMethod(inkStrokeCollection, addInkStrokeWithArrayID, stroke02);

At first glance this all looks good, but I would guess an exception
is being raised here that you have not dealt with. No where do you
do any checking on raised Java exceptions. While I have not seen
the nt kernal api RaiseException() called in this context, it's
possible the JVM is calling it to indicate a problem. Unfortunately,
the exception code is user level code (hence starting with hex E).

I would check for exceptions after each call to a JNI routine using
ExceptionOccurred(), ExceptionDescribe() and ExceptionClear() to see
what else is going on. I suspect you will find something lurking
there. If you find no joy there, turn on your just in time debugging
in Visual Studio and verify the exact line the error is happening on
and that all your variables are as you expect them to be.

So something like this:

inkStrokeCollectionClass = jniEnv->GetObjectClass(inkStrokeCollection);
if (inkStrokeCollectionClass == NULL ||
jniEnv->ExceptionOccured())
{
// bad news, something went wrong, let's find out what
jniEnv->ExceptionDescribe()

// let the Java code handle the exception
return NULL;
}

--Joe
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top