Hallo,
ich habe mit Visual Studio 2010 eine GUI erstellt. Durch Knopfdruck
öffne ich ein Konsolenprogramm, also die Konsole geht ganz normal auf,
das Programm läuft ab und dann schließt sie sich wieder.
Nun kam ich auf die Idee, dass die Konsole nicht angezeigt werden soll,
sondern im Hintergrund läuft und die aktuelle Ausgabe in einem CEditfeld
angezeigt wird. Hierzu rufe ich mein Programm mittels popen() auf und
sende die Ausgabe an mein CEditfeld.
Allerdings erscheint die Ausgabe erst dann, wenn das Konsolenprogramm
beendet ist. Weiß jemand wie ich die Ausgabe in Echtzeit in meine GUI
bekomme?
Grüße
Mit Create Process hab ich es anfangs versucht, hatte eine pipe.h, eine
pipe.cpp, eine command.h und eine command.cpp und eben die xxxdlg.cpp.
Allerdings mit gleichem Effekt. Die Ausgabe erschien erst dann im
Editfeld, wenn der Prozess beendet wurde.
Mit CreateProcess gehts auf jeden Fall, man muss sich den stdout/stderr
auf eine Pipe ausgeben lassen und von da abholen. Bei GUI-Anwendungen
muss man das GUI-Framework anweisen ein Event (callback) zu generieren
wenn Daten ankommen. Google einfach mal nach "Capture standard / console
output" oder so, du bist nicht der erste der sowas macht.
Karl-Heinz schrieb:> Die Ausgabe erschien erst dann im> Editfeld, wenn der Prozess beendet wurde.
dann hast du was falsch gemacht.
du musst die handels wie hStdOutput verwenden. Diese kann man dann
auslesen.
Peter II schrieb:> Karl-Heinz schrieb:>> Die Ausgabe erschien erst dann im>> Editfeld, wenn der Prozess beendet wurde.>> dann hast du was falsch gemacht.>
Ja logisch hab ich was falsch gemacht :D, ich frag mich halt die ganze
Zeit was. Wenn ich zuhause bin kontrolliere ich mal meine Handles.
So, ich hab es mit Createprocess() halbwegs hinbekommen, unter
Zuhilfenahme einer RT-Konsole von codeproject.
Allerdings verstehe ich beim besten Willen nicht, weshalb dieser Code
nicht den gewünschten Effekt bringt:
1
FILE*in;
2
charbuff[512];
3
4
if(!(in=_popen("\"C:\\Users\\admin\\Documents\\Visual Studio 2010\\Projects\\out\\Debug\\out.exe\"","rt")))
5
{
6
// fehler
7
}
8
else
9
{
10
m_out.SetWindowTextW(_T("start..."));
11
m_out.RedrawWindow();
12
13
while(fgets(buff,512,in)!=NULL)
14
{
15
m_out.SetSel(MAXLONG,MAXLONG);
16
m_out.ReplaceSel(CString(buff));
17
}
18
}
19
_pclose(in);
Beim Debuggen sieht man schön, dass die Ausgabe der out.exe schön
zeilenweise eingelesen wird und immer nur eine Zeile im Puffer steht.
Wieso wird die im Editfeld nicht direkt dargestellt?
Hallo,
kann es sein, dass Du bei der Ausgabe auch mal die Steuerung an die
Steuerung an das GUI übergeben musst ?
Application.DoEvents fällt mir da spontan ein.....
Gruß,
Michael
Die Frage ist jetzt, an welcher Stelle du den popen()-Kram aufrufst.
SetText, ReplaceSel, etc. versenden Windows-Nachrichten an das jeweilige
Control.
Wenn das ganze in einem Button-Click-Handler passiert und nicht in einem
eigenen Thread, kann es z.B. sein dass die Nachrichtenschleife dadurch
blockiert wird.
Vlad Tepesch schrieb:> DWORD WINAPI deineFunktion( ParameterFueDeineFunktion par)> {> // mach irgendwas> }>> ...> DWORD threadId;> ParameterFueDeineFunktion parameterFueDeineFunktion;> CreateThread(NULL, 0, &deineFunktion, ¶meterFueDeineFunktion, 0,> &threadId);
Ok danke, kann ich den Thread dann ganz normal in meinem Button-Handler
aufrufen?
hab noch ein paar Edits gemacht. Die Typen haben vorher nicht gestimmt.
Karl-Heinz schrieb:> Ok danke, kann ich den Thread dann ganz normal in meinem Button-Handler> aufrufen?
du kannst es probieren, sollte klappen. kann aber sein, dass du probleme
bekommst, wenn du aus dem Thread versuchst an der Gui rumzufummeln.
is ja auch klar.
deineFunktion ist keine memberfunktion deines Objektes.
wenn du Daten des Objektes brauchst, musst du das Objekt (den
this-Zeiger ) als Parameter übergeben. das hat natürlich auch zur folge,
dass du nicht auf private member zugreifen kannst, sondern nur auf
public (es sei denn du definierst die Funktion als friend.
Edit:
aber wie gesagt:
Zugriffe auf die Gui aus dem anderen Thread können problematisch sein.
Danke das Beispiel hat wirklich geholfen. Allerdings immer noch das
gleiche Ausgangeproblem. Der Text wird erst angezeigt, nachdem die
Konsolenanwendung beendet ist...
Das ist genau das was Peter II oben schon mit CreateProcess erwähnt hat.
Die .NET-Klasse Process ist ein Wrapper um CreateProcess (oder auch
ShellExecuteEx), hier wird aber scheinbar kein .net-Framework sondern
MFC eingesetzt.
Der CreateProcess-Weg ist auch hier beschrieben:
http://msdn.microsoft.com/de-de/library/ms682499.aspx
--
Hmm, also du kannst z.B. mit nem OutputDebugString() in der
while-Schleife sehen, dass die while-Schleife auch läuft - aber auf der
UI werden keine Änderungen sichtbar?
Was noch auffällt: Laut _popen-msdn-seite:
"If used in a Windows program, the _popen function returns an invalid
file pointer that causes the program to stop responding indefinitely.
_popen works properly in a console application."
Keine MS-Runtime oder Projekt auf Konsolenanwendung stehen? - Oder wieso
kann das überhaupt funktionieren :D
bluppdidupp schrieb:> Hmm, also du kannst z.B. mit nem OutputDebugString() in der> while-Schleife sehen, dass die while-Schleife auch läuft - aber auf der> UI werden keine Änderungen sichtbar?
Genau, ein Breakpoint an die while-Bedingung, und bei jedem Durchlauf
steht in buff die nächste Zeile...
Mit CreateProcess hab ich es die ganze schon versucht, aber auch ohne
Erfolg.
bluppdidupp schrieb:> Hmm, also du kannst z.B. mit nem OutputDebugString() in der> while-Schleife sehen, dass die while-Schleife auch läuft - aber auf der> UI werden keine Änderungen sichtbar?
Achso Moment, nein du hast recht, mit OutputDebugString(CString(buff))
seh ich in meinem VS Output die Werte auch erst, wenn die
Konsolenanwendung beendet ist.
Sofern die Message-Loop des GUI-Threads (in der Regel der 1. Thread des
Prozesses) nicht blockiert wird, wird auch die GUI "laufen"
Wird sie blockiert merkt man das unter neueren Windows-Versionen z.B.
wenn man im Fenster rumklickt und Windows dann nach kurzer Zeit einen
grauen Schleier über das Fenster legt, "(Keine Rückmeldung)" in der
Titelzeile ergänzt und ggf. nach einer Weile ein Fensterchen mit "XYZ
reagiert nicht mehr, [Programm schließen], [Auf Antwort des Programms
warten]" anzeigt.
So wie z.B. hier zu sehen:
http://www.drwindows.de/attachments/30674d1303736312-geloest-explorer-reagiert-nicht-mehr-unbenannt2.png
Das verhindert man in der Regel in dem man länger laufende Operationen
in einem zweiten Thread unabhängig vom GUI-Thread laufen lässt und die
GUI nur alle paar ms mal aktualisiert.
-------
Karl-Heinz schrieb:> Achso Moment, nein du hast recht, mit OutputDebugString(CString(buff))> seh ich in meinem VS Output die Werte auch erst, wenn die> Konsolenanwendung beendet ist.
Ich hätte erstmal weiterhin die _popen()-Funktion in Verdacht der
Übeltäter zu sein ;D
Hab die popen() Funktion rausgeschmissen, war mir zu undurchsichtig,
gehe jetzt wieder über CreateProcess und anschließend Readfile.
Natürlich immer noch keine Rückmeldung der GUI solange die
Konsolenanwendung läuft. Wenn du willst schick ich dir mal das Projekt,
vllt fällt dir was auf. Bin mit meinem Latein echt am Ende -.-
vllt. einfach ne Mini-Version davon hier anhängen, dann könnte man mal
drüberschauen.
(Ich hab aktuell leider keine C/C++ Umgebung installiert. C#/.net'ler
;D)