Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / March 2006

Tip: Looking for answers? Try searching our database.

creating a JFrame via JNI

Thread view: 
HenStepper - 14 Mar 2006 02:39 GMT
I get an unhandled native exception when trying to create a JFrame from
C via JNI.
The error message is unhelpful and untraceable even on Google.

Here is the Java line it claims to bomb on:
JFrame frame = new JFrame("test frame");

Here is the result:
JavaAWT: NSException not handled by native method. Passing to Java.
java.lang.RuntimeException: Non-Java exception raised, not handled!
(Original problem: Error (1002) creating CGSWindow)
at apple.awt.OSXOffScreenSurfaceData._copyNSImagePixels(Native Method)
at
apple.awt.OSXOffScreenSurfaceData.copyNSImagePixels(OSXOffScreenSurfaceData.java:1017)
at apple.awt.CImage.createImage(CImage.java:47)
at apple.laf.AquaImageFactory.makeAlertIcon(AquaImageFactory.java:111)
at
apple.laf.AquaImageFactory.getConfirmImageIcon(AquaImageFactory.java:92)
at
apple.laf.AquaLookAndFeel.initComponentDefaults(AquaLookAndFeel.java:616)
at apple.laf.AquaLookAndFeel.getDefaults(AquaLookAndFeel.java:360)
at javax.swing.UIManager.setLookAndFeel(UIManager.java:445)
at javax.swing.UIManager.setLookAndFeel(UIManager.java:485)
at javax.swing.UIManager.initializeDefaultLAF(UIManager.java:1178)
at javax.swing.UIManager.initialize(UIManager.java:1265)
at javax.swing.UIManager.maybeInitialize(UIManager.java:1253)
at javax.swing.UIManager.getUI(UIManager.java:859)
at javax.swing.JPanel.updateUI(JPanel.java:104)
at javax.swing.JPanel.<init>(JPanel.java:64)
at javax.swing.JPanel.<init>(JPanel.java:87)
at javax.swing.JPanel.<init>(JPanel.java:95)
at javax.swing.JRootPane.createGlassPane(JRootPane.java:482)
at javax.swing.JRootPane.<init>(JRootPane.java:313)
at javax.swing.JFrame.createRootPane(JFrame.java:247)
at javax.swing.JFrame.frameInit(JFrame.java:228)
at javax.swing.JFrame.<init>(JFrame.java:195)
at GUIApp.startup(GUIApp.java:8)
startup displaying message

Apparently there is an error when native C calls Java which in turn
calls a native method _copyNSImagePixels. When I start the same class
using "java" on the command line, everything works fine.
So why is _copyNSImagePixels sensitive to the origin of this request?

An extra oddity is that line 8 in GUIApp.java is indeed the JFrame
constructor
(as the traceback shows), but line 9 is a print statement:
System.out.println("startup displaying message");
and you can see that its output arrived too. I cannot interpret this.
Does anyone know what this means?

Or, more to the point...
Does anyone know how to start a GUI from C?
TIA,
hs
Gordon Beaton - 14 Mar 2006 09:48 GMT
> I get an unhandled native exception when trying to create a JFrame
> from C via JNI. The error message is unhelpful and untraceable even
> on Google.
>
> Here is the Java line it claims to bomb on:
> JFrame frame = new JFrame("test frame");

You said from JNI, but that looks like Java to me. At any rate, this
native code works for me:

jframe_cls = (*env)->FindClass(env,"javax/swing/JFrame");
mid = (*env)->GetMethodID(env,jframe_cls,"<init>","(Ljava/lang/String;)V")
jframe = (*env)->NewObject(env,jframe_cls,mid,title);

mid = (*env)->GetMethodID(env,jframe_cls,"pack","()V");
(*env)->CallVoidMethod(env,jframe,mid);

mid = (*env)->GetMethodID(env,jframe_cls,"setVisible","(Z)V");
(*env)->CallVoidMethod(env,jframe,mid,JNI_TRUE);

Similarly, invoking an equivalent Java method from C also works. I
suspect a coding error.

/gordon

Signature

[  do not email me copies of your followups  ]
g o r d o n + n e w s @  b a l d e r 1 3 . s e

HenStepper - 14 Mar 2006 15:50 GMT
>> Here is the Java line it claims to bomb on:
>> JFrame frame = new JFrame("test frame");

> You said from JNI, but that looks like Java to me.

Ummm, yes... I forgot to include my code. Here is the C program:

#include
"/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Headers/jni.h"
#include <string.h>
#include <stdlib.h>

void bomb(int errno, char * msg) {
    printf("ERROR: %s\n", msg);
    exit(errno);
    }

