Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
206 views
in Technique[技术] by (71.8m points)

delphi - Execute and Wait not working sometimes

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;
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...