Umleiten von STD_IN und STD_OUT einer Anwendung

Ich habe folgendes Problem bzw. „Ungereimtheit“!

Mein kleines Programm erstellt einen Prozess via CreateProcess und zwei anonyme Pipes zur Umleitung der STD_Input- und STD_Output-Handles des erzeugten Prozesses.

Soweit funktioniert auch alles wunderbar.

Jetzt taucht aber eine seltsame Begebenheit auf:

Wenn ich zum Beispiel das Programm plink.exe, ein Consolenfrontend für den PuTTy-SSH-Client, verwende, dann kann ich von meinem Programm aus schön einfach in den Standardeingabestrom schreiben, bzw. vom Standardausgabestrom lesen.

Verwende ich allerdings ftp.exe von Microsoft (Habe es auch schon mit php.exe versucht! Ist also kein MS-Phänomen!), so hängt mein Programm bei dem Versuch vom Standardausgabestrom zu lesen so lange, wie ftp.exe läuft. Beende ich ftp.exe via TaskManager, so läuft mein Programm wieder weiter, natürlich mit einem Fehler, da jetzt das lesen der Pipe fehlschlägt, da ftp.exe ja nicht mehr läuft.

Um das ganze noch mysteriöser zu machen gibt es hier noch zwei verschiedene Szenarien.

Setze ich STARTUPINFO.wShowWindow bei Ausführugn von CreateProcess so, dass ftp.exe ohne Fenster ausgeführt wird, so tritt oben beschriebenes Verhalten ein.
Setze ich STARTUPINFO.wShowWindow bei Ausführugn von CreateProcess aber so, dass ftp.exe „normal“ also mit Fenster ausgeführt wird, so gelingt das lesen des Ausgabestroms problemlos. Dummerweise funktioniert dann aber die Umleitung des Eingabestroms nicht mehr, so dass ich die FTP-Befehle per Hand in das Fenster von ftp.exe eingeben muss.

Unter Verwendung von plink.exe ist die Ausführung bzgl. der Fenstereigenschaft jedoch irrelevant und es funktioniert in jedem Fall.

Was ist also der Unterschied zwischen Anwendungen wie plink.exe bei denen das beschriebene Verfahren funktioniert und ftp.exe bei dem es nicht, bzw. nur unzureichend funktioniert?

Weiss da jemand Rat?

Gruß
Heiko

C++?
schaut nicht nach VB-Programm aus…

Und wie das ein VB Prog ist!

Ich kann den Quellcode gerne posten, wenn interesse besteht!

Gruß
Heiko

OK!! Ich glaub’s Dir. Um das Problem besser zu erkenn poste bitte mal den Code, wo die mittels API ein anderes Programm startest und den Code, wo Du über die Pipe Daten zurückbekommst.

VG, Stefan :wink:

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hier der wesentlche Teil des Quelltextes!
Ich hoffe es ist einigermassen leserlich!

---------------- Start ------------------------------
API-Deklarationen gesnippt!

Private Sub ExecCmd(cmdline$)
Dim proc As PROCESS_INFORMATION, ret As Long, bSuccess As Long
Dim start As STARTUPINFO
Dim sa As SECURITY_ATTRIBUTES
Dim i As Integer
Dim createflags As Long

mybuff = String(1024, Chr$(65))

sa.nLength = Len(sa)
sa.bInheritHandle = 1&
sa.lpSecurityDescriptor = 0&

ret = CreatePipe(hReadPipe, hWritePipe, sa, 0)
If ret = 0 Then
MsgBox "CreatePipe Write failed. Error: " & Err.LastDllError
Exit Sub
End If

ret = CreatePipe(hReadPipe3, hWritePipe3, sa, 0)
If ret = 0 Then
MsgBox "CreatePipe STDIN failed. Error: " & Err.LastDllError
Exit Sub
End If

start.cb = Len(start)
start.dwFlags = STARTF_USESTDHANDLES Or STARTF_USESHOWWINDOW
start.hStdOutput = hWritePipe
start.hStdInput = hReadPipe3
start.wShowWindow = SW_HIDE
'start.dwFlags = STARTF_USESHOWWINDOW

ret& = CreateProcessA(0&, cmdline$, sa, sa, 1&, NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)
If ret 1 Then
MsgBox "CreateProcess failed. Error: " & Err.LastDllError
End If

ret& = CloseHandle(hWritePipe)
ret& = CloseHandle(hReadPipe3)

ret& = CloseHandle(proc.hProcess)
ret& = CloseHandle(proc.hThread)

Dim bret As Boolean

readcomplete = True
proceed = False
getprompt = False
Dim isphp As Boolean
isphp = False

If Not isphp Then
’ erste Ausgabe lesen
Timer1.Enabled = True
Do
DoEvents
Loop Until proceed
readcomplete = False
Text1.Text = Text1.Text & ReadStr
Do
DoEvents
Loop Until readcomplete
’ system prompt ermitteln
bret = WriteStr("")
getprompt = True
proceed = False
Timer1.Enabled = True
Do
DoEvents
Loop Until proceed
readcomplete = False
Text1.Text = Text1.Text & ReadStr
readcomplete = True
Do
DoEvents
Loop Until readcomplete
Else
bret = WriteStr(" phpinfo(); ?>")
proceed = False
Timer1.Enabled = True
Do
DoEvents
Loop Until proceed
readcomplete = False
Text1.Text = Text1.Text & ReadStr
readcomplete = True
Do
DoEvents
Loop Until readcomplete
End If
End Sub

Private Sub Command1_Click()

ExecCmd („E:\PuTTy\plink.exe -ssh -pw pwd [email protected]“)

’ ExecCmd („G:\PHP4.1.0-WinInstaller\php-4.1.0-Win32\PHP.exe“)
’ ExecCmd („C:\Windows\ftp.exe“)

End Sub

Private Function WriteStr(tmpstr As String) As Boolean
Dim writebuff As String
Dim bytewritten As Long
Dim bSuccess As Boolean
writebuff = tmpstr '& Chr(13)

bSuccess = WriteFile(hWritePipe3, writebuff, Len(writebuff), bytewritten, 0&amp:wink:

WriteStr = bSuccess
End Function

Private Function ReadStr() As String
Dim bSuccess As Boolean
Dim mybuff As String * 500
Dim bytesread As Long
Dim retcomm As String

Dim retstr As String

mybuff = String(500, Chr$(65))
Do
bSuccess = ReadFile(hReadPipe, mybuff, 500, bytesread, 0&amp:wink:
If bSuccess Then
If getprompt Then
prompt = Right(Replace(Replace(Left(mybuff, bytesread), Chr(13), „“), Chr(10), „“), 3)
getprompt = False
Else
retcomm = Replace(Replace(Left(mybuff, bytesread), Chr(13), „“), Chr(10), vbCrLf)
If InStr(retcomm, prompt) Then
readcomplete = True
Else
readcomplete = False
End If
retstr = retstr & retcomm
End If
Else
MsgBox "ReadFile failed. Error: " & Err.LastDllError
End If
Loop Until bytesread 500

If Not readcomplete Then
Timer1.Enabled = True
End If
ReadStr = retstr
End Function

Private Sub Command2_Click()
WriteNow Text2.Text
Text2.Text = „“
End Sub

Private Sub Command3_Click()
quit
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
quit
End Sub

Private Sub Timer1_Timer()
Dim bytesread As Long
Dim bytesavail As Long
Dim bytesleft As Long
Dim ret As Long

ret = PeekNamedPipe(hReadPipe, 0&, 0&, bytesread, bytesavail, bytesleft)

If bytesavail > 0 Then
Timer1.Enabled = False
If Not readcomplete Then
Text1.Text = Text1.Text & ReadStr
Call ScrollDown
ElseIf proceed = False Then
proceed = True
End If
End If
End Sub

Private Sub ReadNow()
Timer1.Enabled = True
Do
DoEvents
Loop Until proceed
readcomplete = False
Text1.Text = Text1.Text & ReadStr
Call ScrollDown
Do
DoEvents
Loop Until readcomplete
End Sub

Private Sub WriteNow(tstr As String)
Dim bret As Boolean
bret = WriteStr(tstr)
proceed = False
readcomplete = True
ReadNow
End Sub

Private Sub quit()
Dim ret&
ret& = CloseHandle(hReadPipe)
ret& = CloseHandle(hWritePipe3)
End
End Sub
Private Sub ScrollDown()
Dim noflines As Long
noflines = SendMessage(Text1.hWnd, EM_GETLINECOUNT, 0&, 0&amp:wink:

If noflines > 18 Then
noflines = SendMessage(Text1.hWnd, EM_LINESCROLL, 0&, (noflines - 18))
End If
End Sub

---------------------- Ende --------------------

Gruß
Heiko

Und?
Und?