Question

Comment savoir si une instance de mon programme est en cours d'exécution? Je pensais pouvoir faire cela avec un fichier de données, mais ce serait simplement compliqué: (

Je veux le faire car je ne veux qu'une instance ouverte à un moment donné.

Était-ce utile?

La solution

Vous pouvez créer un sémaphore et arrêter l'exécution (placez le code dans votre fichier * .dpr) et vous faire afficher l'application en cours d'exécution.

var
  Semafor: THandle;

begin
  { Don't start twice ... if already running bring this instance to front }
  Semafor := CreateSemaphore(nil, 0, 1, 'MY_APPLICATION_IS_RUNNING');
  if ((Semafor <> 0) and { application is already running }
     (GetLastError = ERROR_ALREADY_EXISTS)) then 
  begin
    RestoreWindow('TMyApplication');
    CloseHandle(Semafor);
    Halt;
  end;

  Application.CreateForm(....);    
  Application.Initialize;
  Application.Run;
  CloseHandle(Semafor);
end;

EDIT (ajout de la méthode RestoreWindow ):

Le aFormName est le nom de votre classe de formulaire principale dans votre application.

procedure RestoreWindow(aFormName: string);
var
  Wnd,
  App: HWND;    
begin
  Wnd := FindWindow(PChar(aFormName), nil);
  if (Wnd <> 0) then 
  begin { Set Window to foreground }
    App := GetWindowLong(Wnd, GWL_HWNDPARENT);
    if IsIconic(App) then 
      ShowWindow(App, SW_RESTORE);

    SetForegroundwindow(App);
  end;
end;

Autres conseils

Comme Jon l’a suggéré pour la première fois, vous pouvez essayer de créer un mutex. Appelez CreateMutex . Si vous obtenez un traitement non nul, appelez GetLastError . Il vous dira si c'est vous qui avez créé le mutex ou si le mutex était déjà ouvert auparavant ( Error_Already_Exists ). Notez qu'il n'est pas nécessaire pour acquérir la propriété du mutex. Le mutex n'est pas utilisé pour l'exclusion mutuelle. Il est utilisé car c'est un objet du noyau nommé. Un événement ou un sémaphore pourrait également fonctionner.

La technique du mutex vous donne une réponse booléenne: oui, il y a un autre exemple, ou non, il n'y en a pas.

Vous voulez souvent savoir plus que cela. Par exemple, vous voudrez peut-être connaître le handle de la fenêtre principale de l'autre instance pour lui indiquer de s'afficher au premier plan à la place de votre autre instance. C'est là qu'un fichier mappé en mémoire peut être utile; il peut contenir des informations sur la première instance pour que les instances ultérieures puissent s'y référer.

Faites attention lorsque vous choisissez le nom du mutex. Lisez attentivement la documentation et gardez à l’esprit que certains caractères (tels que la barre oblique inverse) ne sont pas autorisés dans certaines versions de système d’exploitation, mais sont requis pour certaines fonctionnalités dans les autres versions de système d’exploitation.

Rappelez-vous également le problème des autres utilisateurs. Si votre programme peut être exécuté via un poste de travail distant ou un changement rapide d'utilisateur, il se peut que d'autres utilisateurs l'exécutent déjà et que vous ne souhaitiez pas vraiment empêcher l'utilisateur actuel de l'exécuter. Dans ce cas, n'utilisez pas un nom global. Si vous voulez vouloir restreindre l'accès à tous les utilisateurs, assurez-vous que les attributs de sécurité de l'objet mutex sont tels que tout le monde pourra lui ouvrir un descripteur. L'utilisation d'un pointeur null pour le paramètre lpSecurityAttributes n'est pas suffisante pour cela; le " descripteur de sécurité par défaut " que MSDN mentionne donne un accès complet à l'utilisateur actuel et aucun accès à d'autres.

Vous êtes autorisé à modifier le fichier DPR de votre programme. C'est généralement un bon endroit pour faire ce genre de chose. Si vous attendez jusqu'à l'événement OnCreate de l'un de vos formulaires, votre programme a déjà pris un peu de vitesse pour s'exécuter normalement. Il est donc maladroit d'essayer de mettre fin au programme à ce stade. Mieux vaut terminer avant que trop de travail d'interface utilisateur ait été fait. Par exemple:

var
  mutex: THandle;
  mutexName: string;
begin
  mutexName := ConstructMutexName();

  mutex := CreateMutex(nil, False, PChar(mutexName));

  if mutex = 0 then
    RaiseLastOSError; // Couldn't open handle at all.

  if GetLastError = Error_Already_Exists then begin
    // We are not the first instance.
    SendDataToPreviousInstance(...);
    exit;
  end;
  // We are the first instance.

  // Do NOT close the mutex handle here. It must
  // remain open for the duration of your program,
  // or else later instances won't be able to
  // detect this instance.

  Application.Initialize;
  Application.CreateForm(...);
  Application.Run;
end.

Il y a une question de savoir quand fermer le pseudonyme du mutex. Vous n'êtes pas obligé de le fermer. Lorsque votre processus se termine enfin (même s’il se bloque), le système d’exploitation ferme automatiquement tous les descripteurs en attente et, s’il n’ya plus de descripteurs ouverts, l’objet mutex est détruit (ce qui permet à une autre instance de votre programme de démarrer et de se considérer comme autonome. être la première instance).

Mais vous voudrez peut-être quand même fermer la poignée. Supposons que vous choisissiez d'implémenter la fonction SendDataToPreviousInstance mentionnée dans le code. Si vous voulez avoir du chic, vous pouvez alors prendre en compte le cas où l'instance précédente est déjà en train de fermer et est incapable d'accepter de nouvelles données. Ensuite, vous ne voudrez plus vraiment fermer la deuxième instance. La première instance peut fermer le pseudo mutex dès qu’elle sait qu’elle est en train de s’arrêter, devenant en fait un "canard boiteux". exemple. La deuxième instance tentera de créer le descripteur de mutex, réussira et se considérera comme la première instance réelle. L'instance précédente se fermera sans interruption. Utilisez CloseHandle pour fermer le mutex; appelez-le à partir du gestionnaire d'événements OnClose de votre formulaire principal, ou de l'endroit où vous appelez Application.Terminate , par exemple.

Le tout-puissant JVCL a un composant à cette fin. Voir "TJvAppInstances".

Vous créez un système mutex .

Je n'ai pas de code Delphi, mais voici le code C ++:

HANDLE Mutex;

const char MutexName[] = "MyUniqueProgramName";

Mutex = OpenMutex(MUTEX_ALL_ACCESS, false, MutexName);

if (Mutex)
     throw Exception("Program is already running.");
else
     Mutex = CreateMutex(NULL, true, MutexName);

La solution normale consiste à créer un nom nommé à l’échelle du système, un mutex .

  • Si vous parvenez à le créer, c'est vous qui exécutez l'application.
  • Si vous ne le faites pas, vous savez qu'il y en a un différent.

EDIT:

Je n'ai pas fourni de code car je ne connais pas Delphi. Je peux fournir du code C # si cela peut être utile.

J'aimerais ajouter un point au excellente réponse de Rob Kennedy (mis à part le fait qu'il serait préférable de créer une fonction à partir de son code au lieu de tout copier dans le fichier DPR. Vous n'avez besoin que de deux paramètres, le nom du mutex et un booléen indiquant si le mutext doit être par utilisateur ou par tout le système).

La réponse ne prend pas beaucoup en compte la dénomination du mutex. Si vous pensez que votre programme sera installé via Inno Setup (et peut-être d’autres outils d’installation), vous devez choisir le nom avec soin, car le mutex peut être utilisé pour que le programme d’installation vérifie si l’application est en cours d’exécution et avertit l’utilisateur que ils doivent fermer toutes les instances de l'application. Si vous choisissez d'autoriser une instance du programme par utilisateur, vous devrez peut-être créer un deuxième mutex à l'échelle du système, car il est possible que le programme d'installation ne nécessite aucune instance en cours d'exécution de l'application du tout afin de: être capable de remplacer des fichiers. Le nom à utiliser pour la synchronisation avec un programme d'installation InnoSetup doit être codé en dur.

Je dirais qu'il existe plusieurs stratégies différentes que vous pouvez utiliser. Mais le plus simple (et non spécifique à la plate-forme) est celui que vous avez vous-même suggéré, à savoir, au début du programme, vérifier s'il existe un fichier de verrouillage créé dans un emplacement spécifique. Si ce fichier de verrouillage existe, une autre instance est déjà en cours d'exécution. S'il n'existe pas, aucune autre instance n'est en cours d'exécution. Lorsque votre programme se ferme, vous supprimez le fichier verrou.

Cependant, en utilisant cette stratégie, vous avez un autre problème: que se passe-t-il si votre programme se bloque? Le fichier de verrouillage est toujours présent et ce cas spécifique doit être traité.

Une autre stratégie est la solution mutex à l'échelle du système, dans laquelle vous enregistrez votre présence dans le système d'exploitation (ou il est également plausible que cela se fasse automatiquement). Lorsqu'une deuxième instance essaie de démarrer, elle vérifie s'il existe déjà un processus actif avec un ID spécifique. S'il existe déjà, le second processus choisit de ne pas démarrer et met éventuellement en évidence la fenêtre du premier processus (si le processus en question possède une fenêtre qui l'est).