int main(int argc, char *args[]) {
    jclass        cls;
    JNIEnv        *env;
    JavaVM        *jvm;
    JavaVMOption options[10];
    JavaVMInitArgs vm_args;
    jmethodID mid;

    options[0].optionString= "-Djava.class.path=.";
    memset(&vm_args, 0, sizeof(vm_args));
    vm_args.version = JNI_VERSION_1_4;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized= 0;
    long status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    if (status == JNI_ERR) bomb(1000,"JNI_ERR; Could not launch JVM");
    printf("no JNI_ERR\n");

    cls = (*env)->FindClass(env, "GUIApp"); // find our class
    if (cls==0)    bomb(1003, "JVM cannot find GUIApp class.");

    mid = (*env)->GetStaticMethodID(env, cls, "startup", "()V");
    if (mid==0)  bomb(1004, "couldn't find method");
    printf("calling startup method\n");
    (*env)->CallStaticVoidMethod(env, cls, mid);
    printf("got started\n");

    return 0;
    }

and the Java class it relies on to create the JFrame is here:

import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class GUIApp {

    public static void startup() {
        System.out.println("startup creating frame");
        JFrame frame = new JFrame("test frame");
        System.out.println("startup displaying message");
        JOptionPane.showMessageDialog(frame, "I'm up!");
        System.out.println("startup message acknowledged");
        System.exit(1234);
        }
   
    public static void main(String[] args) { startup(); }
   
    }
HenStepper - 14 Mar 2006 16:08 GMT
Thanks for the code you supplied, Gordon.
I ran it. It bombed in exactly the same way.
Am I having a Mac problem?
Here is my whole program (this time without any supporting java):

#include
"/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Headers/jni.h"
#include <string.h>
#include <stdlib.h>

void bomb(int errno, char * msg) {
    printf("ERROR: %s\n", msg);
    exit(errno);
    }

int main(int argc, char *args[]) {
    jclass        jframe_cls;
    JNIEnv        *env;
    JavaVM        *jvm;
    JavaVMOption options[10];
    JavaVMInitArgs vm_args;
    jmethodID mid;
    jobject jframe;

    options[0].optionString= "-Djava.class.path=.";
    memset(&vm_args, 0, sizeof(vm_args));
    vm_args.version = JNI_VERSION_1_4;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized= 0;
    long status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    printf("no JNI_ERR\n");

    jframe_cls = (*env)->FindClass(env, "javax/swing/JFrame");
    if (jframe_cls==0)    bomb(1003, "JVM cannot find GUIApp class.");

    mid =
(*env)->GetMethodID(env,jframe_cls,"<init>","(Ljava/lang/String;)V");
    if (mid==0)  bomb(1004, "couldn't find constructor");

    jframe = (*env)->NewObject(env,jframe_cls,mid,"JFrame from C!");
    printf("jframe created\n");

    return 0;
    }

The traceback is entirely similar:
JavaAWT: NSException not handled by native method.  Passing to Java.
java.lang.RuntimeException: Non-Java exception raised, not handled!
(Original problem: Error (1002) creating CGSWindow)
...
       at javax.swing.JFrame.<init>(JFrame.java:195)
jframe created

