Delphi: How to start application with elevated status and wait for it to terminate?

匿名 (未验证) 提交于 2019-12-03 01:09:02

问题:

I'm trying to start another application from my program with elevated rights, and wait for it to terminate before continuing.

I've tried several different solutions on the web, but I can't find one that works exactly right.

The code below is the closest I have to working right. It runs the app with elevated privileges and waits for it to terminate, but it freezes once the external app is terminated. In other words, it doesn't keep processing once the launched app is closed.

How can I accomplish what I'm after here?

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; 

Update:

I've come up with the following function, but it only works if I have a ShowMessage statement after calling it. So, I have to have:

RunFileAsAdminWait(Handle, ExtractFilePath(Application.Exename) + 'AutoUpdate.exe', '/auto'); ShowMessage('test'); 

in order to make the function work. How can I make it work without the ShowMessage call?

Here's the updated function:

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; 

回答1:

The following code works for me:

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; 

You have to pass the SEE_MASK_NOCLOSEPROCESS flag to get the process handle to wait for. I also changed the code to loop as long as WaitForSingleObject() returns with timeout.

For more information on the flags see the MSDN page for the SHELLEXECUTEINFO structure.



回答2:

The code in @mghie's answer has the right idea in general, but the code to process messages while waiting on the process handle could be better. Try this:

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; 


回答3:

Your wait (50 ms is too short), try

WaitForSingleObject(sei.hProcess, INFINITE) 

The check for valid process handle (sei.hProcess 0) can be left out.

Corrected Answer:

  while MsgWaitForMultipleObjects(1, sei.hProcess, False, INFINITE, QS_ALLINPUT)      WAIT_OBJECT_0 do   begin     while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do     begin       DispatchMessage(Msg);     end;   end; 


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