Execute and Wait not working sometimes

时光毁灭记忆、已成空白 提交于 2019-12-13 07:59:20

问题


I am using this code I found on the Internet and on some devices it waits, but on others it does not. Can someone please explain where I am going wrong. My app loads in Truecrypt and then waits for the user to enter the password. On exiting Truecrypt, it then launches my menu-program.

My Lenovo Miix 2 8" tablet, win8.1 (all up to date) will wait, my Dad's win8.0 (all up to date) will wait, but my friend's ASUS M80TA 8" win8.1 tablet (all up to date) will not. Another friend's win7 laptop (all up to date) does not wait ether.

var
  aTSI : TStartupInfo;
  aTPI : TProcessInformation;
  iRet : Integer;
  ExitCode: Cardinal;
begin
  FillChar(aTSI, SizeOf(aTSI), #0);
  FillChar(aTPI, SizeOf(aTPI), #0);
  aTSI.CB:=SizeOf(aTSI);
  if not CreateProcess(nil, PChar(sEXE), nil, nil, False,
                       NORMAL_PRIORITY_CLASS,
                       nil, nil, aTSI, aTPI) then
    RaiseLastWin32Error;
  repeat
    iRet:=MsgWaitForMultipleObjects(1, aTPI.hProcess,
    False, INFINITE, (QS_ALLINPUT));
    if iRet <> (WAIT_OBJECT_0) then
      Application.ProcessMessages;
  until iRet = (WAIT_OBJECT_0); // use this for normal programs
  ExitCode:= 0;
  if not GetExitCodeProcess(aTPI.hProcess, ExitCode) then
    RaiseLastWin32Error;
  Result:= ExitCode;
  CloseHandle(aTPI.hProcess);
end;

回答1:


The likely explanation is as follows:

  1. You call CreateProcess which creates a new process and returns a handle to that process.
  2. 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.
  3. 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.



来源:https://stackoverflow.com/questions/26181231/execute-and-wait-not-working-sometimes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!