Note that the exception was thrown in native code,
the taceback got printed,
and then the message "jframe created" arrived... apparently out of the
blue again.
I still cannot interpret this sequencing. There is no second thread
here,
and I doubt that the return statement following the printf("jframe
created") caused
the native exception.
Gordon Beaton - 14 Mar 2006 16:26 GMT
> Thanks for the code you supplied, Gordon.
> I ran it. It bombed in exactly the same way.
> Am I having a Mac problem?

Here's one thing that is likely causing problems:

> jframe = (*env)->NewObject(env,jframe_cls,mid,"JFrame from C!");

That title text needs to be a jstring object, not a char*.

Also (now I'm guessing), have you compiled your launcher with the
necessary CFLAGS for a multithreaded program (e.g. -D_REENTRANT), and
linked with the appropriate thread library (e.g. -pthread)?

/gordon

Signature

[  do not email me copies of your followups  ]
g o r d o n + n e w s @  b a l d e r 1 3 . s e

HenStepper - 15 Mar 2006 04:35 GMT
I had not use D_REENTRANT and -pthread, but I did as soon as you
suggested (to no avail). My concept of creating a JFrame does not
involve any new Threads. Do you know differently? or are you just
suggesting safe practices?

You are right about the jstring, and I've fixed it. But the
exception was happening before that line, so it hasn't mattered yet.

I attach the new code here. I'm running on Mac OS 10.4; I'd be
delighted if people on other OS's would run it and see what happens.
Put the file in GUIdooey.c, then do something like this:
           gcc -framework JavaVM -pthread GUIdooey.c
           a.out
and report if it crashes or not.
You may have to fiddle with the first line.
TIA,
hs

#include
"/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Headers/jni.h"
//#include "jni.h"
#include <string.h>
#include <stdlib.h>

void bomb(int errno, char * msg) {
    printf("ERROR: %s\n", msg);
    exit(errno);
    }

int main(int argc, char *args[]) {
    jclass        jframe_cls;
    JNIEnv        *env;
    JavaVM        *jvm;
    JavaVMOption options[10];
    JavaVMInitArgs vm_args;
    jmethodID mid;
    jobject jframe;

    options[0].optionString= "-Djava.class.path=.";
    memset(&vm_args, 0, sizeof(vm_args));
    vm_args.version = JNI_VERSION_1_4;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized= 0;
    long status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    printf("no JNI_ERR\n");

    jframe_cls = (*env)->FindClass(env, "javax/swing/JFrame");
    if (jframe_cls==0)    bomb(1003, "JVM cannot find GUIApp class.");

    mid = (*env)->
        GetMethodID(env,jframe_cls,"<init>","(Ljava/lang/String;)V");
    if (mid==0)  bomb(1004, "couldn't find constructor");

    jstring title= (*env)->NewStringUTF(env, "JFrame from C!");
    if (title==NULL) bomb(1005,"JNI failed to get memory for string");
    jframe = (*env)->NewObject(env,jframe_cls,mid,title);
    printf("jframe created\n");
   
    return 0;
    }
Gordon Beaton - 15 Mar 2006 08:57 GMT
> I had not use D_REENTRANT and -pthread, but I did as soon as you
> suggested (to no avail). My concept of creating a JFrame does not
> involve any new Threads. Do you know differently? or are you just
> suggesting safe practices?

[...]

> I attach the new code here. I'm running on Mac OS 10.4; I'd be
> delighted if people on other OS's would run it and see what happens.

Your code works for me on Linux/x86. This is how I built it:

gcc
 -Wall
 -D_REENTRANT
 -I $JDK/linux
 -I $JDK/linux/include
 launch.c
 -L $JDK/jre/lib/i386
 -L $JDK/jre/lib/i386/client
 -ljvm -lpthread
 -o launch

The -D_REENTRANT and -lpthread arguments are not just a good idea; the
JVM expects to run in a multithreaded environment. I don't know
whether you need to specify these (or something equivalent) on MacOSX.

To run the program I made sure that the two directories containing the
JVM libraries (indicated with -L above) are in my LD_LIBRARY_PATH so
they can be found at runtime. Again, how you do this on MacOSX I don't
know.

Note that you fail to check the return value from JNI_CreateJavaVM(),
but you print "no JNI_ERR" regardless. Check that the JVM actually
starts before continuing. It will fail to start if the necessary
libraries are not found at runtime.

/gordon

Signature

[  do not email me copies of your followups  ]
g o r d o n + n e w s @  b a l d e r 1 3 . s e

Chris Uppal - 14 Mar 2006 15:33 GMT
> I get an unhandled native exception when trying to create a JFrame from
> C via JNI.

One possible problem may be that you are creating this component from the
"wrong" thread.  AFAIK, Sun now expect you to do all your GUI work on the EDT
thread.  See:
   http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html

Unfortunately there is no JNI equivalent of:
   java.awt.EventQueue.invokeLater()
and/or:
   javax.swing.SwingUtilities.invokeLater()
so it's messy to change the code to ensure that your C code is running in a JNI
method which has been invoked from Java via one of the above methods, and
therefore on the correct thread.

   -- chris
HenStepper - 14 Mar 2006 16:25 GMT
Chris,
You are right to worry about the Thread issue.
I did my share of fretting about it too, and eventually
took *out* the EDT stuff that I originally had.
The removal made no difference in the error caused.

See the Java code in my message of Mar 14 2006 9:50 am;
it runs reliably fine if you invoke it via "java GUIApp".
The only call to any of the GUI stuff is in this line:
       JOptionPane.showMessageDialog(frame, "I'm up!");
This method blocks and waits for user confirmation, so
there is no requirement for an event thread.

But all that seems moot anyway, because I can't get the
JFrame to start at all.
hs
Chris Uppal - 15 Mar 2006 11:09 GMT
> The only call to any of the GUI stuff is in this line:
>         JOptionPane.showMessageDialog(frame, "I'm up!");
> This method blocks and waits for user confirmation, so
> there is no requirement for an event thread.

Whether, when, and why the platform-specific AWT implementation sees fit to
start an EDT (or any other threads necessary for its internal implementatin) is
not something you can determine on that basis.  Since you mentioned that your
debugging output continued even though there was a stack trace caused
apparently at the previous line, it seems very likely that the Mac AWT
implementation does ensure that the EDT is running in this instance.

   -- chris
HenStepper - 17 Mar 2006 23:35 GMT
Thank you, Chris and Gordon.
You both sent me in the right direction.
It was a threading issue (in spite of my mental model) and it was
a Mac-specific issue (which the Linux code brought to light).
I ended up with all the final details to solve this problem at:
http://developer.apple.com/samplecode/simpleJavaLauncher/simpleJavaLauncher.html
hs
Chris Uppal - 18 Mar 2006 11:28 GMT
> It was a threading issue (in spite of my mental model) and it was
> a Mac-specific issue (which the Linux code brought to light).
> I ended up with all the final details to solve this problem at:

http://developer.apple.com/samplecode/simpleJavaLauncher/simpleJavaLauncher.html

Thanks for the follow-up.  Interesting to see that they force a new thread in
their launcher.  Unfortunate that the (otherwise) well-commented code
doesn't explain why.

   -- chris


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.