JNI: Java Methoden von C++ Code aufrufen

Status
Nicht offen für weitere Antworten.

Chris81T

Mitglied
Hallo zusammen.

Mein Bestreben ist es, JAVA Methoden von C++ Code aufzurufen. Dafür dient ja JNI (auch wenn's vorrangig anders rum genutzt wird) und habe mir auch ein Testprojekt erstellt.

Folgendes Problem:

Ich kann nur erfolgreich die main(..) aufrufen. Die testoring(), method1() findet er nicht. Was mache ich falsch??

(Nicht über den Code stören, ist nur ne Spielewiese 🙂 )

JAVA COde:
Code:
class Testor 
{
	public static void method1(int a)
	{
		a = 0;
		System.out.println("JAVA Class: void method1(int a) {..}");
	}
	
	public static void main(String[] args)
	{
		System.out.println("JAVA Class: void main(String[] args) {..}");
		System.out.println("calling testoring()...");
		testoring();
		method1(0);
	}
	
	public static void testoring()
	{
		System.out.println("JAVA Class: void testoring() {..}");
	}
}

C++ Code:
Code:
#include <iostream>
using namespace std;

/*
 * Benötigt für Java Native Interface:
 */
#include <jni.h>
/*
 * ENDE *
 */

int main()
{
	cout << "JNI- Testor:" << endl;
	
	// benötigte Variablen:
	JavaVM * jvm;
	JNIEnv * env;
	JavaVMOption options[1];
	JavaVMInitArgs vm_args;	
	
	// Version festlegen:
	vm_args.version = JNI_VERSION_1_6;
	
	// default Argumente holen:
	JNI_GetDefaultJavaVMInitArgs(&vm_args);
	
	// Pfad zur Java- Klasse festlegen:
	options[0].optionString = "-Djava.class.path=C:\\CHT\\Test- Projects\\JNI_Test";
	vm_args.nOptions = 1;
	vm_args.options = options;
	
	// zur Fehlererkennung:
	jint value;
	
	// JavaVM erzeugen:
	value = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
	if(value < 0)
	{
		cout << value << " : ";
		switch(value)
		{
			case JNI_ERR:
				cout << "JNI_ERR" << endl;
			break;
			case JNI_EDETACHED:
				cout << "JNI_EDETACHED" << endl;
			break;
			case JNI_EVERSION:
				cout << "JNI_EVERSION" << endl;
			break;
			case JNI_ENOMEM:
				cout << "JNI_ENOMEM" << endl;
			break;
			case JNI_EEXIST:
				cout << "JNI_EEXIST" << endl;
			break;
			case JNI_EINVAL:
				cout << "JNI_EINVAL" << endl;
			break;
		}
		return -1;
	}
	else
		cout << "CreateJavaVM success!!" << endl;
	
	// jclass zeigt auf die gewünschte JAVA Klasse:
	jclass javaClass;
	if (javaClass = env->FindClass("Testor"))
		cout << "FindClass success!!" << endl;
	else
		cout << "FindClass failed :(" << endl;
	
	//jmethodID zeigt auf die gewünschte JAVA Methode:
	jmethodID testoring;
	if(testoring = env->GetStaticMethodID(javaClass, "main", "([Ljava/lang/String;)V")) 
	{	
		cout << "GetStaticMethodID success!!" << endl
		     << "now call CallStaticVoidMethod(..)" << endl;
		for(int i=0; i<100; i++)
			 // mit jclass und passender jmethodID wird hier die Funktion ausgeführt:
			 env->CallStaticVoidMethod(javaClass, testoring, 0);
	}
	else
		cout << "GetStaticMethodID failed :(" << endl;
	cout << "JavaVM has finished. Now it's time to destroy it!" << endl;
	
	// zum Schluss wird die VM zerstört:
	jvm->DestroyJavaVM();
	return 0;
}

Kann mir jemand weiterhelfen, bzw. mir en Tipp geben, wo es gute Info's zu "JAVA Methoden von C++ Code aufrufen" gibt?

Vielen Dank
 
In dem Code rufst Du ja nur die main-Methode auf. Wie besorgst Du Dir denn den Pointer auf die anderen beiden Methoden? Ich vermute mal, es stimmt da etwas mit der Signatur nicht.
 
env->CallStaticVoidMethod(javaClass, testoring, 0);

Wie kommst du auf diese Zeile?

Ich vermute mal, du sollstest statt
Code:
0
Code:
()V
oder so schreiben. Schau dir mal die class-Datei an. und nimm dir die Signatur da raus.
 
Anonymous hat gesagt.:
env->CallStaticVoidMethod(javaClass, testoring, 0);

Wie kommst du auf diese Zeile?

Die Zeile scheint mir nicht das Problem zu sein; beim Ausführen der Methode steht die 0 ja nicht für eine Signatur, sondern für den konkreten Parameter.


Relevant ist die Signatur aber beim Beschaffen des Funktionspointers:
Code:
env->GetStaticMethodID(javaClass, "main", "([Ljava/lang/String;)V"))
Bei der main-Methode passt das; "([Ljava/lang/String😉V" steht für ein "String[] als Parameter, kein Rückgabewert (=void). Für die anderen Methoden müsste der String geändert werden, da diese ja eine andere Signatur haben.
 
@Murray:

Code:
env->GetStaticMethodID(javaClass, "main", "([Ljava/lang/String;)V"))

Sorry, es war gestern net viel Zeit zum schreiben.. Ich habe natürlich das "main" durch die anderen Methodennamen ersetzt, aber durch deinen Post habe ich wohl auch das Problem erkannt
>> Die Parameterübergabe muss passend gemacht werden. ( Korrigier mich, falls ich mich irre ). Da ich noch nicht wirklich viel Java programmiert habe, konnte ich anfangs mit dem "([Ljava/lang/String😉V" nicht viel anfangen.

@Gast:
Den Code habe ich mir aus diversen Doku's / (seltenen gefundenen) Beispielen zusammengebaut.
Die 0 soll doch wohl dann der Parameter sein, den man der Funktion übergibt
Wenn ich nun ne Methode habe, die keinen Parameter hat, dann sollte wohl dort ein V stehen??? ( Auch hier bitte mich notfalls korrigieren, danke 🙂 )
 
So müsste das in etwa aussehen:
Code:
jmethodID main      = env->GetStaticMethodID(javaClass, "main",      "([Ljava/lang/String;)V")); //-- args: String[], ret: void
jmethodID method1   = env->GetStaticMethodID(javaClass, "method1",   "(I)V"));                   //-- args: int, ret: void
jmethodID testoring = env->GetStaticMethodID(javaClass, "testoring", "()V"));                    //-- args: none, ret: void
 
Aber JNA ist doch m.W. nur für die andere Richtung geeignet, nämlich für den Aufruf von nativen Methoden aus Java heraus. Hier soll ja aus nativem Code Java aufgerufen werden; es geht also um das Java Invocation API.
 
Vielen Dank Murray!

Die erste Hürde hab ich nun geschafft. Nun kommt die nächste, die ich in einem neuen Thread beschreibe. Vielleicht kannst du da auch mal schauen. Ist wohl was Banales.

Gruß Christian
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben