unit Command.old;
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
interface
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
uses Windows, Utilities;
//----------------------------------------------------------------------------
//
//Starting console application and redirect stdoutput
//
//Most console applications send their output to the stdoutput and stderror
//devices and these are normally connected to the console. You can start such an
// application and capture its output, to read and interpret it in your own
// application. To avoid involving the filesystem and permission problems,
// it's best to redirect to pipes and read from them.
//
//Each "ReadFile" operation on a pipe will block, until there is either data
// to read, or the handle of the pipe is closed (no more data).
// An application who sends data to the pipe will fill up the buffer and block
// until someone reads the data at the other end of the pipe. This means,
// if we read more than one pipe, each pipe can block the others, so for a
// save implementation we have to use threads to read the pipes.
//
//----------------------------------------------------------------------------
type
PStoReadPipeThreadParam = ^TStoReadPipeThreadParam;
TStoReadPipeThreadParam = record
Pipe: THandle;
Content: String;
end;
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
function Sto_ReadPipeThreadProc(Parameter: PStoReadPipeThreadParam): Integer;
function Sto_RedirectedExecute(const CmdLine: String;
var Output, Error: String; const Wait: DWORD = 3600000): Boolean;
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
implementation
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
/// <summary>Helper function to Sto_RedirectedExecute.</summary>
function Sto_ReadPipeThreadProc(Parameter: PStoReadPipeThreadParam): Integer;
const
BLOCK_SIZE = 4096;
var
iBytesRead: DWORD;
szBuffer: array[0..BLOCK_SIZE-1] of Char;
iOldLength: DWORD;
begin
Result := 0;
Parameter^.Content := '';
repeat
// try to read from pipe
if ReadFile(Parameter^.Pipe, szBuffer, BLOCK_SIZE, iBytesRead, nil) then
begin
// extend the content string. do it like TStringStream, this way it
// works for strings containing #0 characters as well.
iOldLength := Length(Parameter^.Content);
SetLength(Parameter^.Content, iOldLength + iBytesRead);
Move(szBuffer, PChar(@Parameter^.Content[iOldLength + 1])^, iBytesRead);
end;
// a process may write less than BLOCK_SIZE, even if not at the end
// of the output, so checking for < BLOCK_SIZE would block the pipe.
until (iBytesRead = 0);
end;
/// <summary>
/// Runs a console application and captures the stdoutput and
/// stderror.</summary>
/// <param name="CmdLine">The commandline contains the full path to
/// the executable and the necessary parameters. Don't forget to
/// quote filenames with "" if the path contains spaces.</param>
/// <param name="Output">Receives the console stdoutput.</param>
/// <param name="Error">Receives the console stderror.</param>
/// <param name="Wait">[milliseconds] Maximum of time to wait,
/// until application has finished. After reaching this timeout,
/// the application will be terminated and False is returned as
/// result.</param>
/// <returns>True if process could be started and did not reach the
/// timeout.</returns>
function Sto_RedirectedExecute(const CmdLine: String;
var Output, Error: String; const Wait: DWORD = 3600000): Boolean;
var
mySecurityAttributes: SECURITY_ATTRIBUTES;
myStartupInfo: STARTUPINFO;
myProcessInfo: PROCESS_INFORMATION;
hPipeOutputRead, hPipeOutputWrite: THandle;
hPipeErrorRead, hPipeErrorWrite: THandle;
myReadOutputThreadParam: TStoReadPipeThreadParam;
myReadErrorThreadParam: TStoReadPipeThreadParam;
hThreadOutputRead, hThreadErrorRead: THandle;
iWaitRes: Integer;
iThreadId: DWord;
begin
// prepare security structure
ZeroMemory(@mySecurityAttributes, SizeOf(SECURITY_ATTRIBUTES));
mySecurityAttributes.nLength := SizeOf(SECURITY_ATTRIBUTES);
mySecurityAttributes.bInheritHandle := TRUE;
// create pipes to get stdoutput and stderror
CreatePipe(hPipeOutputRead, hPipeOutputWrite, @mySecurityAttributes, 0);
CreatePipe(hPipeErrorRead, hPipeErrorWrite, @mySecurityAttributes, 0);
// prepare startupinfo structure
ZeroMemory(@myStartupInfo, SizeOf(STARTUPINFO));
myStartupInfo.cb := Sizeof(STARTUPINFO);
// hide application
myStartupInfo.dwFlags := STARTF_USESHOWWINDOW;
myStartupInfo.wShowWindow := SW_HIDE;
// assign pipes
myStartupInfo.dwFlags := myStartupInfo.dwFlags or STARTF_USESTDHANDLES;
myStartupInfo.hStdInput := 0;
myStartupInfo.hStdOutput := hPipeOutputWrite;
myStartupInfo.hStdError := hPipeErrorWrite;
// start the process
Result := CreateProcess(nil, PChar(CmdLine), nil, nil, True,
CREATE_NEW_CONSOLE, nil, nil, myStartupInfo, myProcessInfo);
// close the ends of the pipes, now used by the process
CloseHandle(hPipeOutputWrite);
CloseHandle(hPipeErrorWrite);
// could process be started ?
if Result then
begin
hThreadOutputRead := 0;
hThreadErrorRead := 0;
try
// create threads for reading the output pipes
myReadOutputThreadParam.Pipe := hPipeOutputRead;
hThreadOutputRead := BeginThread(nil, 0, @Sto_ReadPipeThreadProc,
@myReadOutputThreadParam, 0, iThreadId);
myReadErrorThreadParam.Pipe := hPipeErrorRead;
hThreadErrorRead := BeginThread(nil, 0, @Sto_ReadPipeThreadProc,
@myReadErrorThreadParam, 0, iThreadId);
// wait unitl there is no more data to receive, or the timeout is reached
iWaitRes := WaitForSingleObject(myProcessInfo.hProcess, Wait);
// timeout reached ?
if (iWaitRes = WAIT_TIMEOUT) then
begin
Result := False;
TerminateProcess(myProcessInfo.hProcess, UINT(ERROR_CANCELLED));
end;
// return output
Output := myReadOutputThreadParam.Content;
Error := myReadErrorThreadParam.Content;
finally
CloseHandle(myProcessInfo.hThread);
CloseHandle(myProcessInfo.hProcess);
CloseHandle(hThreadOutputRead);
CloseHandle(hThreadErrorRead);
end;
end;
// close our ends of the pipes
CloseHandle(hPipeOutputRead);
CloseHandle(hPipeErrorRead);
end;
end.
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet)
¤
|
Haftungshinweis
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.
|