|
Registriert seit: 22. Dez 2006 Ort: Friedrichroda 38 Beiträge |
#1
Hallo.
Ich habe ein kleines Problem eine DOS- Anwendung mittels eines Delphi- Programms zu steuern. Es gibt ein Konsolenprogramm, welches rein Textbasiert (keine Menü- Masken) arbeitet. Also so wie man die ersten Pascal- Programme kennt. In der Art: Wählen Sie die 1 um dies zu tun, Wählen Sie die 2 um dies zu tun. Sie haben die 2 gewählt, geben Sie den Wert für xyz an. usw. Im Rahmen eines größeren bestehenden Delphi- Projektes soll nun dieses Programm angesteuert werden. Die Grundidee war nun, mittels CreateProcess dieses zu öffnen und die Standardein- und -ausgaben umzuleiten, um diese zu lesen und darauf zu reagieren. Dazu habe ich einiges ausprobiert, aber irgendwie will das nicht richtig laufen. Vielleicht hat jemand ein passendes Beispiel oder Tipps, was ich falsch mache. Der Rumpf der Ansteuerung steckt in einer Klasse. Der betreffende Teil sieht so aus:
Delphi-Quellcode:
Mit dieser Variante kamen aber nur ein paar Fetzen der Ausgaben des Consolen Programms an. Die Umleitung scheint zu funktionieren, aber eben nicht richtig.
var
StartupInfo: TStartupInfo; ProcessInfo: TProcessInformation; Buffer: array[0..255] of char; bRead: DWord; hRead, hWrite: THandle; saAttr: TSECURITYATTRIBUTES; Output: TMemoryStream; CommandArgument: string; Log:TextFile; begin saAttr.nLength := sizeof(TSECURITYATTRIBUTES); saAttr.bInheritHandle := true; saAttr.lpSecurityDescriptor := nil; if not CreatePipe(hRead, hWrite, @saAttr, 0) then begin ShowMessage('Pipe konnte nicht erstellt werden.'); Exit; end; try FillChar(StartupInfo, Sizeof(StartupInfo), #0); StartupInfo.cb := Sizeof(StartupInfo); StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; StartupInfo.wShowWindow := SW_HIDE and SW_SHOWMINNOACTIVE; StartupInfo.hStdInput := hRead; StartupInfo.hStdOutput := hWrite; StartupInfo.hStdError := hRead; AssignFile(Log,'H:\DOS_TEST.log.txt'); if FileExists('H:\DOS_TEST.log.txt') then Append(Log) else Rewrite(Log); CommandArgument:='H:\DosPrg.exe ' + FCreateArguments; Writeln(Log, 'Aufruf: '+CommandArgument); if not CreateProcess(nil, PChar(CommandArgument), nil, nil, True, 0, nil, PChar('H:\'), StartupInfo, ProcessInfo) then begin ShowMessage('Fehler beim Erstellen des Prozesses'); end else begin while WaitforSingleObject(ProcessInfo.hProcess, 0) <> WAIT_OBJECT_0 do; Output := TMemoryStream.Create; Output.Clear; repeat Buffer := #0; if ReadFile(hRead, Buffer, 80, bRead, nil) then begin Output.WriteBuffer(Buffer, bRead); Write(Log, Buffer); Output.Position := bRead; end else break; until bRead <> 80; Output.Position := 0; Buffer := #0; output.Read(Buffer, output.Size); Writeln(Log, Buffer); FreeAndNil(Output); end; finally CloseHandle(hRead); CloseHandle(hWrite); CloseFile(Log); ShowMessage('Ende'); end; Ebenfalls seltsam war, dass das Consolenprogrammen gleich dannach geschlossen wurde, obwohl es normalerweise die Eingabe eines großen Q (also die Tastenkombination Umschalt+Q) braucht. Jetzt war meine Idee, dass das andere Programm durch das Delphi- Programm wieder geschlossen wird und die Ausgabe nur zeitweise umgeleitet wird. Also habe ich versucht den Buffer der Umleitung ständig zu überwachen in einem eigenen Thread. Dazu habe ich eine zweite Klasse geschrieben:
Delphi-Quellcode:
anschließend habe ich die Steuer- Routine wie folgt geändert:
const
cBufferSize = 4096; type tBuffer = ARRAY[1..cBufferSize] of Byte; tReadPipe = class(TThread) private FPipe : THandle; FThreadExit : boolean; FCritical : TCriticalSection; FTestLog : TextFile; function BufferToString(Buffer:tBuffer):string; protected public constructor Create(ReadPipe : THandle); destructor Destroy;override; procedure Execute;override; procedure Start; procedure Stop; published end; constructor tReadPipe.Create(ReadPipe : THandle); var LogFileName:string; begin inherited Create(true); FThreadExit:=false; Self.Priority:=tpNormal; Self.FreeOnTerminate:=true; FCritical:=TCriticalSection.Create; FPipe:=ReadPipe; LogFileName:='H:\'+IntToStr(Self.Handle)+'.log.txt'; AssignFile(FTestLog, LogFileName); if FileExists(LogFileName) then Append(FTestLog) else ReWrite(FTestLog); end; destructor tReadPipe.Destroy; begin CloseFile(FTestLog); FCritical.Free; inherited; end; function tReadPipe.BufferToString(Buffer:tBuffer):string; var Zeile : string; i:integer; NullFound : boolean; begin Zeile := ''; i:=1; NullFound:=false; repeat if Buffer[i]<>0 then begin Zeile:=Zeile+Chr(Buffer[i]); end else begin NullFound:=true; end; INC(i); until NullFound or (i>cBufferSize); Result:=Zeile; end; procedure tReadPipe.Execute; var Buffer:tBuffer; Readed:LongWord; begin while not FThreadExit do begin repeat ReadFile(FPipe,Buffer,cBufferSize,Readed,NIL); if Readed>0 then begin Writeln(FTestLog, BufferToString(Buffer)); end; until FThreadExit xor (Readed=0); Sleep(30); end; end; procedure tReadPipe.Start; begin Self.Resume; end; procedure tReadPipe.Stop; begin FCritical.Enter; FThreadExit:=true; FCritical.Leave; end;
Delphi-Quellcode:
Das Verhalten ist nun folgendes:
var
StartupInfo: TStartupInfo; ProcessInfo: TProcessInformation; Buffer: array[0..255] of char; bRead: DWord; hRead, hWrite: THandle; saAttr: TSECURITYATTRIBUTES; Output: TMemoryStream; CommandArgument: string; Log:TextFile; OutputThread : tReadPipe; begin saAttr.nLength := sizeof(TSECURITYATTRIBUTES); saAttr.bInheritHandle := true; saAttr.lpSecurityDescriptor := nil; if not CreatePipe(hRead, hWrite, @saAttr, 0) then begin ShowMessage('Fehler beim Erstellen der Pipe.'); Exit; end; try FillChar(StartupInfo, Sizeof(StartupInfo), #0); StartupInfo.cb := Sizeof(StartupInfo); StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; StartupInfo.wShowWindow := SW_HIDE and SW_SHOWMINNOACTIVE; StartupInfo.hStdInput := hRead; StartupInfo.hStdOutput := hWrite; StartupInfo.hStdError := hRead; AssignFile(Log,'H:\DOS_TEST.log.txt'); if FileExists('H:\DOS_TEST.log.txt') then Append(Log) else Rewrite(Log); CommandArgument:='H:\DosPrg.exe ' + FCreateArguments; Writeln(Log, 'Aufruf: '+CommandArgument); if not CreateProcess(nil, PChar(CommandArgument), nil, nil, True, 0, nil, PChar('H:\'), StartupInfo, ProcessInfo) then begin ShowMessage('Prozess konnte nicht erstellt werden.'); end else begin OutputThread:=tReadPipe.Create(hRead); OutputThread.Start; WaitforSingleObject(ProcessInfo.hProcess, INFINITE); OutputThread.Stop; end; finally CloseHandle(hRead); CloseHandle(hWrite); CloseFile(Log); ShowMessage('Ende'); end; end; Starte ich das Programm über die IDE normal, reagiert es nicht. Die Log- Dateien werden zwar erstellt, aber sind 0 Bytes. Das Consolen Programm bleibt nun aber im Task- Manager sichtbar, scheint also geöffnet zu bleiben. Nur wird scheinbar nichts eingelesen. Setze ich einen BreakPoint auf die Ausführung, werden wieder Teile der Ausgaben gelesen/geschrieben, aber das Consolen Programm schließt sich wieder direkt nach dem Start. Ich sitze da nun schon über eine Woche dran, komme nun aber nicht mehr weiter. Hat also eventuell jemand ein funktionierendes Beispiel oder eine Idee, woran das liegen kann? Entwicklungsumgebung ist Delphi 7 pro. In was das darunter liegende Programm geschrieben ist, weiß ich nicht. Es ist von extern. Umgebung wo es läuft ist Windows XP. |
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |