182 lines
5.4 KiB
ObjectPascal
182 lines
5.4 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: CapExec.pas, released on 2003-11-28.
|
|
|
|
The Initial Developer of the Original Code is Andreas Hausladen
|
|
(Andreas dott Hausladen att gmx dott de)
|
|
Portions created by Andreas Hausladen are Copyright (C) 2003 Andreas Hausladen.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s): -
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL
|
|
home page, located at http://jvcl.sourceforge.net
|
|
|
|
Known Issues:
|
|
-----------------------------------------------------------------------------}
|
|
// $Id: CapExec.pas,v 1.8 2006/02/14 15:32:35 ahuser Exp $
|
|
|
|
unit CapExec;
|
|
|
|
{$I jvcl.inc}
|
|
{$I windowsonly.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, SysUtils, Classes;
|
|
|
|
type
|
|
TCaptureLine = procedure(const Line: string; var Aborted: Boolean) of object;
|
|
|
|
function CaptureExecute(const App, Args, Dir: string; CaptureLine: TCaptureLine;
|
|
OnIdle: TNotifyEvent = nil; CtrlCAbort: Boolean = False): Integer;
|
|
|
|
|
|
implementation
|
|
|
|
function Oem2Ansi(const Text: string): string;
|
|
begin
|
|
Result := Text;
|
|
OemToCharBuff(PChar(Result), PChar(Result), Length(Result));
|
|
end;
|
|
|
|
function CaptureExecute(const App, Args, Dir: string; CaptureLine: TCaptureLine;
|
|
OnIdle: TNotifyEvent = nil; CtrlCAbort: Boolean = False): Integer;
|
|
const
|
|
CtrlCBuffer: array[0..7] of Char = #3#3#3#3#3#3#3#3;
|
|
var
|
|
ProcessInfo: TProcessInformation;
|
|
StartupInfo: TStartupInfo;
|
|
SecAttrib: TSecurityAttributes;
|
|
hRead, hWrite: THandle;
|
|
hAbortRead, hAbortWrite: THandle;
|
|
Line: string;
|
|
Aborted: Boolean;
|
|
Num: Cardinal;
|
|
|
|
procedure ProcessInput;
|
|
var
|
|
BytesInPipe, n: Cardinal;
|
|
S: string;
|
|
i: Integer;
|
|
Found: Boolean;
|
|
begin
|
|
BytesInPipe := 0;
|
|
if not PeekNamedPipe(hRead, nil, 0, nil, @BytesInPipe, nil) then
|
|
BytesInPipe := 0;
|
|
SetLength(S, BytesInPipe);
|
|
if S <> '' then
|
|
begin
|
|
ReadFile(hRead, S[1], BytesInPipe, n, nil);
|
|
SetLength(S, n);
|
|
Line := Line + S;
|
|
repeat
|
|
Found := False;
|
|
for i := 1 to Length(Line) do
|
|
if Line[i] in [#10, #13] then
|
|
begin
|
|
CaptureLine(Oem2Ansi(Copy(Line, 1, i - 1)), Aborted);
|
|
if (Line[i] = #13) and (Line[i + 1] = #10) then
|
|
begin
|
|
if Line[i + 2] = #13 then
|
|
Delete(Line, 1, i + 2)
|
|
else
|
|
Delete(Line, 1, i + 1);
|
|
end
|
|
else
|
|
Delete(Line, 1, i);
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
until (Aborted) or (not Found);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Result := -2;
|
|
if not Assigned(CaptureLine) then
|
|
Exit;
|
|
|
|
FillChar(SecAttrib, SizeOf(SecAttrib), 0);
|
|
with SecAttrib do begin
|
|
nLength := SizeOf(SecAttrib);
|
|
bInheritHandle := True;
|
|
lpSecurityDescriptor := nil;
|
|
end; // with
|
|
|
|
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
|
|
StartupInfo.cb := SizeOf(TStartupInfo);
|
|
|
|
Aborted := False;
|
|
if not CreatePipe(hRead, hWrite, @SecAttrib, 0) then
|
|
Exit;
|
|
try
|
|
if CtrlCAbort then
|
|
if not CreatePipe(hAbortRead, hAbortWrite, @SecAttrib, 0) then
|
|
Exit;
|
|
try
|
|
StartupInfo.wShowWindow := SW_HIDE;
|
|
if CtrlCAbort then
|
|
StartupInfo.hStdInput := hAbortRead
|
|
else
|
|
StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
|
|
StartupInfo.hStdOutput := hWrite;
|
|
StartupInfo.hStdError := StartupInfo.hStdOutput; // redirect
|
|
StartupInfo.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
|
|
|
|
if CreateProcess(nil, PChar(App + ' ' + Args), @SecAttrib, nil, True,
|
|
0, nil, PChar(Dir), StartupInfo, ProcessInfo) then
|
|
begin
|
|
CloseHandle(ProcessInfo.hThread);
|
|
try
|
|
while (WaitForSingleObject(ProcessInfo.hProcess, 30) = WAIT_TIMEOUT) and (not Aborted) do
|
|
begin
|
|
ProcessInput;
|
|
if Assigned(OnIdle) then
|
|
OnIdle(nil);
|
|
end;
|
|
ProcessInput;
|
|
if Line <> '' then
|
|
CaptureLine(Line, Aborted);
|
|
if Aborted then
|
|
begin
|
|
if CtrlCAbort then
|
|
begin
|
|
WriteFile(hAbortWrite, CtrlCBuffer, SizeOf(CtrlCBuffer), Num, nil);
|
|
if WaitForSingleObject(ProcessInfo.hProcess, 500) = WAIT_TIMEOUT then
|
|
TerminateProcess(ProcessInfo.hProcess, Cardinal(1));
|
|
end
|
|
else
|
|
TerminateProcess(ProcessInfo.hProcess, Cardinal(1));
|
|
end;
|
|
GetExitCodeProcess(ProcessInfo.hProcess, Cardinal(Result));
|
|
finally
|
|
CloseHandle(ProcessInfo.hProcess);
|
|
end;
|
|
end
|
|
else
|
|
Result := -1;
|
|
finally
|
|
if CtrlCAbort then
|
|
begin
|
|
CloseHandle(hAbortRead);
|
|
CloseHandle(hAbortWrite);
|
|
end;
|
|
end;
|
|
finally
|
|
CloseHandle(hRead);
|
|
CloseHandle(hWrite);
|
|
end;
|
|
end;
|
|
|
|
end.
|