Wie kann ich die Ausgabe der Konsole in meinem Programm anzeigen? Es ist möglich, aus Delphi heraus einen Kommandozeilenbefehl auszuführen und die Ausgabe, die normalerweise in DOS- bzw. Eingabezeilenfenster erscheint, abzufangen und in einer Stringliste zu speichern. Zentraler Befehl dieses Codes ist CreateProcess. Dieser Win32-API-Befehl erlaubt es, eine Anwendung so detailiert zu starten, dass auch die Ausgabe konfiguriert werden kann (über die Parameter-Struktur StartupInfo). Sie wird hier in eine Pipe (eine Art Datenröhre) umgeleitet, auf die im Beispiel über PipeOutputWrite zugegriffen wird. PipeOutputRead dient anschließend dazu, die dort aufgelaufenen Daten auszulesen und in einen Stream zu schreiben. function GetConsoleOutput(const Command: String; var Output, Errors: T StringList): Boolean; var StartupInfo: TStartupInfo; ProcessInfo: TProcessInformation; SecurityAttr: TSecurityAttributes; PipeOutputRead: THandle; PipeOutputWrite: THandle; PipeErrorsRead: THandle; PipeErrorsWrite: THandle; Succeed: Boolean; Buffer: array [0..255] of Char; NumberOfBytesRead: DWORD; Stream: TMemoryStream; //Initialisierung ProcessInfo FillChar(ProcessInfo, SizeOf(TProcessInformation), 0); //Initialisierung SecurityAttr FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0); SecurityAttr.nLength := SizeOf(SecurityAttr); SecurityAttr.bInheritHandle := true; SecurityAttr.lpSecurityDescriptor := nil; //Pipes erzeugen CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0); CreatePipe(PipeErrorsRead, PipeErrorsWrite, @SecurityAttr, 0); //Initialisierung StartupInfo FillChar(StartupInfo, SizeOf(TStartupInfo), 0); StartupInfo.cb:=SizeOf(StartupInfo); StartupInfo.hStdInput := 0; StartupInfo.hStdOutput := PipeOutputWrite; StartupInfo.hStdError := PipeErrorsWrite; StartupInfo.wShowWindow := sw_hide; StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; Seite 1 / 5
if CreateProcess(nil, PChar(command), nil, nil, true, CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or NORMAL_PRIORITY_C LASS, nil, nil, StartupInfo, ProcessInfo) then result:=true; //Write-Pipes schließen CloseHandle(PipeOutputWrite); CloseHandle(PipeErrorsWrite); //Ausgabe Read-Pipe auslesen Stream := TMemoryStream.Create; while true do succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytes Read, nil); if not succeed then break; Stream.Write(Buffer, NumberOfBytesRead); Stream.Position := 0; Output.LoadFromStream(Stream); Stream.Free; CloseHandle(PipeOutputRead); //Fehler Read-Pipe auslesen Stream := TMemoryStream.Create; while true do succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytes Read, nil); if not succeed then break; Stream.Write(Buffer, NumberOfBytesRead); Stream.Position := 0; Errors.LoadFromStream(Stream); Stream.Free; CloseHandle(PipeErrorsRead); WaitForSingleObject(ProcessInfo.hProcess, INFINITE); CloseHandle(ProcessInfo.hProcess); end else result:=false; CloseHandle(PipeOutputRead); CloseHandle(PipeOutputWrite); Seite 2 / 5
CloseHandle(PipeErrorsRead); CloseHandle(PipeErrorsWrite); Delphi Aufrufbeispiel: Für die Ausgabe und die Fehler wird zunächst eine Stringliste erzeugt. Anschließend wird obige Funktion aufgerufen. Ist sie erfolgreich ausgeführt wurden (Rückgabewert ist true), wird die Output-Stringliste in einem Memo angezeigt. Um Kommandozeilenbefehle ausführen zu können, die keine eigenständigen Anwendungen sind (wie der DOS-Befehl "dir" im folgenden Beispiel) muss der Name des Kommandozeileninterpreters davor stehen. "cmd.exe" ist das unter Windows NT/2000/ XP und "command.com" unter Windows 9x. Der Parameter /c sorgt dafür, dass der Kommandozeilenbefehl ausgeführt und die Kommandozeile anschließend wieder geschlossen wird. procedure TForm1.Button1Click(Sender: TObject); var output, errors: TStringList; output:=tstringlist.create; errors:=tstringlist.create; if GetConsoleOutput('cmd /c dir c:\', output, errors) then Memo1.Lines.AddStrings(output); output.free; errors.free; Weiteres Beispiel: //about.com //09/2001. Capture the Output From a DOS Window { The example runs 'chkdsk.exe c:\' and displays the output to Memo1 Put a TMemo (Memo1) and a TButton (Button1) in your form Put this code in the OnCLick of Button1: } procedure TForm1.Button1Click(Sender: TObject); procedure RunDosInMemo(DosApp:String;AMemo:TMemo); Seite 3 / 5
const ReadBuffer = 2400; var Security : TSecurityAttributes; ReadPipe,WritePipe : THandle; start : TStartUpInfo; ProcessInfo : TProcessInformation; Buffer : Pchar; BytesRead : DWord; Apprunning : DWord; With Security do nlength := SizeOf(TSecurityAttributes); binherithandle := true; lpsecuritydescriptor := nil; if Createpipe (ReadPipe, WritePipe, @Security, 0) then Buffer := AllocMem(ReadBuffer + 1); FillChar(Start,Sizeof(Start),#0); start.cb := SizeOf(start); start.hstdoutput := WritePipe; start.hstdinput := ReadPipe; start.dwflags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW; start.wshowwindow := SW_HIDE; if CreateProcess(nil, PChar(DosApp), @Security, @Security, true, NORMAL_PRIORITY_CLASS, nil, nil, start, ProcessInfo) then repeat Apprunning := WaitForSingleObject (ProcessInfo.hProcess,100); Application.ProcessMessages; until (Apprunning WAIT_TIMEOUT); Repeat BytesRead := 0; ReadFile(ReadPipe,Buffer[0], ReadBuffer,BytesRead,nil); Buffer[BytesRead]:= #0; Seite 4 / 5
Powered by TCPDF (www.tcpdf.org) Delphi OemToAnsi(Buffer,Buffer); AMemo.Text := AMemo.text + String(Buffer); until (BytesRead FreeMem(Buffer); CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); CloseHandle(ReadPipe); CloseHandle(WritePipe); {button 1 code} RunDosInMemo('chkdsk.exe c:\',memo1); Eindeutige ID: #0 Verfasser: Markus Stein Letzte Änderung der FAQ: 2006-02-21 22:22 Seite 5 / 5