【问题标题】:How do I properly use the WaitForSingleObject method to wait for an external program to terminate?如何正确使用 WaitForSingleObject 方法等待外部程序终止?
【发布时间】:2011-03-10 14:35:48
【问题描述】:

我正在尝试以提升的状态启动一个外部应用程序,并等到它退出后再继续:

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,但我遇到了同样的问题。我在这里做错了什么?

【问题讨论】:

  • 你试图执行什么进程?你确定成功了吗?如果是这样,你确定你有一个有效的句柄吗?在您到达您所询问的部分之前,该代码中有很多可能出错的地方。确保你问的是正确的事情。如果 WaitForSingleObject 调用返回,它显然没有返回 Wait_Timeout;那么它返回的是什么

标签: delphi delphi-2007


【解决方案1】:

什么代码

while WaitForSingleObject(ExecInfo.hProcess, INFINITE) <> WAIT_TIMEOUT do
  Application.ProcessMessages;

应该怎么做?这是一个无限循环。

只使用

WaitForSingleObject(ExecInfo.hProcess, INFINITE);

相反。是的,你需要

fMask:= SEE_MASK_NOCLOSEPROCESS;

获取进程句柄。

【讨论】:

    【解决方案2】:

    您的代码已损坏。您没有将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;
    

    【讨论】:

    • 如何通过这种方法从被调用进程中获取ExitCode
    • 在循环退出后关闭进程句柄前调用GetExitCodeProcess()
    【解决方案3】:

    如果你阅读description of ShellExecuteEx in MSDN,你会看到:

    h进程

    Type: HANDLE
    

    新启动的应用程序的句柄。该成员设置在 返回并始终为 NULL,除非 fMask 设置为 SEE_MASK_NOCLOSEPROCESS。 即使 fMask 设置为 SEE_MASK_NOCLOSEPROCESS,hProcess 将 如果没有启动进程,则为 NULL。

    即您根本没有有效的句柄。您需要按照上面的说明设置 fMask。

    【讨论】:

    • 这对我不起作用。相应地更改 fMask 后,它仍然会锁定调用应用程序。
    猜你喜欢
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    • 2018-02-04
    • 1970-01-01
    • 2017-09-09
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多