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

Discussion in 'Java' started by Jabel D. Morales - VMan of Mana, Aug 1, 2003.

  1. 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.
    Jabel D. Morales - VMan of Mana, Aug 1, 2003
    #1
    1. Advertising

  2. On Fri, 01 Aug 2003 01:01:06 GMT, "Jabel D. Morales - VMan of Mana"
    <> wrote:

    > 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
    Joseph Millar, Aug 1, 2003
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. bigbinc

    Java, jni.h and native method

    bigbinc, Oct 10, 2003, in forum: Java
    Replies:
    1
    Views:
    1,254
    Gordon Beaton
    Oct 10, 2003
  2. Alex Hunsley
    Replies:
    4
    Views:
    884
    Alex Hunsley
    Nov 14, 2003
  3. Replies:
    13
    Views:
    6,062
  4. Replies:
    3
    Views:
    394
    Lawrence Kirby
    Feb 28, 2005
  5. bgabrhelik
    Replies:
    0
    Views:
    797
    bgabrhelik
    Sep 29, 2009
Loading...

Share This Page