Hi, wenn ich in meinem Win32-Programm einen Prozess per createProcess erzeuge und die Std-Ein/Ausgabe in Pipes umlenke, dann terminiert der letzte Read-Zugriff auf die Output-Pipe nicht. Die einzige Abhilfe bis jetzt ist GetExitCodeProcess kurz vor dem Read-Zugriff, was ein STILL_ACTIVE auswirft. Ich bin mir aber relativ sicher, dass ein Read-Zugriff automatisch bei Prozessterminierung ebenfalls terminieren kann. Habe ich vlt. vergessen, ein Flag oÄ zu setzen? Gruss
Hast du auch auch sicher gestellt, dass das schreibende Ende entweder nicht auch vererbt worden ist oder in allen Prozessen, die es vererbt bekommen haben, auch geschlossen worden ist?
tictactoe schrieb: > Hast du auch auch sicher gestellt, dass das schreibende > Ende entweder nicht auch vererbt worden ist > oder in allen Prozessen, die es vererbt > bekommen haben, auch geschlossen worden ist? Sorry, habe seit Jahren kaum noch was mit Prozessen und Pipes gemacht, ich stelle am besten mal eine gekürzte Version hier rein.
Hast du es mal ohne das STARTF_USESTDHANDLES und Inheritance getestet?
Peter II schrieb: > Hast du es mal ohne das STARTF_USESTDHANDLES und Inheritance > getestet? ohne STARTF_USESTDHANDLES: keine Umleitung der Ausgabe (Ausgabe wird direkt im Koonsolenfenster ausgegeben, die Output-Pipe wird scheinbar nicht verwendet) Ohne Inheritance: kein Unterschied, Inheritance wird aber glaube ich benötigt.
Sigi schrieb: > ohne STARTF_USESTDHANDLES: keine Umleitung der Ausgabe > (Ausgabe wird direkt im Koonsolenfenster ausgegeben, > die Output-Pipe wird scheinbar nicht verwendet) > > Ohne Inheritance: kein Unterschied, Inheritance wird > aber glaube ich benötigt. wenn ich die doku richtig verstehe ist Inheritance etwas anders. Statt dem STARTF_USESTDHANDLES verwende mal hStdInput, hStdOutput und hStdError
Das werde ich mal Morgen Früh ausprobieren und mich erst mal wieder in die Docs eingraben. Bis dahin Gute Nacht.
Ich habe noch mal darüber nachgedacht. Es dürfte normal sein, das der Read blockiert. Die Pipe ist ja immer noch offen. Sie wird erst durch das CloseHandle geschlossen. Man könnte ja den nächsten Prozess mit diese Pipe starten.
Ich habe ebenfalls nochmal in die Pipe-Docs reingeschaut. Inheritance muss auf jeden Fall sein (auf Pipes werden ja im ChildProcess zugegriffen etc.). Und ReadFile blockiert solange, bis der entsprechende Write-Seite geschlossen wird. Ich habe das jetzt wie folgt gemacht: DWORD dwExitCode; GetExitCodeProcess(piProcInfo.hProcess,&dwExitCode); if(dwExitCode != STILL_ACTIVE) CloseHandle(g_hStdOut_W); Es muss aber sichergestellt werden, dass die Write-Seite nur einmal geschlossen wird, sonst gibt's einen Fehler. Kann man einfach durch ein Flag lösen. Anschliessend kann von der Read-Seite die restlichen Daten gelesen werden. Inzwischen glaube ich, dass es auch keine andere Möglichkeit gibt, denn wer sonst sollte die Write-Seite schliessen.
Sigi schrieb: > Ich habe ebenfalls nochmal in die Pipe-Docs > reingeschaut. Inheritance muss auf jeden Fall > sein (auf Pipes werden ja im ChildProcess > zugegriffen etc.). kann nicht sein, sonst würde es keinen Sinn machen das es noch die andere Flags gibt. Du willst ja nichts von deinen Prozess vererben, du willst neue Pipes übergeben.
Stimmt, in meiner Source wird ja das entsprechende Flag gelöscht: SetHandleInformation(g_hStdOut_R,HANDLE_FLAG_INHERIT,0) Aber ohne manuelles Freigeben funktioniert es trotzdem nicht. Muss ich mir aber Heute Abend nochmal anschauen.
Erstens ist da ein Bug und zweitens denke ich, dass die Reihenfolge nicht optimal ist. Ich lass das hier mal stehen als Gedächtnisstütze:
1 | if(!CreatePipe(&g_hStdIn_R,&g_hStdIn_W,&saAttr,0)) |
2 | ...
|
3 | |
4 | if(!CreatePipe(&g_hStdOut_R,&g_hStdOut_W,&saAttr,0)) |
5 | ...
|
Der Bug ist hier:
1 | |
2 | // Ensure the read handle to the pipe for STDOUT is not inherited.
|
3 | if(!SetHandleInformation(g_hStdIn_R,HANDLE_FLAG_INHERIT,0)) |
4 | {
|
5 | printf("Error: createStdIn inherited\n"); |
6 | return; |
7 | }
|
8 | |
9 | if(!SetHandleInformation(g_hStdOut_R,HANDLE_FLAG_INHERIT,0)) |
10 | {
|
11 | printf("Error: createStdOut inherited\n"); |
12 | return; |
13 | }
|
Im ersten if soll natürlich g_hStdIn_W statt g_hStdIn_R stehen. Du willst ja das beschreibbare Ende nicht vererben. Und dann solltest du nach dem Starten des Prozesses die nicht benutzten Enden der Pipes schließen, bevor du mit dem Datenaustausch beginnst:
1 | bSuccess = CreateProcess |
2 | (
|
3 | NULL, |
4 | szCmdLine, // command line |
5 | NULL, // process security attributes |
6 | NULL, // primary thread security attributes |
7 | TRUE, // handles are inherited |
8 | 0, // creation flags |
9 | NULL, // use parent's environment |
10 | NULL, // use parent's current directory |
11 | &siStartInfo, // STARTUPINFO pointer |
12 | &piProcInfo // receives PROCESS_INFORMATION |
13 | );
|
14 | |
15 | // If an error occurs, exit the application.
|
16 | if(!bSuccess) |
17 | {
|
18 | printf("Error: createProcess failed\n"); |
19 | return; |
20 | }
|
21 | CloseHandle(g_hStdIn_R); // <- hier |
22 | CloseHandle(g_hStdOut_W); // <- und hier |
tictactoe schrieb: > Im ersten if soll natürlich g_hStdIn_W statt g_hStdIn_R stehen. Meine erste Version war aus mehreren Quellen zusammenkopiert, da ist mir dieser Fehler passiert. Den habe ich aber relativ schnell rausbekommen. tictactoe schrieb: > Und dann solltest du nach dem Starten des Prozesses die nicht benutzten > Enden der Pipes schließen, bevor du mit dem Datenaustausch beginnst: Und genau da lag der eigentliche Knackpunkt: Ohne das Schliessen bleiben die Pipes offen und ReadFile terminiert nicht. Nach dem Schliessen funktioniert's natürlich wunderbar. Und sehr wichtig, weiterer Bug: In meinem Code übergebe ich einmal StdIn und zweimal StdOut (2. mal als StdError), und dass ist gefährlich. Entweder muss hier per DublicateHandle StdOut kopiert (=> StdError als "neuer" Handle) oder aber es muss eine neue Pipe generiert werden. Mit diesen Änderungen klappt's problemlos.
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.