Output einer Konsolenanwendung in GUI

Gast #3607099
Lesenswert?
• ▲
▼
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
Gast #3607136
Lesenswert?
• ▲
▼
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.
Gast #3607139
Lesenswert?
• ▲
▼
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.
Gast #3607243
Lesenswert?
• ▲
▼
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.
Gast #3608269
Lesenswert?
• ▲
▼
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?
Gast #3608492
Lesenswert?
• ▲
▼
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.
#3608599
Lesenswert?
• ▲
▼
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, &parameterFueDeineFunktion, 0, &threadId);
Gast #3608611
Lesenswert?
• ▲
▼
Vlad Tepesch schrieb:
> DWORD WINAPI deineFunktion( ParameterFueDeineFunktion par)
> {
>   // mach irgendwas
> }
>
> ...
> DWORD threadId;
> ParameterFueDeineFunktion parameterFueDeineFunktion;
> CreateThread(NULL, 0, &deineFunktion, &parameterFueDeineFunktion, 0,
> &threadId);

Ok danke, kann ich den Thread dann ganz normal in meinem Button-Handler 
aufrufen?
Gast #3608641
Lesenswert?
• ▲
▼
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
}
#3608649
Lesenswert?
• ▲
▼
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.
#3608911
Lesenswert?
• ▲
▼
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.
Gast #3608971
Lesenswert?
• ▲
▼
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
Gast #3609002
Lesenswert?
• ▲
▼
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.
Gast #3609781
Lesenswert?
• ▲
▼
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.
Gast #3610662
Lesenswert?
• ▲
▼
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
Gast #3610746
Lesenswert?
• ▲
▼
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 -.-

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren