QThread und JNI

Alles rund um die Programmierung mit Qt
Antworten
lespaul
Beiträge: 87
Registriert: 11. August 2011 10:07

QThread und JNI

Beitrag von lespaul »

Hallo,

ich habe eine (Java executable archiv) extern.jar welche ich in meinem Qt Projekt mit JNI starte. Läuft auch soweit sogut.

Problem ist folgender: DIe externe.jar hört aufm Lokalhost an ein bestimmtes Port. Diese Message sollte eig. vom Qt-Projekt gesendet werden. Geht net, da die externe.jar durch ihr SocketListen blockiert.

Da aber die KommandoZeile meines Qt-Projekts durch das extern.jar zugemüllt wird und ich das extern.jar unabhängig von meinem Projekt laufen lassen würde, möcht ich es gerne als separaten Thread starten (also am liebstan IN eigener CMD.exe). Im Netz habe ich QThread gefunden und die Header enthält Q_OBJECt und erbt von QThread. Dann Methode run() mit exec() .. Was fehlt mir?:

Code: Alles auswählen

#include <jni.h>
#include "ExternJar.h"

#pragma comment (lib,"C:\\Program Files\\Java\\jdk1.6.0_26\\lib\\jvm.lib")

/// Constructor
ExternJar::ExternJar(const char* pPathToJar, const char* pPathToLib, const char *t_argv, const char *t_path2Package, const char* t_methodName)
{
	int oi = 0;
	options[oi++].optionString = const_cast<char*>(pPathToJar);
	options[oi++].optionString = "-verbose:jni";   
	vm_args.nOptions = oi;
	vm_args.version = JNI_VERSION_1_6;
	vm_args.options = options;
	vm_args.ignoreUnrecognized = JNI_FALSE;

	argumentString = t_argv;
	path2Jar = pPathToJar;
	path2Lib = pPathToLib;
	packagePath = t_path2Package;
	methodName = t_methodName;
	debugMode = 0;
}

void ExternJar::setClassName()
{  
	switch(JNI_CreateJavaVM( &jvm,(void **)&env, &vm_args)) {
		case JNI_ERR:
			printf("\nUnknown Error invoking the JVM\n");
			return;
		case JNI_EDETACHED:
			printf("\nThread detached from the JVM\n");
			return;
		case JNI_EVERSION:
			printf("\nJNI version error\n");
			return;
		case JNI_ENOMEM:
			printf("\nNot enough memory the JVM\n");
			return;
		case JNI_EEXIST:
			printf("\nJVM already created\n");
			return;
		case JNI_EINVAL:
			printf("\nInvalid arguments\n");
			return;
		case JNI_OK:
			if (debugMode == 1)printf("\nJVM created --> Ready ...\n");
	}
	if( NULL == (cls = env->FindClass(packagePath)) ) printf("\nCan't find class %s\n", packagePath);
	else if (debugMode == 1) printf("\nClass %s found!\n", packagePath);
}

void ExternJar::setArgCV()
{
	if (!argumentString) return;
	this->applicationArg0 = env->NewStringUTF(argumentString);
	this->applicationArgs = env->NewObjectArray(1, env->FindClass("java/lang/String"), applicationArg0);
	env->SetObjectArrayElement(applicationArgs, 0, applicationArg0);
}

void ExternJar::setMethodName()
{
	mid = env->GetStaticMethodID(cls, methodName, "([Ljava/lang/String;)V");
	if (debugMode == 1) printf("\nMethod name set to: %s", methodName);
}

void ExternJar::callXMethod()
{		
	// Method call
	if (debugMode == 1) printf("\nCall now \n%s(\"%s\"):", methodName, argumentString);	
	if (mid != NULL) env->CallStaticVoidMethod(cls, mid, applicationArgs);
	else printf("\nMethod %s corrupted!\n", mid);
}

JavaVM * ExternJar::getVM()
{
	return this->jvm;
}

void * ExternJar::getEnv()
{
	return this->env;
}

bool ExternJar::destroyVM()
{
	if (debugMode == 1) printf("\nDestroy VM now!");
	if ( this->getVM()->DestroyJavaVM() == 1 ) return true;
	else return false;
}

void ExternJar::run()
{
	this->setClassName();
	this->setArgCV();
	this->setMethodName();
	this->callXMethod();	
	exec();
}
Ich danke!

Mfg LesPaul
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QThread und JNI

Beitrag von solarix »

Was fehlt mir?:
Keine Ahnung, aber was uns fehlt ist eine Fehlerbeschreibung..
lespaul
Beiträge: 87
Registriert: 11. August 2011 10:07

Re: QThread und JNI

Beitrag von lespaul »

Also gut, diesmal kurz und kanpp:
Die JVM wird in der Shell von meinem Qt-Projekt gestartet. Ich möchte meine jar in einer eigenen Shell (cmd.exe) ausführen.

Gruß LesPaul
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: QThread und JNI

Beitrag von franzf »

Auf deinen letzten Post würd ich sagen -> QProcess. Aber irgendwie war dann der erste Post unnütz, danach dachte ich du hättest ein Socket-Problem und irgend ner Blockierung... Das Wirre "externes .jar", Socket, CMD.exe, QThread, Message hat mit "zugemüllte Shell" wenig bis gar nichts zu tun :/
lespaul
Beiträge: 87
Registriert: 11. August 2011 10:07

Re: QThread und JNI

Beitrag von lespaul »

