2011-05-15 136 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 @

相关问题