Comment puis-je savoir si un autre exemple de mon programme est déjà en cours d'exécution?

Comment dire si une instance de mon programme est en cours d'exécution? J'ai pensé que je pourrais faire cela avec un fichier de données mais ce serait juste désordre : (

je veux le faire car je veux qu'une seule instance soit jamais ouverte à un moment donné.

27
demandé sur Toby Allen 2009-01-20 02:07:20

11 réponses

vous pouvez créer un sémaphore et arrêter l'exécution (mettez le code dans votre *.dpr file) et vous amène l'application en cours d'exécution à l'écran.

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;

MODIFIER (ajoutée le RestoreWindow la méthode):

le aFormName est le nom de votre classe de formulaire principale dans votre demande.

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;
17
répondu Drejc 2017-07-25 08:26:06

comme Jon l'a suggéré, vous pouvez essayer de créer un mutex. Appel CreateMutex . Si vous obtenez une poignée non-null de retour, puis appeler GetLastError . Il vous dira si vous êtes celui qui a créé le mutex ou si le mutex était déjà ouvert avant ( Error_Already_Exists ). Notez qu'il est et non nécessaire pour acquérir la propriété du mutex. Le mutex n'est pas utilisé pour l'exclusion mutuelle. Il est utilisé parce c'est un nom d'objet de noyau. Un événement ou un sémaphore pourrait aussi fonctionner.

la technique mutex vous donne une réponse booléenne: Oui, il y a une autre instance, ou non, il n'y en a pas.

vous voulez souvent savoir plus que cela. Par exemple, vous pourriez vouloir connaître la poignée de la fenêtre principale de l'autre instance afin que vous puissiez lui dire de venir au premier plan à la place de votre autre instance. C'est là qu'un fichier mappé en mémoire peut être utile; il peut conservez les informations sur la première instance pour que les instances suivantes puissent s'y référer.

faites attention en choisissant le nom du mutex. Lisez attentivement la documentation, et gardez à l'esprit que certains caractères (tels que backslash) ne sont pas autorisés dans certaines versions D'OS, mais sont nécessaires pour certaines fonctionnalités dans d'autres versions D'OS.

se rappeler aussi le problème des autres utilisateurs. Si votre programme peut être exécuté via le bureau distant ou la commutation rapide d'utilisateur, puis il il peut s'agir d'autres utilisateurs qui exécutent déjà votre programme, et vous ne voudrez peut-être pas vraiment empêcher l'utilisateur actuel d'exécuter votre programme. Dans ce cas, n'utilisez pas un nom global. Si vous do voulez restreindre l'accès pour tous les utilisateurs, alors assurez-vous que les attributs de sécurité de l'objet mutex sont tels que tout le monde sera en mesure d'ouvrir une poignée pour lui. Utiliser un pointeur null pour le paramètre lpSecurityAttributes n'est pas suffisant pour cela; le" descripteur de sécurité par défaut " que MSDN les mentions donnent un accès complet à l'utilisateur courant et aucun accès aux autres.

vous êtes autorisé à éditer 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, alors votre programme a déjà un peu d'élan pour fonctionner normalement, il est donc maladroit d'essayer de terminer le programme à ce point. Mieux de résilier avant trop UI travail a é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.

la question Est de savoir quand fermer la poignée mutex. Vous n'avez pas à le fermer. Lorsque votre processus se termine (même s'il se bloque), L'OS ferme automatiquement toutes les poignées en cours, et lorsqu'il n'y a plus de poignées ouvertes, l'objet mutex est détruit (permettant ainsi à une autre instance de votre programme de démarrer et de se considérer comme la première instance).

mais vous pourriez vouloir fermer la poignée de toute façon. Supposons que vous choisi d'implémenter la fonction SendDataToPreviousInstance que j'ai mentionnée dans le code. Si vous voulez être fantaisiste, alors vous pouvez expliquer le cas où l'instance précédente est déjà en train de se fermer et est incapable d'accepter de nouvelles données. Alors vous ne voudrez pas vraiment fermer la seconde instance. La première instance pourrait fermer la poignée de mutex dès qu'elle sait qu'elle se ferme, devenant en fait une instance de "canard boiteux". La deuxième instance va essayer de créer la poignée mutex, réussir, et se considérer comme le véritable première instance. L'instance précédente se terminera sans interruption. Utilisez CloseHandle pour fermer le mutex; appelez-le à partir du gestionnaire d'événements OnClose de votre formulaire principal, ou où que vous appeliez Application.Terminate , par exemple.

