Delphi:如何以提升状态启动应用程序并等待它终止?

cro*_*don 13 delphi

我正在尝试从我的程序中启动另一个具有提升权限的应用程序,并在继续之前等待它终止.

我在网上尝试了几种不同的解决方案,但我找不到一种完全正确的解决方案.

下面的代码是我最接近工作的代码.它以提升的权限运行应用程序并等待它终止,但一旦外部应用程序终止它就会冻结.换句话说,一旦启动的应用程序关闭,它就不会继续处理.

我怎样才能完成我在这里的工作?

procedure TfMain.RunFileAsAdminWait(hWnd: HWND; aFile, aParameters: string);
var
  sei: TShellExecuteInfo;
begin
  FillChar(sei, SizeOf(sei), 0);
  sei.cbSize := SizeOf(sei);
  sei.Wnd := hWnd;
  sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
  sei.lpVerb := 'runas';
  sei.lpFile := PChar(aFile);
  sei.lpParameters := PChar(aParameters);
  sei.nShow := SW_SHOWNORMAL;

  if not ShellExecuteEx(@sei) then
    RaiseLastOSError
  else
    while WaitForSingleObject(sei.hProcess, 50) <> WAIT_OBJECT_0 do
      Application.ProcessMessages;

  CloseHandle(sei.hProcess);
end;
Run Code Online (Sandbox Code Playgroud)

更新:

我已经提出了以下函数,但只有在调用它之后我有一个ShowMessage语句时它才有效.所以,我必须:

RunFileAsAdminWait(Handle, ExtractFilePath(Application.Exename) + 'AutoUpdate.exe', '/auto');
ShowMessage('test');
Run Code Online (Sandbox Code Playgroud)

为了使功能工作. 如何在没有ShowMessage调用的情况下使其工作?

这是更新的功能:

procedure TfMain.RunFileAsAdminWait(hWnd: HWND; aFile, aParameters: string);
var
  sei: TShellExecuteInfo;
begin
  FillChar(sei, SizeOf(sei), 0);
  sei.cbSize := SizeOf(sei);
  sei.Wnd := hWnd;
  sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
  sei.lpVerb := 'runas';
  sei.lpFile := PChar(aFile);
  sei.lpParameters := PChar(aParameters);
  sei.nShow := SW_SHOWNORMAL;

  if not ShellExecuteEx(@sei) then
    RaiseLastOSError
  else
    if sei.hProcess <> 0 then
      WaitForSingleObject(sei.hProcess, 50)
    else
      Exit;

  CloseHandle(sei.hProcess);
end;
Run Code Online (Sandbox Code Playgroud)

mgh*_*hie 15

以下代码适用于我:

procedure RunFileAsAdminWait(hWnd: HWND; aFile, aParameters: string);
var
  sei: TShellExecuteInfo;
begin
  FillChar(sei, SizeOf(sei), 0);
  sei.cbSize := SizeOf(sei);
  sei.Wnd := hWnd;
  sei.fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_NOCLOSEPROCESS;
  sei.lpVerb := 'runas';
  sei.lpFile := PChar(aFile);
  sei.lpParameters := PChar(aParameters);
  sei.nShow := SW_SHOWNORMAL;

  if not ShellExecuteEx(@sei) then
    RaiseLastOSError;
  if sei.hProcess <> 0 then begin
    while WaitForSingleObject(sei.hProcess, 50) = WAIT_TIMEOUT do
      Application.ProcessMessages;
    CloseHandle(sei.hProcess);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

您必须传递SEE_MASK_NOCLOSEPROCESS标志才能使进程句柄等待.只要WaitForSingleObject()返回超时,我也将代码更改为循环.

有关标志的更多信息,请参阅SHELLEXECUTEINFO结构的MSDN页面.


Rem*_*eau 5

@mghie 的答案中的代码总体上具有正确的想法,但是在等待进程句柄时处理消息的代码可能会更好。尝试这个:

procedure RunFileAsAdminWait(hWnd: HWND; aFile, aParameters: string);
var
  sei: TShellExecuteInfo;
  Ret: DWORD;
begin
  FillChar(sei, SizeOf(sei), 0);
  sei.cbSize := SizeOf(sei);
  sei.Wnd := hWnd;
  sei.fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_NOCLOSEPROCESS;
  sei.lpVerb := 'runas';
  sei.lpFile := PChar(aFile);
  sei.lpParameters := PChar(aParameters);
  sei.nShow := SW_SHOWNORMAL;

  if not ShellExecuteEx(@sei) then
    RaiseLastOSError;
  if sei.hProcess <> 0 then
  try
    repeat
      Ret := MsgWaitForMultipleObjects(1, sei.hProcess, False, INFINITE, QS_ALLINPUT);
      if Ret = (WAIT_OBJECT_0+1) then Application.ProcessMessages
      else if Ret = WAIT_FAILED then RaiseLastOSError;
    until Ret = WAIT_OBJECT_0;
  finally
    CloseHandle(sei.hProcess);
  end;
end;
Run Code Online (Sandbox Code Playgroud)