Как правильно использовать метод WaitForSingleObject для ожидания завершения внешней программы?
Я пытаюсь запустить внешнее приложение с повышенным статусом и дождаться его выхода, прежде чем продолжить:
var
FProcess: THandle;
ExecInfo: TShellExecuteInfo;
begin
FillChar(ExecInfo, SizeOf(ExecInfo), 0);
with ExecInfo do
begin
cbSize := SizeOf(ExecInfo);
fMask := 0;
Wnd := AWindow;
lpVerb := 'runas';
lpFile := PChar(APath);
lpParameters := PChar(AParams);
lpDirectory := PChar(AWorkDir);
nShow := SW_NORMAL;
end;
Result := ShellExecuteEx(@ExecInfo);
if Wait then
begin
while WaitForSingleObject(ExecInfo.hProcess, INFINITE) <> WAIT_TIMEOUT do
Application.ProcessMessages;
end;
это запускается, но он просто продолжает ждать. Вызывающая программа никогда не продолжает вызов WaitForSingleObject, даже после выхода вызываемой программы.
Я пробовал WAIT_OBJECT_0 вместо WAIT_TIMEOUT, но у меня такая же проблема. Что я здесь делаю не так?
3 ответов
код
while WaitForSingleObject(ExecInfo.hProcess, INFINITE) <> WAIT_TIMEOUT do
Application.ProcessMessages;
- Это должен делать? Это бесконечная петля.
использовать просто
WaitForSingleObject(ExecInfo.hProcess, INFINITE);
. И да, вам нужно
fMask:= SEE_MASK_NOCLOSEPROCESS;
для получения дескриптора процесса.
ваш код сломан. Вы не проходите SEE_MASK_NOCLOSEPROCESS
флаг ShellExecuteEx()
, поэтому он не вернет вам допустимый дескриптор процесса, и ваш цикл игнорирует ошибки, которые WaitForSingleObject()
говорит вам, так что вы в конечном итоге в бесконечный цикл.
попробуйте это вместо этого:
var
ExecInfo: TShellExecuteInfo;
begin
ZeroMemory(@ExecInfo, SizeOf(ExecInfo));
with ExecInfo do
begin
cbSize := SizeOf(ExecInfo);
fMask := SEE_MASK_NOCLOSEPROCESS;
Wnd := AWindow;
lpVerb := 'runas';
lpFile := PChar(APath);
lpParameters := PChar(AParams);
lpDirectory := PChar(AWorkDir);
nShow := SW_NORMAL;
end;
Result := ShellExecuteEx(@ExecInfo);
if Result and Wait then
begin
if ExecInfo.hProcess <> 0 then // no handle if the process was activated by DDE
begin
repeat
if MsgWaitForMultipleObjects(1, ExecInfo.hProcess, FALSE, INFINITE, QS_ALLINPUT) = (WAIT_OBJECT_0+1) then
Application.ProcessMessages
else
Break;
until False;
CloseHandle(ExecInfo.hProcess);
end;
end;
end;
Если вы читали описание ShellExecuteEx в MSDN, вы увидите это:
hProcess
Type: HANDLE
дескриптор недавно запущенного приложения. Этот элемент установлен на возвращает и всегда NULL, если fMask установлено SEE_MASK_NOCLOSEPROCESS. Даже если fMask имеет значение SEE_MASK_NOCLOSEPROCESS, hProcess будет значение NULL, если процесс не запущен.
т. е. у вас просто нет дескриптора. Вам нужно установить fMask как написано выше.