Cependant, cette stratégie est spécifique à la plate-forme et la mise en œuvre diffère d'une plate-forme à l'autre.

Vous pouvez simplement utiliser la fonction Windows api de FindWindow. Dans delphi, le nom de classe de la fenêtre est identique à celui de classe, vous pouvez redéfinir le nom de classe en redéfinissant la fonction CreateParams. Pour vérifier si la fenêtre existe, ajoutez du code avant la création de la fenêtre principale, avant Application.Initialize;

Program test
var 
  handle :HWND;
begin
  handle := FindWindow('TMySuperApp', nil);

  if IsWindow(handle) then
  begin 
       //app is running
       exit;
  end.

  Application.Initialize;
  Application.CreateForm(TMySuperApp, SuperApp);
  Application.Run;
end;

Contrôle du nombre d'instances d'application:

http://delphi.about.com/od/windowsshellapi/l/ aa100703a.htm

Voir cette unité (utilisant CreateMutex): UiApp

De plus, sur cette page, vous pouvez lire les avantages et les inconvénients de ce travail avec différentes méthodes (mutex, FindWindows, ...).

Cet appareil dispose de la solution pour activer l'instance previos de l'application lorsque celle-ci est détectée.

Cordialement et pardonnez-moi pour mon mauvais anglais.

