Entwickler-Ecke
Windows API - Eingabe-/Ausgabereihenfolge bei einer Pipe
.Chef - Mo 15.11.04 22:55
Titel: Eingabe-/Ausgabereihenfolge bei einer Pipe
Hallo,
bei der Verwendung einer Pipe bin ich auf ein merkwürdiges Problem gestoßen. Ich fange die Ausgaben einer x-beliebigen Konsolenanwendung ab, um sie in meinem Programm darzustellen. Funktioniert soweit wunderbar.
Erwartet die Anwendung jedoch eine Eingabe, wird nichts zurückgeliefert. Auch nicht bis zu der Stelle, an der die Eingabe verlangt wird. Erst nach Senden der Eingabewerte durch die Pipe wird die komplette(!) Ausgabe der Anwendung zurückgeliefert.
Zwei Fragen dazu: Warum ist das so? Wie kann ich die Ausgabe bis zur Eingabestelle auch vor der Eingabe empfangen?
Gruß,
Jörg
BenBE - Mo 15.11.04 23:06
Das Phänomän ist mir noch nicht aufgefallen, aber vielleicht liegt es daran, dass Windows erst dann die Ausgaben in die Pipe schreibt, wenn der Prozess beendet wird.
Weiterhin wäre evtl. interessant, wie du die Pipe ausliest, d.h. ob Zeichenweise oder gepuffert. Wenn Zeichenweise, dann wundert mich das ein wenig.
Aber bis jetzt hab ich auch Pipes für solche Sachen stets vermieden. Ich nutz für solche Dinge meist Temp-Files, was zwar etwas langsaer ist, aber recht gut zu funktionieren scheint (hab aber noch nicht mit Eingaben an andere Programme gearbeitet).
Evtl. hast du etwas SRC zum Testen des Phänomäns???
.Chef - Mo 15.11.04 23:26
BenBE hat folgendes geschrieben: |
Das Phänomän ist mir noch nicht aufgefallen, aber vielleicht liegt es daran, dass Windows erst dann die Ausgaben in die Pipe schreibt, wenn der Prozess beendet wird. |
Das wäre eine Erklärung. Würde mich allerdings vor große Probleme stellen.
BenBE hat folgendes geschrieben: |
Weiterhin wäre evtl. interessant, wie du die Pipe ausliest, d.h. ob Zeichenweise oder gepuffert. Wenn Zeichenweise, dann wundert mich das ein wenig. |
Gepuffert. Wie soll das anders gehen?
BenBE hat folgendes geschrieben: |
Evtl. hast du etwas SRC zum Testen des Phänomäns??? |
Der Kern der Sache sieht so aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| ProgRunning:=True; repeat AtWork:=WaitForSingleObject(ProcInfo.hProcess,100); Application.ProcessMessages; PeekNamedPipe(StdOutRead,nil,0,nil,@WaitSize,nil); if WaitSize > 0 then begin repeat BytesRead:=0; ReadFile(StdOutRead,Buffer[0],BufferSize,BytesRead,nil); Buffer[BytesRead]:=#0; OemToAnsi(Buffer,Buffer); Text:=Text+StrPas(Buffer); until BytesRead < BufferSize; end; until AtWork = 0; ProgRunning:=False; |
Geschrieben wird in einer anderen Prozedur:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| var wr, sz: DWORD; pc: PChar; begin if ProgRunning then begin if Key = chr(13) then begin pc:=PChar(Tasten+#13#10); sz:=Length(pc); WriteFile(StdInWrite,pc[0],sz,wr,nil); |
Motzi - Mo 15.11.04 23:29
Das ist "normal".. schau dir einfach mal die Doku zu
FLUSHFILEBUFFERS an...
.Chef - Mo 15.11.04 23:50
Motzi hat folgendes geschrieben: |
Das ist "normal".. schau dir einfach mal die Doku zu FLUSHFILEBUFFERS an... |
Seh ich das richtig, dass ich da 'ne Named Pipe brauche? Hab ich bis jetzt nämlich nicht, das PeekNamedPipe täuscht. ;-)
Motzi - Di 16.11.04 00:25
Nein, nur weil im in dem Beispiel-Code eine Named Pipe verwendet wird heißt das nicht, dass du auch eine Named Pipe brauchst.. IMHO ist es egal um was für ein Objekt es sich handelt, du brauchst eh nur das Handle übergeben..!
.Chef - Di 16.11.04 11:29
Motzi hat folgendes geschrieben: |
IMHO ist es egal um was für ein Objekt es sich handelt, du brauchst eh nur das Handle übergeben..! |
Das Problem ist, dass die anonyme Pipe kein Handle hat, das ich übergeben könnte. Und wenn ich StdOutRead übergebe, passiert nichts.
Etwas ist mir noch aufgefallen, was die ganze Sache noch seltsamer macht: Führe ich z.B. Ping durch die Pipe aus, erscheint die Ausgabe auch häppchenweise, also wie normal. Also die Theorie mit dem "erst nach Programmende" ist damit widerlegt.
Motzi - Di 16.11.04 12:59
Die Theorie mit "erst nach Programmened" hat auch nie gestimmt.. aber spätestens beim Programmende wird der Buffer auf jeden Fall geflushed, insofern kommt man also leicht zu diesem (falschen) Schluss..
Es sollen ja auch die geschriebenen Daten aus dem Zwischenpuffer geflushed werden -> schonmal probiert das Write-Handle zu übergeben? BTW:
PSDK hat folgendes geschrieben: |
Anonymous pipes are implemented using a named pipe with a unique name. Therefore, you can often pass a handle to an anonymous pipe to a function that requires a handle to a named pipe. |
.Chef - Di 16.11.04 13:33
Motzi hat folgendes geschrieben: |
Es sollen ja auch die geschriebenen Daten aus dem Zwischenpuffer geflushed werden |
Um das nochmal kurz zu verdeutlichen: Ich habe streng genommen zwei Pipes, eine für die Ausgabe und eine für die Eingabe.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| if CreatePipe(StdOutRead,StdOutWrite,@Security,0) then if CreatePipe(StdInRead,StdInWrite,@Security,0) then begin with StartInfo do begin cb:=SizeOf(StartInfo); hStdInput:=StdInRead; hStdOutput:=StdOutWrite; |
StdInRead und StdOutWrite sind damit die Pipe-Enden auf der "anderen" Seite, und ich nutze auf "meiner" Seite StdOutRead zum Lesen und StdInWrite zur Eingabe.
Motzi hat folgendes geschrieben: |
-> schonmal probiert das Write-Handle zu übergeben? |
Ich habe natürlich schon alle Handles auf Teufel-komm-raus geflusht. Bei keinem passiert irgendetwas, außer bei StdOutWrite, da bleibt das Programm hängen. :shock:
Motzi hat folgendes geschrieben: |
BTW: PSDK hat folgendes geschrieben: | Anonymous pipes are implemented using a named pipe with a unique name. Therefore, you can often pass a handle to an anonymous pipe to a function that requires a handle to a named pipe. |
|
Was ich daran noch nicht durchschaut habe ist folgendes: Im MSDN-Beispiel von oben wird das Handle der Named Pipe übergeben, was man bei CreateNamedPipe zurückbekommt. Bei der anonymen Pipe habe ich ja nur meine seperaten Lese- und Schreibhandles, aber kein globales Pipe-Handle. Also was nehmen? :gruebel:
BenBE - Di 16.11.04 19:28
Erzeug einfach nur ein einziges Handle mit Lese- UND Schreibzugriff- und übergebe dieses dann.
.Chef - Fr 19.11.04 11:34
BenBE hat folgendes geschrieben: |
Erzeug einfach nur ein einziges Handle mit Lese- UND Schreibzugriff- und übergebe dieses dann. |
Wie soll das dann aussehen? Ich krieg ja schon Probleme beim PeekNamedPipe, wenn ich nur eine Pipe verwende. Und dann nur ein Handle? :shock:
.Chef - Di 23.11.04 16:41
Kurzes Update des Entwicklungsstandes (im Moment wieder Zeitknappheit):
- Also mit einem Handle kireg ich das nicht zm laufen, wie auch immer du das meinst.
- Das Problem tritt nur auf bei Konsolenprogrammen mit längeren Eingaben (z.B. programmiert mit ReadLn). Bei Ein-Buchstaben-Eingaben (z.B. bei XCOPY) gehts so wie von mir gewünscht.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!