Здравствуйте, mDmitriy, Вы писали:
D>Приветствую, All!
D>Вопрос в следующем:
D>Надо запустить консольное приложение, например, rar.exe или компилятор или еще что...
D>Запуск предполагается через CreateProcess
D>Надо в реальном времени получать результат процесса, т.е. вариант с перенаправленим в файл и последующей читкой оного не прокатит.
D>CreateProcess вроде позволяет получать хэндл устройства вывода, но как перехватить идущие туда данные?
В свое время я написал нечно вроде
этого. Работает не всегда корректно, но для моих целей хватило. А до товарного вида все баги не пофиксил

... << RSDN@Home 1.1.3 stable >>
Здравствуйте, mDmitriy, Вы писали:
D>Приветствую, All!
D>Вопрос в следующем:
D>Надо запустить консольное приложение, например, rar.exe или компилятор или еще что...
D>Запуск предполагается через CreateProcess
D>Надо в реальном времени получать результат процесса, т.е. вариант с перенаправленим в файл и последующей читкой оного не прокатит.
D>CreateProcess вроде позволяет получать хэндл устройства вывода, но как перехватить идущие туда данные?
D>В MSDN есть пример похожий с PIPE, но может кто знает попроще?
D>Дмитрий
Для этих целей я писал вот такую вот процедурень запуска программы. MSDN начитался до опупения, зато работает как часики
type
TDOutputCallBack = procedure (OuptpuStr : string) of object;
......
function RunProgram(FileName : string; CommandLine : string; WorkDir : string;
ShowCmd : Integer; OutputCallBack : TDOutputCallBack; WaitFor : Boolean = True): DWORD;
const
cntReadBufferSize = 1024;
var
BytesRead: Cardinal;
Buffer : array [0..cntReadBufferSize] of Char;
hOutputReadTmp, hOutputRead, hOutputWrite : THandle;
hInputWriteTmp, hInputRead, hInputWrite : THandle;
hErrorWrite : THandle;
var
ProcessInfo : TProcessInformation;
StartupInfo : TStartupInfo;
EnviromentBlock : PChar;
ExecString : string;
Security : TSecurityAttributes;
begin
with Security do begin
nlength := SizeOf (TSecurityAttributes);
binherithandle := True;
lpsecuritydescriptor := nil;
end;
FileName := TString.Trim (FileName);
if (TString.Char (FileName) <> '"') and (Pos (' ', FileName) > 0) then
FileName := '"' + StringReplace (FileName, '"', '""', [rfReplaceAll]) + '"';
hOutputRead := 0;
if Assigned (OutputCallBack) then begin
if CreatePipe (hOutputReadTmp, hOutputWrite, @Security, 0) then begin
DuplicateHandle (GetCurrentProcess, hOutputWrite, GetCurrentProcess, @hErrorWrite, 0, True, DUPLICATE_SAME_ACCESS);
if CreatePipe (hInputRead, hInputWriteTmp, @Security, 0) then begin
DuplicateHandle (GetCurrentProcess, hOutputReadTmp, GetCurrentProcess, @hOutputRead, 0, False, DUPLICATE_SAME_ACCESS);
DuplicateHandle (GetCurrentProcess, hInputWriteTmp, GetCurrentProcess, @hInputWrite, 0, False, DUPLICATE_SAME_ACCESS);
CloseHandle (hOutputReadTmp);
CloseHandle (hInputWriteTmp);
end;
end;
end;
FillChar (StartupInfo, SizeOf (StartupInfo), 0);
with StartupInfo do begin
cb := sizeof (StartupInfo);
lpReserved := nil;
lpDesktop := nil; {inherit}
lpTitle := nil;
dwFlags := TDTools.Choose (not Assigned (OutputCallBack), 0, STARTF_USESTDHANDLES) or STARTF_USESHOWWINDOW;
hStdOutput := hOutputWrite;
hStdInput := hInputRead;
hStdError := hErrorWrite;
wShowWindow := ShowCmd;
cbReserved2 := 0;
lpReserved2 := nil;
end;
EnviromentBlock := GetEnvironmentStrings;
try
ExecString := FileName + ' ' + CommandLine;
if not CreateProcess( nil,
PChar(ExecString),
@Security,
@Security,
true,
0{DEBUG_PROCESS},
EnviromentBlock,
TDTools.Choose (WorkDir = '', nil, PChar (WorkDir)),
StartupInfo,
ProcessInfo)
then RaiseLastWin32Error;
CloseHandle(hOutputWrite);
CloseHandle(hInputRead);
CloseHandle(hErrorWrite);
CloseHandle (ProcessInfo.hThread);
finally
FreeEnvironmentStrings (EnviromentBlock)
end;
Result := 0;
try
if hOutputRead <> 0 then begin
BytesRead := 0;
repeat
if not ReadFile (hOutputRead, Buffer, cntReadBufferSize, BytesRead, nil) then begin
Break
end else begin
if BytesRead > 0 then begin
Buffer [BytesRead] := #0;
if Assigned (OutputCallback) then begin
OemToChar (@Buffer, @Buffer);
OutputCallback (string (Buffer));
end;
end;
end;
until False;
end;
if WaitFor then begin
if Result = 0 then
Result := WaitForSingleObject(ProcessInfo.hProcess, 2 * 60 * 60 * 1000 {2 hours});
case Result of
WAIT_TIMEOUT : raise Exception.Create ('Process timed out.');
WAIT_FAILED : raise Exception.Create ('Process filed');
end;
GetExitCodeProcess (ProcessInfo.hProcess, Result);
end else
Result := 0;
CloseHandle (ProcessInfo.hProcess);
finally
if hOutputRead <> 0 then
CloseHandle (hOutputRead);
end;
end;
Удачи!
Здравствуйте, Danchik, Вы писали:
D>Для этих целей я писал вот такую вот процедурень запуска программы. MSDN начитался до опупения, зато работает как часики
неименованные пайпы — самое простое.
Как мне кажется, все проще, чем написано.
Никаких DuplicateHandle не нужно.
просто создаешь пайп — 2 хэндла. (1 штуку, а то все норовят 2 пайпа создать и поиметь 4 хэндла соответственно)
записываешь во входящий нпайп чего надо.
Присваиваешь нелбходимые значения для ShellExecuteEx
Запускаешь
Там читают чего ты записал
Дальше по пайпам пишешь/читаешь (для справки — ReadFile ждет пока в пайп запишут)
Можно ждать одновременно пайп и завершение приложения (WaitFor)
Потом оба хэндла нужно закрыть.
В общем, если в объекты не обертывать, то я в пол дюжины строк (чисто на служебные нужды без особенностей протокола обмена) укладывался всегда.
Здравствуйте, s.ts, Вы писали:
ST>Здравствуйте, Danchik, Вы писали:
D>>Для этих целей я писал вот такую вот процедурень запуска программы. MSDN начитался до опупения, зато работает как часики
ST>неименованные пайпы — самое простое.
ST>Как мне кажется, все проще, чем написано.
Ты пробовал? у меня иначе все висло
ST>Никаких DuplicateHandle не нужно.
Выдрано и портировано с MSDN, один в один
ST>просто создаешь пайп — 2 хэндла. (1 штуку, а то все норовят 2 пайпа создать и поиметь 4 хэндла соответственно)
ST>записываешь во входящий нпайп чего надо.
ST>Присваиваешь нелбходимые значения для ShellExecuteEx
ST>Запускаешь
ST>Там читают чего ты записал
ST>Дальше по пайпам пишешь/читаешь (для справки — ReadFile ждет пока в пайп запишут)
Итак понятно
ST>Можно ждать одновременно пайп и завершение приложения (WaitFor)
согласен
ST>Потом оба хэндла нужно закрыть.
че то не закрыл?, тыкни в место
ST>В общем, если в объекты не обертывать, то я в пол дюжины строк (чисто на служебные нужды без особенностей протокола обмена) укладывался всегда.
Кидай код, только если он еа CreateProcess основан
Здравствуйте, mDmitriy, Вы писали:
D>Приветствую, All!
D>Вопрос в следующем:
D>Надо запустить консольное приложение, например, rar.exe или компилятор или еще что...
D>Запуск предполагается через CreateProcess
D>Надо в реальном времени получать результат процесса, т.е. вариант с перенаправленим в файл и последующей читкой оного не прокатит.
D>CreateProcess вроде позволяет получать хэндл устройства вывода, но как перехватить идущие туда данные?
D>В MSDN есть пример похожий с PIPE, но может кто знает попроще?
Что интересно — работает без дубликации хэндлов
интересующимся — сюды (много исходников по теме):
http://delphiworld.narod.ru/_os_.html
Дмитрий