Ausgabe der Konsole in meinem Programm anzeigen |
|
| System | Win9x, WinNT, Win2000, WinXP, Vista, Win7 |
|---|---|
| Ab Delphi-Version | Delphi 1 |
| Letzte Änderung | 28.09.2010 |
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 detailliert 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.
Output, Errors : TStringList) : Boolean;
var
Buffer : array[0..255] of Char;
CreationFlags : DWORD;
NumberOfBytesRead : DWORD;
PipeErrorsRead : THandle;
PipeErrorsWrite : THandle;
PipeOutputRead : THandle;
PipeOutputWrite : THandle;
ProcessInfo : TProcessInformation;
SecurityAttr : TSecurityAttributes;
StartupInfo : TStartupInfo;
Stream : TMemoryStream;
begin
//Initialisierung ProcessInfo
FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);
//Initialisierung SecurityAttr
FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0);
SecurityAttr.nLength := SizeOf(TSecurityAttributes);
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(TStartupInfo);
StartupInfo.hStdInput := 0;
StartupInfo.hStdOutput := PipeOutputWrite;
StartupInfo.hStdError := PipeErrorsWrite;
StartupInfo.wShowWindow := SW_HIDE;
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
CreationFlags := CREATE_DEFAULT_ERROR_MODE or
CREATE_NEW_CONSOLE or
NORMAL_PRIORITY_CLASS;
if CreateProcess(nil,
PChar(Command),
nil,
nil,
True,
CreationFlags,
nil,
nil,
StartupInfo,
ProcessInfo) then
begin
Result := True;
//Write-Pipes schließen
CloseHandle(PipeOutputWrite);
CloseHandle(PipeErrorsWrite);
//Ausgabe Read-Pipe auslesen
Stream := TMemoryStream.Create;
try
while ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil) do
begin
Stream.Write(Buffer, NumberOfBytesRead);
end;
Stream.Position := 0;
Output.LoadFromStream(Stream);
finally
Stream.Free;
end;
CloseHandle(PipeOutputRead);
//Fehler Read-Pipe auslesen
Stream := TMemoryStream.Create;
try
while ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil) do
begin
Stream.Write(Buffer, NumberOfBytesRead);
end;
Stream.Position := 0;
Errors.LoadFromStream(Stream);
finally
Stream.Free;
end;
CloseHandle(PipeErrorsRead);
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
CloseHandle(ProcessInfo.hProcess);
end
else
begin
Result := False;
CloseHandle(PipeOutputRead);
CloseHandle(PipeOutputWrite);
CloseHandle(PipeErrorsRead);
CloseHandle(PipeErrorsWrite);
end;
end;
Aufrufbeispiel:
Für die Ausgabe und die Fehler wird zunächst eine Stringliste erzeugt. Anschließend wird obige Funktion aufgerufen. Wurde sie erfolgreich ausgeführt (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 : TStringList;
Errors : TStringList;
begin
Output := TStringList.Create;
Errors := TStringList.Create;
try
if GetConsoleOutput('cmd /c dir c:', Output, Errors) then
Memo1.Lines.AddStrings(Output);
finally
Output.free;
Errors.free;
end;
end;