2009-11-11 57 views
13

我想開始我與提升權限的程序另一個應用程序,並等待它繼續之前終止。德爾福:如何開始升高地位的申請,並等待它終止?

我已經在網上嘗試了幾種不同的解決方案,但是我找不到完全正確的工作。

下面的代碼是最接近我必須工作的權利。它使用提升的權限運行應用程序並等待它終止,但一旦外部應用程序終止,它就會凍結。換句話說,一旦推出的應用程序關閉,它不會繼續處理。

我怎麼能做到什麼,我這裏後我?

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; 

回答

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頁面。

+0

工作完美!謝謝! – croceldon 2009-11-11 20:43:15

+1

這將是更有效地使用'MsgWaitForMultipleObjects()',而不是'WaitForSingleObject的()',這樣你就可以調用'Application.ProcessMessages()'只有當它告訴你,消息等待處理。唐」牛逼一味叫'ProcessMessages()'不必要。 – 2014-12-21 20:59:48

0

你的等待(50毫秒太短),嘗試

WaitForSingleObject(sei.hProcess, INFINITE) 

的有效進程句柄的檢查(sei.hProcess <> 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; 
+1

這將導致調用應用程序出現掛起,因爲它將不再處理消息。 – mghie 2009-11-11 20:11:45

+0

對不起,我忽略了關於凍結的部分,我更正了我的回答 – Remko 2009-11-11 21:05:13

+0

只有當'MsgWaitForMultipleObjects()'專門返回'WAIT_OBJECT_0 + 1'時,您才應該處理消息。相應地處理其他返回值。 – 2014-12-21 21:01:55

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; 
+0

感謝寫這個詳細的回答,雷米。 – 2016-01-27 23:54:28