Wait for ShellExecute to complete?

I hopefully have a quick question: is it possible to delay ShellExecute execution a bit?

I have an application with autoupdater. After downloading all the necessary files, etc. It renames the current files to * .OLD, and the new one as the previous one. Simple enough. But then I need to delete these .OLD files. This "cleanup" procedure is performed on MainForm.OnActivate (checking if this is the first proc activation). But this seems to be happening too fast (I get False from DeleteFile). This is the procedure:

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; 

This procedure should restart the application. I am sure that the removal problem was caused by the quick launch of the second application, because if I restart it myself, giving it a little time, the files will be deleted normally.

tl; dr : I need to call ShellExecute (), which is waiting for a bit (0.1 s or so), and THEN will execute the command.

Note

I tried using the -ping command to try to delay it, but that didn't work.

Thank you in advance

Edit: rephrase

I need this to happen || The first application closes; Wait 100 ms; the second application opens || I need to call ShellExecute first, and then wait for the calling application to close completely, and then start the shell (i.e. open the second application)

+8
delphi shellexecute delay
source share
3 answers

Are you doing autopatcher right?

I had the same problem, and here's how I got around it:

You start the second application with the argument "--delay" or something like that. The second application processes the argument "--delay" and sleeps for 100 ms, then continues to work normally.

+5
source share

This routine is some utils code in our game engine. It can run an executable file and possibly wait for it to exit. It will return an exit code:

 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; 

Here is some code that can check if a process exists. So ... the current application calls the update and terminates. The updater can check whether the old application has stopped and what they are doing (rename, update, delete, etc.):

 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; 
+3
source share

If you can use CreateProcess instead of ShellExecute , you can wait for the process handle. A process handler is signaled when the application exits. For example:

 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; 

After returning ExecAndWait, you can sleep for 100 ms if you need to.

N @

+2
source share

All Articles