The likely explanation is as follows:
- You call CreateProcess which creates a new process and returns a handle to that process.
- That first new process in turn starts a different process, and immediately returns. That second process is the one that you see, and believe to be the process that you created.
- Your wait on the first process handle returns.
In order to know how to deal with this you'd need to supply some details about the process that you are attempting to start. As to why the code works on some machines and not others, that would likely be down to the implementation details of the target application, the external application that you are starting. Presumably it differs from machine to machine.
Looking at the code, it always leaks the thread handle returned in aTPI.hThread
. And it leaks aTPI.hProcess
if GetExitCodeProcess
fails.
You also need to ensure that the string you pass to the command line argument of CreateProcess
is an editable string, and not a literal that is stored in read-only memory.
It is also pointless to initialise ExitCode
and then immediately overwrite it. What's more you can remove the ExitCode
variable and pass Result
directly to GetExitCodeProcess
.
Your code also fails to acknowledge an error being returned by the wait function.
I'd probably write it like this:
function ExecAndWait(CommandLine: string): DWORD;
var
si: TStartupInfo;
pi: TProcessInformation;
iRet: Integer;
begin
UniqueString(CommandLine);
si := Default(TStartupInfo);
si.cb := SizeOf(si);
Win32Check(CreateProcess(nil, PChar(CommandLine), nil, nil, False,
NORMAL_PRIORITY_CLASS, nil, nil, si, pi));
CloseHandle(pi.hThread);
try
while True do
begin
iRet := MsgWaitForMultipleObjects(1, pi.hProcess, False, INFINITE, QS_ALLINPUT);
Win32Check(iRet <> WAIT_FAILED);
case iRet of
WAIT_OBJECT_0:
break;
WAIT_OBJECT_0+1:
Application.ProcessMessages;
end;
end;
Win32Check(GetExitCodeProcess(pi.hProcess, Result));
finally
CloseHandle(pi.hProcess);
end;
end;
On my machine, when I pass 'notepad.exe'
to this function, the function does not return until the Notepad process is closed.
On the other hand, if I pass 'explorer.exe'
to the process, then the function returns immediately. What happens here is that a new explorer process starts, but it detects that one is already running, and asks that process to open a new window. The newly started explorer process immediately terminates.