2011-05-15 5 views
8

J'ai une question rapide à espérer: Est-il possible de retarder un peu l'exécution de ShellExecute?Attendre que ShellExecute soit exécuté?

J'ai une application avec autoupdater. Après avoir téléchargé tous les fichiers nécessaires, etc, il renomme les fichiers actuels à * .OLD et le nouveau comme le précédent. Assez simple. Mais alors j'ai besoin de supprimer ces fichiers .OLD. Cette procédure de 'nettoyage' est exécutée sur MainForm.OnActivate (avec une vérification s'il s'agit du premier proc activé). Mais cela arrive apparemment trop vite (je reçois False de DeleteFile). Voici la procédure:

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; 

Cette procédure est supposée redémarrer l'application. Je suis certain que le problème de suppression est causé par le démarrage rapide de la deuxième application, parce que si je le redémarre moi-même, en lui donnant un peu de temps, les fichiers sont supprimés normalement. Version: tl; dr version: J'ai besoin d'appeler ShellExecute() qui attend un bit (0,1 seconde environ) et THEN exécute la commande.

Remarque

J'ai essayé d'utiliser la commande -ping pour tenter de le retarder, mais cela n'a pas fonctionné.

Merci beaucoup à l'avance

Edit: reformulée

J'ai besoin que cela se produise || La première application se ferme; Attendez 100 ms; la deuxième application s'ouvre ||. Je dois d'abord appeler ShellExecute, puis attendre que l'application appelante se ferme complètement, puis exécuter le shell (c'est-à-dire ouvrir la deuxième application)

+3

Je ne comprends pas.Vous voulez attendre 100 ms, puis faire 'ShellExecute'? Eh bien, faites-le! 'Sommeil (100); ShellExecute (...) '. Ou voulez-vous que ShellExecute ne revienne pas tant que le processus nouvellement créé n'est pas sorti? Si oui, en théorie, vous voulez le 'Sleep' *** après ***' ShellExecute', pas * avant * il. Mais c'est une solution laide. Au lieu de cela, vous devriez 'WaitForSingleObject' ou quelque chose comme ça. –

+1

Je vais essayer de le reformuler: j'ai besoin que cela arrive || La première application se ferme; Attendez 100 ms; la deuxième application s'ouvre ||. Je dois d'abord appeler ShellExecute, puis attendre que l'application appelante se ferme complètement, puis exécuter le shell (c'est-à-dire ouvrir la seconde application) -> Aucune de vos suggestions. J'ai besoin de ShellExecute _not pour exécuter_ jusqu'à ce que l'application en cours soit complètement fermée (afin que je puisse supprimer ses fichiers) –

+0

Vous ne pouvez pas faire cela. Après la fermeture de l'application 1, mais avant l'ouverture de l'application 2, vous ne pouvez rien faire car vous n'avez aucun programme en cours d'exécution. Ce que vous pouvez faire est d'appeler une application, de dormir, puis d'appeler une autre application, puis de terminer. Mais au lieu d'un 'sommeil 'fixe, vous devriez' WaitForSingleObject' ou quelque chose d'autre plus robuste. –

Répondre

5

Vous faites un autoguideur, n'est-ce pas?

J'ai eu le même problème et voici comment je contourna:

Vous exécutez deuxième application avec l'argument « --delay » ou quelque chose comme ça. La deuxième application traite l'argument "--delay" et dort pendant 100 ms, puis continue à fonctionner normalement.

+0

Semble soigné.Simple moi.Regardez pour vous, merci –

+4

Que faire si vous copiez un fichier WTV sur un disque dur externe à 100 ms n'est probablement pas suffisant, et vous échouez toujours Une solution basée sur 'WaitForSingleObject' est meilleure Sinon, la seconde application peut faire' while done do sleep (100) 'ou quelque chose comme ça au démarrage Ce que je fais lors de l'exécution de mon "re-runner" est simplement passer en params avec les fichiers à copier (source, dest), puis réessayer si elle échoue en raison de l'application encore –

+0

okay.Je vais regarder cela aussi, merci –

3

Cette routine est un code utilitaires dans notre moteur de jeu. Il peut exécuter un exécutable et éventuellement l'attendre pour quitter. Il renverra son code de sortie:

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; 

Voici un code qui peut vérifier si un processus existe. Donc ... l'application actuelle appelle le programme de mise à jour et se termine. Updater peut vérifier si ancienne application est terminée et le faire est chose (renommer, modifier, supprimer, 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; 
+0

Merci pour la réponse, mais je pense que vous avez mal compris ma question: je devais mettre un exécutable dans une 'requête', quitter l'application actuelle ion (l'appelant), puis exécutez l'exec à partir de la requête. –

+0

belle busy-loop, BTW – user422039

+0

Ok .... penser ... votre application actuelle engendre le programme de mise à jour pour faire le travail et quitte. Le programme de mise à jour vérifie ensuite que l'ancienne application est terminée (j'ai le code que vous pouvez utiliser pour vérifier cela), puis met à jour, renomme, supprime, etc. Une fois terminé, il engendre une nouvelle application et se termine? –

2

Si vous pouvez utiliser CreateProcess au lieu de ShellExecute, vous pouvez attendre sur la poignée de processus. Le handle de processus est signalé lorsque l'application se termine. Par exemple:

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; 

Après le retour d'ExecAndWait, vous pouvez dormir pendant 100ms si nécessaire.

N @

Questions connexes