Запуск программ с передачей консольного ввода и чтением вывода.
Компилятор: Delphi
Автор: Алексей Бойко
Это пример запуска консольных программ с
передачей ей консольного ввода (как если бы он
был введен с клавиатуры после запуска программы)
и чтением консольного вывода. Таким способом
можно запускать например стандартный виндовый ftp.exe
(в невидимом окне) и тем самым отказаться от
использования специализированных, зачастую
глючных компонент.
function ExecuteFile(FileName,StdInput: string;
TimeOut: integer;
var StdOutput:string) : boolean;
label Error;
type
TPipeHandles = (IN_WRITE, IN_READ,
OUT_WRITE, OUT_READ,
ERR_WRITE, ERR_READ);
type
TPipeArray = array [TPipeHandles] of THandle;
var
i : integer;
ph : TPipeHandles;
sa : TSecurityAttributes;
Pipes : TPipeArray;
StartInf : TStartupInfo;
ProcInf : TProcessInformation;
Buf : array[0..1024] of byte;
TimeStart : TDateTime;
function ReadOutput : string;
var
i : integer;
s : string;
BytesRead : longint;
begin
Result := '';
repeat
Buf[0]:=26;
WriteFile(Pipes[OUT_WRITE],Buf,1,BytesRead,nil);
if ReadFile(Pipes[OUT_READ],Buf,1024,BytesRead,nil) then
begin
if BytesRead>0 then
begin
buf[BytesRead]:=0;
s := StrPas(@Buf[0]);
i := Pos(#26,s);
if i>0 then s := copy(s,1,i-1);
Result := Result + s;
end;
end;
if BytesRead1024 then break;
until false;
end;
begin
Result := false;
for ph := Low(TPipeHandles) to High(TPipeHandles) do
Pipes[ph] := INVALID_HANDLE_VALUE;
// Создаем пайпы
sa.nLength := sizeof(sa);
sa.bInheritHandle := TRUE;
sa.lpSecurityDescriptor := nil;
if not CreatePipe(Pipes[IN_READ],Pipes[IN_WRITE], @sa, 0 ) then
goto Error;
if not CreatePipe(Pipes[OUT_READ],Pipes[OUT_WRITE], @sa, 0 ) then
goto Error;
if not CreatePipe(Pipes[ERR_READ],Pipes[ERR_WRITE], @sa, 0 ) then
goto Error;
// Пишем StdIn
StrPCopy(@Buf[0],stdInput+^Z);
WriteFile(Pipes[IN_WRITE],Buf,Length(stdInput),i,nil);
// Хендл записи в StdIn надо закрыть - иначе выполняемая программа
// может не прочитать или прочитать не весь StdIn.
CloseHandle(Pipes[IN_WRITE]);
Pipes[IN_WRITE] := INVALID_HANDLE_VALUE;
FillChar(StartInf,sizeof(TStartupInfo),0);
StartInf.cb := sizeof(TStartupInfo);
StartInf.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
StartInf.wShowWindow := SW_SHOW; // SW_HIDE если надо запустить невидимо
StartInf.hStdInput := Pipes[IN_READ];
StartInf.hStdOutput := Pipes[OUT_WRITE];
StartInf.hStdError := Pipes[ERR_WRITE];
if not CreateProcess(nil, PChar(FileName), nil,
nil, True, NORMAL_PRIORITY_CLASS,
nil, nil, StartInf, ProcInf) then goto Error;
TimeStart := Now;
repeat
Application.ProcessMessages;
i := WaitForSingleObject(ProcInf.hProcess,100);
if i = WAIT_OBJECT_0 then break;
if (Now-TimeStart)*SecsPerDay>TimeOut then break;
until false;
if iWAIT_OBJECT_0 then goto Error;
StdOutput := ReadOutput;
for ph := Low(TPipeHandles) to High(TPipeHandles) do
if Pipes[ph]INVALID_HANDLE_VALUE then
CloseHandle(Pipes[ph]);
CloseHandle(ProcInf.hProcess);
CloseHandle(ProcInf.hThread);
Result := true;
Exit;
Error:
if ProcInf.hProcessINVALID_HANDLE_VALUE then
begin
CloseHandle(ProcInf.hThread);
i := WaitForSingleObject(ProcInf.hProcess, 1000);
CloseHandle(ProcInf.hProcess);
if iWAIT_OBJECT_0 then
begin
ProcInf.hProcess := OpenProcess(PROCESS_TERMINATE,
FALSE,
ProcInf.dwProcessId);
if ProcInf.hProcess 0 then
begin
TerminateProcess(ProcInf.hProcess, 0);
CloseHandle(ProcInf.hProcess);
end;
end;
end;
for ph := Low(TPipeHandles) to High(TPipeHandles) do
if Pipes[ph]INVALID_HANDLE_VALUE then
CloseHandle(Pipes[ph]);
end;
|