2017-07-16 5 views
1

Ich entwickle eine Anwendung, die mit einem Hardwaregerät interagiert. Unter Verwendung der DLL-Datei, die mit der offiziellen Anwendung der Hardware geliefert wird, initialisiere ich das Gerät und registriere eine Funktion als einen Rückruf, der bei einer Benutzerinteraktion aufgerufen wird. In dieser Callback-Funktion möchte ich eine Java-Funktion aufrufen, um Daten zu übertragen. Allerdings tritt die gesamte Anwendung ohne Fehlerprotokoll nur an diesem Anruf im Callback:JNI-Aufruf schlägt im Treiber-Callback fehl

jclass cls = env->FindClass("java/lang/String"); 

Der gleiche Anruf funktioniert, wenn es in der Funktion ausgeführt wird, die direkt von Java aufgerufen wird. Was ist der Grund für dieses Verhalten? Wie macht es den Unterschied, JNI von Gerätetreiberanrufen aus anzurufen? Jede Hilfe wird geschätzt.

EDIT: Ich versuchte Vernees Vorschlag und versuchte, den Treiber-Thread an JVM anzuhängen, jedoch änderte sich das Verhalten nicht. Außerdem habe ich die printf Ausgänge verloren, die - leider - meine einzige Option zum Debuggen der JNI-Seite sind. Sie arbeiten vor dem Attach-Vorgang, hören aber auf, danach zu arbeiten.

+2

Werfen Sie einen Blick hier: https://StackOverflow.com/a/12900986/3699139 Die 'JNIEnv *' ist nur gültig für den Thread, der den Aufruf zu nativen macht. –

+0

@JornVernee hast du andere Vorschläge? – ram

+0

Entschuldigung, das war meine einzige Vermutung. –

Antwort

1

Wenn Sie unter Windows entwickeln, empfehle ich Ihnen dringend, dass Sie Visual Studio verwenden, um den C-Code zu debuggen. Sie können Ihr Java-Programm starten und einen Haltepunkt auf System.load setzen, wenn das Java-Programm an dieser Stelle stoppt, zu Visual Studio gehen und über Werkzeuge> Prozess anhängen, können Sie an Haltepunkten im C-Code stoppen. Danach einfach den Java-Code fortsetzen. eine Java-Methode von C-Thread aufrufen erfordert einige preperation:

1- Cache JVM Objekt

JavaVM * javaVm; 
(*jenv)->GetJavaVM(jenv, &javaVm); 

2- Cache das Klassenobjekt der Klasse, die Java-Callback-Methode enthält.

clazz = (*jenv)->NewGlobalRef(jenv, (*jenv)->FindClass(jenv, "com/something/somepackage/SomeClass")); 

3- Wenn Sie Instanzmethode aufrufen, müssen Sie auch die Instanz cahce

zu virtuellen Maschine
callback = (*jenv)->NewGlobalRef(jenv, callbackInstance); 

4- Attach native Thread aufgerufen wird (wenn Sie den Anruf tätigen müssen, um Java-Methode)

JNIEnv * jenv; 
int errorCode = (*j_javaVm)->AttachCurrentThread(j_javaVm, (void**) &jenv, NULL); 

5- Holen Sie sich das ID-Methode Sie aufrufen müssen (Wenn Sie den Anruf zu Java-Methode machen müssen)

6- Stellen des Methodenaufruf

(*jenv)->CallVoidMethod(jenv, cachedCallbackInstance, methodID, param1, param2,....); 

7- deattach der native Thread

(*j_javaVm)->DetachCurrentThread(j_javaVm); 

Stufen 1,2 und 3 erfordern eine Java-Umgebung, und sie können in JNI_OnLoad Methode durchgeführt werden oder in der Implementierung einer nativen Java-Methode.

+0

Ich habe eine Bearbeitung eingereicht, die jedoch nicht genehmigt wurde. Können Sie Ihre Antwort zum JVM-Objekt im Cache einfügen? Es hat anscheinend nicht funktioniert, wenn es in einer globalen Variablen gespeichert ist. Ich löste es, indem ich es in eine Datei schrieb und es dann las, wenn der Treiber meinen C++ - Callback aufruft. – ram