38
répondu Rob Kennedy 2015-06-02 12:18:57

le tout-puissant JVCL a un composant à cet effet. Voir "TJvAppInstances".

17
répondu utku_karatas 2009-01-19 23:18:01

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);
6
répondu Kluge 2015-06-02 12:11:37

la solution normale est de créer un nommé, à l'échelle du système mutex .

  • si vous parvenez à le créer, vous êtes la seule application en cours d'exécution.
  • si vous ne le faites pas, vous savez qu'il y en a un autre.

modifier:

Je n'ai pas fourni de code car je ne connais pas Delphi. Je peux fournir le code C si ce serait utile si.

5
répondu Jon Skeet 2015-06-02 12:09:34

je voudrais ajouter un point à la excellente réponse de Rob Kennedy (outre le fait qu'il serait préférable de faire une fonction à partir de son code au lieu de tout Copier dans le fichier DPR. Vous avez seulement besoin de deux paramètres, le nom du mutex, et un booléen si le mutext doit être par utilisateur ou à l'échelle du système).

la réponse ne donne pas beaucoup de considération à la dénomination du mutex. Si vous attendez de votre programme à installer via Inno Setup (et peut-être d'autres outils de setup aussi), vous devez choisir le nom avec soin, car le mutex peut être utilisé pour faire vérifier par le programme DE setup si l'application est en cours d'exécution, et alerter l'utilisateur qu'il doit fermer toutes les instances de l'application. Si vous choisissez d'autoriser une instance du programme par utilisateur, vous pouvez avoir besoin de créer un deuxième mutex à l'échelle du système aussi, car la configuration peut avoir besoin de ne pas avoir d'instances en cours d'exécution de l'application du tout afin d'être possibilité de remplacer des fichiers. Le nom qui doit être utilisé pour la synchronisation avec un installateur InnoSetup doit être codé en dur.

2
répondu mghie 2017-05-23 11:54:22

je dirais qu'il existe plusieurs stratégies que vous pouvez employer. Mais le plus facile (et non pas spécifique à la plate-forme) est celui que vous avez vous-même suggéré, à savoir, au début du programme vérifier pour voir s'il y a un fichier de verrouillage créé dans un ensemble, emplacement spécifique. Si ce fichier lock existe, alors une autre instance est déjà en cours d'exécution, si elle n'existe pas, alors il n'y a pas d'autre instance en cours d'exécution. Lorsque votre programme sort, vous supprimez le fichier lock.

Cependant, en utilisant cette stratégie, vous avez un autre problème, que se passe-t-il si votre programme plante? Le fichier lock reste toujours, et ce cas précis doit être traité.

une autre stratégie est la solution système mutex, où vous enregistrez votre présence dans le système d'exploitation (ou il est également plausible que cela soit fait automatiquement). Quand une seconde instance essaie de démarrer, elle vérifie s'il y a déjà un processus actif avec un ID spécifique. Si elle existe déjà, le deuxième processus choisit de ne pas démarrer, et optionnellement met en lumière la fenêtre du premier processus (si le processus en question possède une fenêtre qui est).

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

1
répondu jimka 2009-01-19 23:28:38

vous pouvez simplement utiliser la fonction api windows de FindWindow. Dans le nom de classe delphi de la fenêtre est le même que le nom de classe, vous pouvez redéfinir le nom de classe en écrasant la fonction CreateParams. Pour vérifier si la fenêtre existe, ajouter du code avant la création de la fenêtre principale , avant L'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;
1
répondu Edin Omeragic 2009-01-19 23:52:16

Contrôler le nombre d'instances de l'application:

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

1
répondu g2mk 2012-03-01 06:08:44

voir cette unité (en utilisant CreateMutex): UiApp

en outre à cette page, vous pouvez lire les avantages et les inconvénients de ce travail avec des méthodes différentes (mutex, FindWindows,...).

cette unité a la solution pour activer l'instance previos de l'application lorsque cela est détecté.

salutations et excuses-moi pour mon mauvais anglais.


Neftalí-Germán Estévez -

0
répondu Germán Estévez -Neftalí- 2009-01-20 15:13:02

dans le passé, j'ai utilisé une socket pour empêcher plusieurs instances de fonctionner en même temps. Si la socket est utilisée, ne poursuivez pas le programme, s'il est disponible, laissez tout tourner normalement.

-1
répondu ahanson 2009-01-19 23:37:55