我正在尝试使用提升权限从我的程序启动另一个应用程序,并在继续之前等待它终止。
我在网上尝试了几种不同的解决方案,但我找不到一种完全正确的解决方案。
以下代码是我最接近工作的代码。它以提升的权限运行应用程序并等待它终止,但一旦外部应用程序终止它就会冻结。换句话说,一旦启动的应用程序关闭,它就不会继续处理。
我怎样才能完成我在这之后所做的事情?
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;
更新
我已经提出了以下函数,但只有在调用它之后我有一个ShowMessage语句时它才有效。所以,我必须:
RunFileAsAdminWait(Handle, ExtractFilePath(Application.Exename) + 'AutoUpdate.exe', '/auto');
ShowMessage('test');
为了使功能起作用。 如何在没有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;
答案 0 :(得分: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;
您必须传递SEE_MASK_NOCLOSEPROCESS
标志才能获得等待的进程句柄。只要WaitForSingleObject()
返回超时,我也将代码更改为循环。
有关标志的更多信息,请参阅SHELLEXECUTEINFO
结构的MSDN页面。
答案 1 :(得分:3)
@ 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;
答案 2 :(得分:0)
你的等待(50毫秒太短),试试
WaitForSingleObject(sei.hProcess, INFINITE)
可以省略对有效进程句柄(sei.hProcess&lt;&gt; 0)的检查。
更正的答案:
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;