2011-03-10 22 views
8

我試圖啓動與地位提升外部應用程序,並等待它繼續之前退出:如何正確使用WaitForSingleObject方法等待外部程序終止?

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,但我有同樣的問題。我在這裏做錯了什麼?

+1

什麼樣的過程,你試圖執行?你確定它成功了嗎?如果是這樣,你確定你有一個有效的句柄?在你遇到你所問的部分之前,有很多東西可能會在代碼中出錯。確保你問的是正確的事情。如果WaitForSingleObject調用返回,它顯然不會返回Wait_Timeout;所以*返回的是什麼? – 2011-03-10 15:30:32

回答

11

什麼碼

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

是應該做的?這是一個無限循環。

使用只是

WaitForSingleObject(ExecInfo.hProcess, INFINITE); 

代替。是的,你需要

fMask:= SEE_MASK_NOCLOSEPROCESS; 

獲取進程句柄。

2

如果你讀description of ShellExecuteEx in MSDN,你會看到:

hProcess

Type: HANDLE 

的句柄新啓動的應用程序。此成員設置爲 返回並始終爲NULL,除非fMask 設置爲SEE_MASK_NOCLOSEPROCESS。 即使fMask設置爲 SEE_MASK_NOCLOSEPROCESS,如果沒有進程啓動,hProcess將 爲NULL。

I.e.你根本沒有一個有效的句柄。您需要按照上面所述設置fMask。

+0

這不適合我。相應地更改fMask後,它仍會鎖定調用應用程序。 – croceldon 2011-03-10 15:07:01

4

您的代碼已損壞。您沒有將SEE_MASK_NOCLOSEPROCESS標誌傳遞給ShellExecuteEx(),所以它不會向您返回有效的進程句柄,並且您的循環忽略了因此而告訴您的錯誤,所以最終會導致無限循環。

試試這個:

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

如何使用此方法從被調用的進程中獲取'ExitCode'? – 2014-05-08 00:39:30

+0

在循環退出並關閉進程句柄之前調用['GetExitCodeProcess()'](http://msdn.microsoft.com/en-us/library/windows/desktop/ms683189.aspx)。 – 2014-05-08 01:32:54