J'utilise JNI pour appeler une méthode java statique qui à son tour crée une JFrame Swing et l'affiche. Le code est assez simple et le code Java fonctionne de manière autonome (c'est-à-dire que java StartAWT
fait ce qu'il doit) alors que lorsqu'il est appelé depuis C en utilisant JNI, le processus se bloque. J'utilise le JDK 1.7.0_09 sur Mac OS X 10.8 Mountain Lion.Java JNI: Création d'une fenêtre Swing à l'aide de JNI à partir de C
C'est le code C J'utilise pour appeler la méthode statique:
JavaVM* jvm;
JNIEnv* env = create_vm(&jvm);
jclass class = (*env)->FindClass(env, "StartAWT");
jmethodID method = (*env)->GetStaticMethodID(env, class, "run", "()V");
(*env)->CallStaticVoidMethod(env, class, method);
(*jvm)->DestroyJavaVM(jvm);
La classe StartAWT
ressemble à ceci:
public class StartAWT {
public static class Starter implements Runnable {
public void run() {
System.out.println("Runnning on AWT Queue.");
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("That's a frame!");
JLabel label = new JLabel("A Label");
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
public static class GUI implements Runnable {
public void run() {
try {
System.out.println("Going to put something on the AWT queue.");
SwingUtilities.invokeAndWait(new Starter());
} catch (Exception exc) {
throw new RuntimeException(exc);
}
}
}
public static void run() {
Thread gui = new Thread(new GUI());
gui.start();
}
}
Lorsque je démarre l'application, je ne vois Going to put something on the AWT queue
mais pas Running on AWT Queue
. Je crois que la machine virtuelle dans mon processus C n'a pas de file d'attente d'événements AWT mais je ne sais pas comment la configurer pour en avoir une (et je ne suis pas sûr que ce soit la raison).
Que faire pour afficher une interface graphique AWT utilisant JNI?
-
EDIT: Je ai inséré des boucles pour voir quels fils sont en vie et qui ne sont pas (peut être vu dans this gist). Dans cette version, je fais l'invocation de SwingUtilities.invokeAndWait
dans un autre thread. Le résultat: Le thread principal est vivant (C). Le premier thread envoyé par Java (pas le thread principal) est vivant; le fil faisant l'appel invokeAndWait
est bloqué (je ne pense pas que invokeAndWait est même revenu), la fonction qui doit être exécutée sur EventQueue n'est même pas entrée.
J'ai aussi essayé d'invoquer SwingUtilities.invokeAndWait
directement, ce qui donne le message suivant:
2013-02-02 13:50:23.629 swing[1883:707] Cocoa AWT: Apple AWT Java VM was loaded on first thread -- can't start AWT. (
0 liblwawt.dylib 0x0000000117e87ad0 JNI_OnLoad + 468
1 libjava.dylib 0x00000001026076f1 Java_java_lang_ClassLoader_00024NativeLibrary_load + 207
2 ??? 0x000000010265af90 0x0 + 4335185808
)
C'est aussi ce que je l'ai lu dans d'autres questions à poser sur StackOverflow, comme celui suggéré dans les commentaires au dessous de. Cependant, je n'ai pas trouvé de solution au problème original. Peut-être vaut-il la peine de noter qu'après que le message ci-dessus est apparu, le thread principal est toujours en vie, c'est-à-dire que le processus ne s'est pas bloqué ni ne s'est écrasé.
-
EDIT: J'ai testé le code sur Linux où il fonctionne comme prévu. Donc, je crois que c'est un problème de Mac OS X avec Cocoa AWT, mais je ne sais pas comment le contourner.
-
EDIT: Je essayé aussi déplacer l'invocation complète de la machine virtuelle Java sur un nouveau thread natif. Cela fonctionne sur Mac OS X 10.6 avec Apple Java 32 bits (1.6.0_37), mais entraîne le même blocage que décrit ci-dessus. Sur Mac OS X 10.8 c'est pire, l'application se bloque avec le seul message "Trace/BPT trap: 5" (qui seems to be related to loading dynamic libraries).
J'ai aussi essayé le binaire comme regroupement décrit in this Q&A, mais le lancement échoue avec le message lsopenurlswithrole() failed with the message -10810
, ce qui est une erreur inconnue, selon des pommes Launch Services Reference. Ce dernier se produit également sans essayer d'utiliser AWT (la simple invocation JVM échoue).
Voir aussi cette [Q & A] (http://stackoverflow.com/q/8750690/230513). – trashgod
Merci, j'ai vérifié cette Q & A et joué avec mon application; mais cela ne marche pas après tout (comme dans l'autre question, aucune solution n'est donnée là aussi). – scravy
J'ai obtenu un résultat similaire; J'utilise simplement 'JavaApplicationStub', mais je ne sais pas comment cela fonctionne. Je me demande si 'JVM TI', cité [ici] (http://stackoverflow.com/a/14492574/230513), a quelque chose de pertinent. – trashgod