procedure TStdIORedirect.DestroyHandles;
begin
if fInputRead <> 0 then CloseHandle (fInputRead);
if fOutputRead <> 0 then CloseHandle (fOutputRead);
if fErrorRead <> 0 then CloseHandle (fErrorRead);
if fInputWrite <> 0 then CloseHandle (fInputWrite);
if fOutputWrite <> 0 then CloseHandle (fOutputWrite);
if fErrorWrite <> 0 then CloseHandle (fErrorWrite);
procedure TStdIORedirect.HandleOutput;
var
ch : char;
begin
fOutputStream.Position := fOutputStreamPos;
while fOutputStream.Position < fOutputStream.Size do
begin
fOutputStream.Read (ch, sizeof (ch));
case ch of
#13 :
begin
fOutputText.Add (fOutputLineBuff);
if Assigned (OnOutputText) then
OnOutputText (self, fOutputLineBuff);
fOutputLineBuff := '';
end;
while fErrorStream.Position < fErrorStream.Size do
begin
fErrorStream.Read (ch, sizeof (ch));
case ch of
#13 :
begin
fErrorText.Add (fErrorLineBuff);
if Assigned (OnErrorText) then
OnErrorText (self, fErrorLineBuff);
fErrorLineBuff := '';
end;
procedure TStdIORedirect.PrepareStartupInformation(
var info: TStartupInfo);
begin
info.cb := sizeof (info);
info.dwFlags := info.dwFlags or STARTF_USESTDHANDLES;
info.hStdInput := fInputRead;
info.hStdOutput := fOutputWrite;
info.hStdError := fErrorWrite;
end;
procedure TStdIORedirect.Run(fileName, cmdLine, directory: string);
var
startupInfo : TStartupInfo;
pOK : boolean;
fName, cLine, dir : PChar;
begin
if not Running then
begin
FillChar (startupInfo, sizeof (StartupInfo), 0);
CreateHandles;
PrepareStartupInformation (startupInfo);
if fileName <> '' then fName := PChar (fileName) else fName := Nil;
if cmdLine <> '' then cLine := PChar (' '+cmdLine) else cLine := Nil;
if directory <> '' then dir := PChar (directory) else dir := Nil;
if pOK then
begin
fRunning := True;
try
TStdIOInputThread.Create (self);
TStdIOOutputThread.Create (self);
while MsgWaitForMultipleObjects (1, fProcessInfo.hProcess, False,
INFINITE, QS_ALLINPUT) = WAIT_OBJECT_0 + 1 do
Application.ProcessMessages;
if not GetExitCodeProcess (fProcessInfo.hProcess, fReturnValue) then
RaiseLastWin32Error;
finally
fInputText.Clear;
CloseHandle (fProcessInfo.hThread);
CloseHandle (fProcessInfo.hProcess);
fRunning := False;
if Assigned (OnTerminate) then
OnTerminate (self);
end;
end
else RaiseLastWin32Error;
end;
end;
procedure TStdIORedirect.Terminate;
begin
if Running then TerminateProcess (fProcessInfo.hProcess, 0);
end;
function CopyTextToPipe (handle : THandle; text : TStrings) : boolean;
var
i : Integer;
st : string;
bytesWritten : DWORD;
p : Integer;
bTerminate : boolean;
begin
bTerminate := False;
for i := 0 to text.Count - 1 do
begin
st := text [i];
p := Pos (#26, st);
if p > 0 then
begin
st := Copy (st, 1, p - 1);
bTerminate := True;
end
else
st := st + #13#10;
if st <> '' then
if not WriteFile (handle, st [1], Length (st), bytesWritten, Nil) then
if GetLastError <> ERROR_NO_DATA then
RaiseLastWin32Error;
end;
result := bTerminate;
text.Clear;
end;
procedure TStdIOInputThread.Execute;
var
objects : array [0..1] of THandle;
objectNo : DWORD;
begin
if fParent.fInputText.Count > 0 then
fParent.fInputEvent.SetEvent;
while True do
begin
objectNo := WaitForMultipleObjects (2, @objects [0], False, INFINITE);
case objectNo of
WAIT_OBJECT_0 + 1 :
if CopyTextToPipe (fParent.fInputWrite, fParent.fInputText) then
begin
CloseHandle (fParent.fInputWrite);
fParent.fInputWrite := 0;
break;
end;
else
break;
end;
end;
end;
procedure TStdIOOutputThread.Execute;
var
buffer : array [0..1023] of char;
bytesRead : DWORD;
begin
while ReadFile (fParent.fOutputRead, buffer, 1024, bytesRead, Nil) and
(bytesRead > 0) do
begin
fParent.fOutputStream.Seek (0, soFromEnd);
fParent.fOutputStream.Write (buffer [0], bytesRead);
Synchronize (fParent.HandleOutput)
end;
end;
Public methods and properties:
|
|
|
| procedure Run (fileName, cmdLine, directory : string);
|
| Run a program with redirected output
|
| procedure AddInputText (const st : string);
|
| Add a line of text to be sent to the application's STDIN
|
| procedure Terminate;
|
| Terminate the program started with 'Run'
|
| property ReturnValue : DWORD read fReturnValue;
property OutputText : TStrings read fOutputText;
property ErrorText : TStrings read fErrorText;
property Running : boolean read fRunning;