Ждать прежде чем ShellExecute будет выполнена? - PullRequest
8 голосов
/ 15 мая 2011

У меня, надеюсь, быстрый вопрос: возможно ли немного задержать выполнение ShellExecute?

У меня есть приложение с автообновлением. После загрузки всех необходимых файлов и т. Д. Он переименовывает текущие файлы в * .OLD, а новые - в предыдущие. Достаточно просто. Но тогда мне нужно удалить эти .OLD файлы. Эта процедура «очистки» выполняется в MainForm.OnActivate (с проверкой, является ли это первым активным процессом). Но это, видимо, происходит слишком быстро (я получаю False из DeleteFile). Это процедура:

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, затем подождать, пока вызывающее приложение полностью закроется, а затем выполнить оболочку (то есть открыть второе приложение)

Ответы [ 3 ]

5 голосов
/ 15 мая 2011

Вы делаете автопатчер правильно?

У меня была такая же проблема, и вот как я ее обошел:

Вы запускаете второе приложение с аргументом "--delay" или чем-то в этом роде. Второе приложение обрабатывает аргумент «--delay» и спит в течение 100 мс, затем продолжает работать в обычном режиме.

3 голосов
/ 15 мая 2011

Эта процедура представляет собой некоторый код утилит в нашем игровом движке.Он может запустить исполняемый файл и при необходимости дождаться его выхода.Он вернет свой код выхода:

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;
2 голосов
/ 24 мая 2011

Если вы можете использовать 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 вы можете спать в течение 100 мс, если вам нужно.

N @

...