Neftal & # 237; -Germ & # 225; n Est & # 233; vez -

Si vous souhaitez arrêter l'exécution de votre application plus d'une fois dans le même temps (placez le code dans *. dpr fichier du projet). montrera un message après la deuxième application sera en cours d'exécution et l'arrêter instantanément.

Forms,
  Unit1 in 'Unit1.pas' {Form1},
// add this units ....
TlHelp32,SysUtils,Windows,Dialogs;

{$R *.res}


function ProcessCount(const ExeName: String): Integer;
var
  ContinueLoop: BOOL;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  FSnapshotHandle:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize:= SizeOf(FProcessEntry32);
  ContinueLoop:= Process32First(FSnapshotHandle, FProcessEntry32);
  Result:= 0;
  while Integer(ContinueLoop) <> 0 do begin
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
      UpperCase(ExeName)) or (UpperCase(FProcessEntry32.szExeFile) =
      UpperCase(ExeName))) then Inc(Result);
    ContinueLoop:= Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;


begin
  if ProcessCount(ExtractFileName(Application.ExeName)) > 1 then begin
    MessageDlg('Application is already running!', mtError, [mbOK], 0);
    Application.Terminate;
  end else begin

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
  end;

end.

Par le passé, j’utilisais un socket pour empêcher l’exécution simultanée de plusieurs instances. Si le socket est en cours d'utilisation, ne continuez pas le programme, s'il est disponible, laissez tout fonctionner normalement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top