如何正确使用 WaitForSingleObject 方法来等待外部程序终止?

发布于 2024-10-21 09:14:04 字数 741 浏览 5 评论 0原文

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

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

I'm trying to launch an external application with elevated status, and wait until it exits before continuing:

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;

This launches, but it just keeps waiting. The calling program never continues past the call to WaitForSingleObject, even after the called program exits.

I've tried WAIT_OBJECT_0 instead of WAIT_TIMEOUT, but I have the same problem. What am I doing wrong here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

や三分注定 2024-10-28 09:14:04

代码

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

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

直接使用

WaitForSingleObject(ExecInfo.hProcess, INFINITE);

即可。是的,您需要

fMask:= SEE_MASK_NOCLOSEPROCESS;

获取进程句柄。

What the code

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

is supposed to do? It is an infinite loop.

Use just

WaitForSingleObject(ExecInfo.hProcess, INFINITE);

instead. And yes, you need

fMask:= SEE_MASK_NOCLOSEPROCESS;

to obtain the process handle.

骷髅 2024-10-28 09:14:04

你的代码被破坏了。您没有将 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;

Your code is broken. You are not passing the SEE_MASK_NOCLOSEPROCESS flag to ShellExecuteEx(), so it will not return a valid process handle to you, and your loop is ignoring the errors that WaitForSingleObject() tells you because of that, so you end up in an endless loop.

Try this instead:

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;
沉溺在你眼里的海 2024-10-28 09:14:04

如果您阅读MSDN 中有关 ShellExecuteEx 的说明,你会看到这个:

h进程

类型:HANDLE

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

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

If you read description of ShellExecuteEx in MSDN, you will see this:

hProcess

Type: HANDLE

A handle to the newly started application. This member is set on
return and is always NULL unless fMask
is set to SEE_MASK_NOCLOSEPROCESS.
Even if fMask is set to
SEE_MASK_NOCLOSEPROCESS, hProcess will
be NULL if no process was launched.

I.e. you simply don't have a valid handle. You need to set fMask as written above.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文