Ich bin davon ausgegangen, dass mein Host-Qt-Prozess pausiert, da mein Gast-Java-Jar beschäftigt ist (mit socket.listening()).
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QThread und JNI

Beitrag von solarix »

Wenn du einen 2. Prozess startest blockiert da gar nichts.. würden sonst die Beispiele in der Doku von QProcess funktionieren...?
Sauber gekapselt wäre die Thread-Variante natürlich auch eine Möglichkeit, aber Multithreads brauchen mehr Programmierkenntnisse/Erfahrung als Multiprocess... ich würde daher eher zuerst die QProcess-Variante testen...

hth!
lespaul
Beiträge: 87
Registriert: 11. August 2011 10:07

Re: QThread und JNI

Beitrag von lespaul »

solarix hat geschrieben:Wenn du einen 2. Prozess startest blockiert da gar nichts
Blockiert hat es, als ich die *.jar aus meinem QtProjekt mit JNI (Java Native Interface - man kann JavaMethoden aus C++ heraus aufrufen) gestartet habe.
solarix hat geschrieben:ich würde daher eher zuerst die QProcess-Variante testen
Ich bin auch grad an der QProcess Variante dran, vergeblich:

Code: Alles auswählen

QString program = "C:/Program Files/Java/jdk1.7.0/bin/java.exe"; 
QStringList arguments; 
arguments << "-jar" << "C:/MyProject/Project.jar";
QProcess *myProcess = new QProcess();  
myProcess->start(program, arguments); 
Da geht gar nichts. Es taucht eine java.exe lediglich für ne Sekunde auf und verschwidnet wieder. Diese Project.jar hat eine unendliche while(true) schleife, die sekündlich System.out.println("Test"); ausgibt. Aber Pustekuchen. java -jar Project.jar auf commandozeile läuft einwandfrei.

Es ist wichtig, dass meine external.jar in einem eigenen cmd.exe gestartet wird, damit ich die Debugausgaben sehen kann!
solarix hat geschrieben:Sauber gekapselt wäre die Thread-Variante natürlich auch eine Möglichkeit, aber Multithreads brauchen mehr Programmierkenntnisse/Erfahrung als Multiprocess
Ich arbeite mich gerne auch in Multithreads ein, wenn es sabeur läuft.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QThread und JNI

Beitrag von solarix »

lespaul hat geschrieben: Blockiert hat es, als ich die *.jar aus meinem QtProjekt mit JNI (Java Native Interface - man kann JavaMethoden aus C++ heraus aufrufen) gestartet habe..
Logisch.. das ist weder Multiprocess noch Multithreads..
lespaul hat geschrieben: Es ist wichtig, dass meine external.jar in einem eigenen cmd.exe gestartet wird, damit ich die Debugausgaben sehen kann!
Jain.. Es ist nicht wichtig, ob eine eigene Konsole aufgemacht wird oder nicht.. sondern es ist wichtig, dass du an die Debug-Ausgaben rankommst.. Genau dafür bietet QProcess "readAllStandardError()" und "readAllStandardOutput()".. damit du die Programmausgaben des "Kind-Prozesses" behandeln kannst...

hth!
lespaul
Beiträge: 87
Registriert: 11. August 2011 10:07

Re: QThread und JNI

Beitrag von lespaul »

Also allen anschein nach kann ich aus Qt heraus keine java.exe -jar file.jar in einem eigenen Dosfenster starten... Schade.

Mit einer *.bat Datei würde mir noch eifnallen, ist mir aber eig. auch zu blöd..
brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: QThread und JNI

Beitrag von brax »

Das ausführen der java.exe, so wie Du beschrieben hast, funktioniert einwandfrei (gerade getestet). Wenn Du den Grund wissen möchtest, warum es gleich wieder beendet wird, würde ich den Ratschlag von solarix bzgl. des Umleiten von stdout vom QProcess nochmal näher anschauen.

Wenn Du unbedingt möchtest, dass cmd.exe ausgeführt wird, musst Du als executable auch cmd.exe nehmen und dem dann "java.exe -jar ..." als Argumente mitgeben. "cmd.exe /?" gibt da ganz gut Auskunft... Ich befürchte jedoch, dass sich auch dann nicht die von Dir gewünschte Konsole öffnen wird, so dass Du auch in diesem fall die Channels selbst lesen und schreiben müsstest, Dir also quasi eine Konsole nachbauen müsstest.

Wenn Du (wie es den Anschein hat) eh nicht direkt aus dem Qt-Code mit dem Programm interagieren möchtest, kannst Du einfach QProcess::startDetached benutzen. Das öffnet dann auch die von Dir gewünschte Konsole. Nur hast Du dann eben im C++ Code keine Chance an die Ausgabe des Programmes zu kommen, bzw. vom C++ Code Kommandos an das Programm zu schicken.

Nebenbei: Wenn Du das Programm eh als externen Prozess startest, hättest Du Dir die Sache mit dem JNI auch sparen können.
lespaul
Beiträge: 87
Registriert: 11. August 2011 10:07

Re: QThread und JNI

Beitrag von lespaul »

brax hat geschrieben:Nebenbei: Wenn Du das Programm eh als externen Prozess startest, hättest Du Dir die Sache mit dem JNI auch sparen können.
Ich danke! startDetachted() funzt super!

Ja, die Sache mit dem JNI: Habe nun auch gemerkt, dass ich das nicht mehr brauche. Da die beiden Prozesse sehr oft kommunizieren, denke ich das es mit SOckets gut gelöst ist..

Ich danke allen Hinweisgebern!

Gruß LesPaul
Antworten