You need to use ShellExecuteEx
with SEE_MASK_NOCLOSEPROCESS
. Check this out and see my comments inline:
var
sei: TShellExecuteInfo;
exitCode: Cardinal;
begin
ZeroMemory(@sei, SizeOf(sei));
with sei do
begin
cbSize := SizeOf(sei);
fMask := SEE_MASK_NOCLOSEPROCESS; // Tell ShellExecuteEx to keep the process handle open
Wnd := WindowHandleIfNeeded; // Can be omitted
lpVerb := 'open';
lpFile := PChar(PathOfExeToRun);
lpParameters := PChar(ParametersToUse);
lpDirectory := PChar(WorkingDirectoryToUse); // Can be omitted
nShow := SW_NORMAL; // Can be omitted
end;
if ShellExecuteEx(@sei) then
begin
// I have encapsulated the different ways in begin/end and commented.
// *** EITHER: Wait for the child process to close, without processing messages (if you do it in a background thread)
begin
WaitForSingleObject(sei.hProcess, INFINITE);
end;
// *** OR: Wait for the child process to close, while processing messages (if you do it in the UI thread)
begin
while MsgWaitForMultipleObjects(1, sei.hProcess, FALSE, INFINITE, QS_ALLINPUT) = (WAIT_OBJECT_0 + 1) do begin
Application.ProcessMessages
end;
end;
// *** OR: Do something else, and in the middle you can check whether the child is still running using this:
begin
GetExitCodeProcess(sei.hProcess, exitCode);
if exitCode == STILL_ACTIVE then begin
// It's still running!
end else begin
// It has finished!
end;
end;
// At the end, close the handle
CloseHandle(sei.hProcess);
end;
end;