2011-05-15 277 views
8

我有一個希望很快的問題:是否有可能延遲ShellExecute的執行一點點?在執行ShellExecute之前等待嗎?

我有一個autoupdater的應用程序。在下載所有必要的文件等之後,它將當前文件重命名爲* .OLD,並將新文件重命名爲前一個。夠簡單。但後來我需要刪除這些.OLD文件。這個「清理」過程在MainForm.OnActivate上執行(檢查它是否是第一個激活過程)。但是,這顯然發生得太快(我從DeleteFile中得到False)。這是程序:

procedure TUpdateForm.OKBtnClick(Sender: TObject); 
const SHELL = 'ping 127.0.0.1 -n 2'; 
begin 
    ShellExecute(0,'open',pchar(SHELL+#13+Application.ExeName),nil,nil,SW_SHOWNORMAL); 
    Application.Terminate; 
end; 

此過程應該重新啓動應用程序。我確信刪除問題是由第二個應用程序的快速啓動引起的,因爲如果我自己重新啓動它,給它一點時間,文件就會正常刪除。

tl; dr版本:我需要調用ShellExecute(),等待一會兒(0.1秒左右),然後執行命令。

我嘗試使用-ping命令來儘量拖延,但沒有奏效。

非常感謝你提前

編輯:改寫

我需要這樣的事情發生|| 第一款應用關閉;等待100毫秒;第二個應用程序打開 ||。我需要先調用ShellExecute,然後等到調用應用程序完全關閉,然後執行shell(即打開第二個應用程序)

+3

我不明白。你想等待100毫秒,然後執行'ShellExecute'?那麼,那麼這樣做! '睡眠(100);的ShellExecute(...)'。或者你想'ShellExecute' *不能返回,直到新創建的進程退出*?如果是這樣,從理論上講,你希望***'ShellExecute'之後的'Sleep' ***,而不是*之前。但這是一個醜陋的解決方案。相反,你應該'WaitForSingleObject'或類似的東西。 – 2011-05-15 16:24:55

+1

我會嘗試重寫它:我需要這種情況||第一個應用關閉;等待100毫秒;第二個應用打開||。我需要先調用ShellExecute,然後等待調用應用程序完全關閉,然後執行shell(即打開第二個應用程序) - >您的建議都不是。我需要ShellExecute _not執行,直到當前應用程序完全關閉(這樣我可以刪除它的文件) – 2011-05-15 16:29:46

+0

你不能那樣做。應用程序1關閉後,但在應用程序2打開之前,您無法執行任何操作,因爲您沒有程序運行。你可以做的是調用一些應用程序,睡覺,然後調用其他應用程序,然後終止。但是,而不是一個固定的'睡眠',你應該'WaitForSingleObject'或其他更健壯的東西。 – 2011-05-15 16:32:36

回答

5

您正在執行autopatcher的權利嗎?

我有同樣的問題,這是我繞過它:

您運行參數「--delay」或類似的東西,第二個應用程序。 第二個應用程序處理參數「--delay」並睡眠100毫秒,然後繼續正常運行。

+0

看起來很整齊,愚蠢的我爲你投票,謝謝 – 2011-05-15 16:37:29

+4

如果你正在複製一個WTV文件到外部硬盤那麼100 ms可能還不夠,而且你還是失敗了,基於'WaitForSingleObject'的解決方案更好,或者第二個應用程序可以在啓動時「做不到睡眠(100)」或類似的事情 – 2011-05-15 16:43:45

+0

好的,我也會看看,謝謝 – 2011-05-15 16:49:33

3

這個例程是我們的遊戲引擎中的一些utils代碼。它可以運行一個可執行文件並有選擇地等待它退出。它將返回退出代碼:

function TSvUtils.FileExecute(ahWnd: Cardinal; const aFileName, aParams, aStartDir: string; aShowCmd: Integer; aWait: Boolean): Integer; 
var 
    Info: TShellExecuteInfo; 
    ExitCode: DWORD; 
begin 

    Result := -1; 
    FillChar(Info, SizeOf(Info), 0); 
    Info.cbSize := SizeOf(TShellExecuteInfo); 
    with Info do begin 
    fMask := SEE_MASK_NOCLOSEPROCESS; 
    Wnd := ahWnd; 
    lpFile := PChar(aFileName); 
    lpParameters := PChar(aParams); 
    lpDirectory := PChar(aStartDir); 
    nShow := aShowCmd; 
    end; 

    if ShellExecuteEx(@Info) then 
    begin 
    if aWait then 
    begin 
     repeat 
     Sleep(1); 
     Application.ProcessMessages; 
     GetExitCodeProcess(Info.hProcess, ExitCode); 
     until (ExitCode <> STILL_ACTIVE) or Application.Terminated; 
     CloseHandle(Info.hProcess); 
     Result := ExitCode; 
    end; 
    end 
end; 

以下是一些可以檢查進程是否存在的代碼。所以......當前應用程序調用更新程序並終止。該更新程序可以檢查,看是否舊的應用程序已終止和做的事情(重命名,更新,刪除等):

function TSvUtils.ProcessExists(const aExeFileName: string; aBringToForgound: Boolean=False): Boolean; 
var 
    ContinueLoop: BOOL; 
    FSnapshotHandle: THandle; 
    FProcessEntry32: TProcessEntry32; 
begin 

    FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
    FProcessEntry32.dwSize := SizeOf(FProcessEntry32); 
    ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32); 
    Result := False; 
    while Integer(ContinueLoop) <> 0 do 
    begin 
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) = 
     UpperCase(aExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) = 
     UpperCase(aExeFileName))) then 
    begin 
     if aBringToForgound then 
     EnumWindows(@BringToForgroundEnumProcess, FProcessEntry32.th32ProcessID); 
     Result := True; 
    end; 
    ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32); 
    end; 
    CloseHandle(FSnapshotHandle); 
