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
Karl-Heinz schrieb: > mittels popen() open ist ein wenig altmodisch CreateProcess ist das etwas flexibler: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
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 | char buff[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.
Ok danke. Mit Threads habe ich noch nie gearbeitet. Wie würde ein eigener Thread denn aussehen?
1 | DWORD WINAPI deineFunktion( LPVOID i_par ) |
2 | {
|
3 | ParameterFueDeineFunktion* par = (ParameterFueDeineFunktion*)i_par; |
4 | // mach irgendwas
|
5 | }
|
6 | |
7 | |
8 | ...
|
9 | DWORD threadId; |
10 | ParameterFueDeineFunktion parameterFueDeineFunktion; |
11 | CreateThread(NULL, 0, &deineFunktion, ¶meterFueDeineFunktion, 0, &threadId); |
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
Also ich das hier so in die dlg.cpp eingefügt. Leider wird m_out als undefined deklariert:
1 | DWORD WINAPI deineFunktion( LPVOID i_par ) |
2 | {
|
3 | FILE *in; |
4 | char buff[512]; |
5 | |
6 | if(!(in = _popen("\"c:\\users\\admin\\documents\\visual studio 2010\\projects\\out\\debug\\out.exe\"", "r"))) |
7 | {
|
8 | // fehler
|
9 | }
|
10 | else
|
11 | {
|
12 | m_out.SetWindowTextW(_T("start...")); |
13 | m_out.RedrawWindow(); |
14 | |
15 | while(fgets(buff, 512, in)) |
16 | {
|
17 | m_out.SetSel(MAXLONG,MAXLONG); |
18 | m_out.ReplaceSel(CString(buff)); |
19 | |
20 | if (!AfxGetThread()->PumpMessage()) return; |
21 | }
|
22 | }
|
23 | _pclose(in); |
24 | }
|
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.
:
Bearbeitet durch User
Ich bekomm ich nicht zum laufen. Wenn das die einzige Möglichkeit war, siehts schlecht aus. Trotzdem danke!
Ein einfaches Beispiel gibts z.B. hier: http://www.codeproject.com/Articles/2459/Using-AfxBeginThread-with-class-member-controlling
Danke das Beispiel hat wirklich geholfen. Allerdings immer noch das gleiche Ausgangeproblem. Der Text wird erst angezeigt, nachdem die Konsolenanwendung beendet ist...
Du kannst doch den "Standardoutput" eines Prozesses einfach "umbiegen".
1 | private Process myProgram = new Process(); |
2 | |
3 | myProgram.StartInfo.UseShellExecute = false; |
4 | myProgram.StartInfo.RedirectStandardOutput = true; |
5 | myProgram.StartInfo.RedirectStandardError = true; |
6 | myProgram.StartInfo.RedirectStandardInput = true; |
7 | myProgram.StartInfo.CreateNoWindow = true; |
8 | ...
|
dann einen Lesethread starten, der die Ausgabe immer zB in einer "TextBoxConsole" ausgibt. Lesethread:
1 | StreamReader myStreamReader = starterBatch.StandardOutput; |
2 | |
3 | try
|
4 | {
|
5 | string l; |
6 | reader_running = true; |
7 | while ((((l = myStreamReader.ReadLine()) != null)) && (reader_running==true) ) |
8 | {
|
9 | textBoxConsole.AppendText(l + "\r\n"); |
10 | }
|
11 | |
12 | }
|
...so habe ich das mal gemacht.
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
Da bekomme ich nur Fehlermeldungen, ist das eine Syntax für MFC?
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.
Kann es vielleicht daran liegen, das während die Konsolenanwendung läuft, die GUI nicht aktiv 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)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.