Это пример
запуска консольных программ с передачей ей консольного ввода (как если бы он был
введен с клавиатуры после запуска программы) и чтением консольного вывода. Таким
способом можно запускать например стандартный виндовый 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;
Это код на языке Delphi, который запускает консольное приложение и захватывает его вывод в реальном времени, без отображения окна консоли.
Первый вариант (Dos2Win) создает трубу и использует ее для общения с процессом-ребенком (консольным приложением). Функция CreateProcess используется для создания процесса-ребенка, а функция ReadFile - для чтения из трубы. Вывод процесса-ребенка записывается в компонент мемо.
Второй вариант (ExecuteFile) - улучшенная версия, которая включает обработку ошибок и позволяет захватывать вывод в реальном времени.
Схема кода следующая:
Первый раздел определяет типы и переменные, используемые в коде.
Функция ReadOutput читает из трубы и конвертирует вывод в строку.
Главная процедура создает трубы, пишет в стандартный ввод (если предоставлен), и запускает процесс-ребенка с помощью CreateProcess.
Код ждет, пока процесс-ребенок не закончится, используя WaitForSingleObject. Если таймаут достигнут, код прерывает процесс-ребенка с помощью TerminateProcess.
Вывод процесса-ребенка читается из трубы с помощью ReadFile и хранится в строке.
Наконец, код закрывает все handles и возвращает результат.
Третий вариант (ExecuteFile) добавляет дополнительную обработку ошибок и позволяет захватывать вывод в реальном времени, читая из трубы маленькими кусками (1024 байта за раз).
В целом, этот код предоставляет способ запускать консольные приложения программно в Delphi без отображения окна консоли.
Данные выводятся в TMemo с помощью метода Text := OutMemo.text + String(Buffer).
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.