Это пример запуска консольных программ с передачей ей консольного ввода (как если бы он был введен с клавиатуры после запуска программы) и чтением консольного вывода. Таким способом можно запускать например стандартный виндовый ftp.exe (в невидимом окне) и тем самым отказаться от использования специализированных, зачастую глючных компонент.
Code: |
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; |
Автор: Алексей Бойко
- << Назад
- Вперёд
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!