end; 
+0

謝謝你的答案,但我想你誤解了我的問題,我需要把一個可執行文件放在'查詢'中,退出當前應用程序ion(調用者),然後從查詢中運行exec。 – 2011-05-15 17:25:36

+0

不錯的忙碌循環,順便說一句 – user422039 2011-05-15 17:58:23

+0

好吧......想着......你目前的應用程序會產生更新以完成工作並退出。然後更新程序檢查以確保舊應用程序已終止(我有可用於檢查此問題的代碼),然後更新,重命名,刪除等。完成後,它會產生新的應用程序並自行終止? – 2011-05-15 19:22:08

2

如果您可以使用CreateProcess而不是ShellExecute,你可以等待進程句柄。進程句柄在應用程序退出時發出信號。例如:

function ExecAndWait(APath: string; var VProcessResult: cardinal): boolean; 
var 
    LWaitResult : integer; 
    LStartupInfo: TStartupInfo; 
    LProcessInfo: TProcessInformation; 
begin 
    Result := False; 

    FillChar(LStartupInfo, SizeOf(TStartupInfo), 0); 

    with LStartupInfo do 
    begin 
    cb := SizeOf(TStartupInfo); 

    dwFlags := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK; 
    wShowWindow := SW_SHOWDEFAULT; 
    end; 

    if CreateProcess(nil, PChar(APath), nil, nil, 
        False, NORMAL_PRIORITY_CLASS, 
        nil, nil, LStartupInfo, LProcessInfo) then 
    begin 

    repeat 
     LWaitResult := WaitForSingleObject(LProcessInfo.hProcess, 500); 
     // do something, like update a GUI or call Application.ProcessMessages 
    until LWaitResult <> WAIT_TIMEOUT; 
    result := LWaitResult = WAIT_OBJECT_0; 
    GetExitCodeProcess(LProcessInfo.hProcess, VProcessResult); 
    CloseHandle(LProcessInfo.hProcess); 
    CloseHandle(LProcessInfo.hThread); 
    end; 
end; 

ExecAndWait返回後,如果需要可以睡100ms。

N @

相關問題