2010-12-06 4 views

Répondre

44

Je voudrais utiliser un Mutex

static void Main() 
    { 
    string mutex_id = "MY_APP"; 
    using (Mutex mutex = new Mutex(false, mutex_id)) 
    { 
     if (!mutex.WaitOne(0, false)) 
     { 
      MessageBox.Show("Instance Already Running!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand); 
      return; 
     } 
     // Do stuff 
    } 
    } 
+1

Merci pour SwDevMan81 extrait de code. –

+1

Cela peut-il être limité à un certain nombre d'instances également? –

+0

Merci. Je l'utilise dans un projet WinForms dans VS2015. J'ai fusionné ce qui précède avec Main() dans program.cs, de sorte que l'emplacement "// Do stuff" aurait ces 3 lignes générées par VS: "Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault (false); Application.Run (new Form1()); "Ajout également" using System.Threading; "en haut de program.cs. – gus

18

Il y a plusieurs façons, par exemple -

  • Énumération liste des processus avant de commencer et nier le démarrage si le nom de processus existe déjà.
  • Création d'un mutex au démarrage et vérification si le mutex existe déjà.
  • Lancement d'un programme via une classe singleton.

Chacun est demoed ci-dessous:

http://iridescence.no/post/CreatingaSingleInstanceApplicationinC.aspx
http://www.codeproject.com/KB/cs/restricting_instances.aspx
http://www.codeproject.com/KB/cs/singleinstance.aspx

Chacun a ses avantages et ses inconvénients. Mais je crois que le mutex créateur est le meilleur choix.

+5

+1 pour les alternatives non mutex –

31

Si vous décidez d'utiliser un Mutex à cet effet, il y a quelques pièges que vous devriez être au courant:

  • Si vous souhaitez limiter l'application à une instance par machine (et non un par connecté sur l'utilisateur), alors vous aurez besoin de votre nom de mutex pour commencer par le préfixe Global\. Si vous n'ajoutez pas ce préfixe, une instance différente du mutex sera créée par le système d'exploitation pour chaque utilisateur. Si vous exécutez une machine Win7/Vista avec UAC activé et que l'instance d'application en cours s'exécute en tant qu'admin, les instances suivantes échoueront à la détecter et vous obtiendrez des exceptions d'autorisation. Pour éviter cela, vous devez spécifier un ensemble d'autorisations différent pour le Mutex lors de sa création.

+6

Bonnes pièges. Une autre est que si vous exécutez deux programmes qui se détestent, l'un d'eux pourrait essayer de monter une attaque par déni de service contre l'utilisateur en supprimant le mutex de l'autre programme et en ne le relâchant jamais. –

+3

Bien ... Mais je doute que cela vaille la peine d'être protégé, car un programme "diabolique", une fois que vous lui faites confiance pour le faire fonctionner, peut de toute façon gâcher d'autres programmes et n'a pas besoin du mutex. Par exemple, il peut tuer d'autres processus, corrompre les fichiers installés par l'autre programme, changer ses raccourcis, ou le désinstaller complètement ... – Ran

+0

@Ran: Bien sûr, c'est en quelque sorte l'un des «vous êtes déjà derrière l'écoutille hermétique de Raymond Chen " problèmes. Cependant, le niveau d'autorisation requis pour sortir un mutex peut être différent du niveau d'autorisation nécessaire pour faire ces autres choses, qui devraient toutes exiger une confiance totale. Je ne sais pas si les programmes partiellement fiables sont autorisés à retirer les mutex nommés ou non; Ce serait intéressant à découvrir. –

2

ici est une solution qui a fonctionné pour moi

private static bool AlreadyRunning() 
{ 
    Process[] processes = Process.GetProcesses(); 
    Process currentProc = Process.GetCurrentProcess(); 

    foreach (Process process in processes) 
    { 
     try 
     { 
      if (process.Modules[0].FileName == System.Reflection.Assembly.GetExecutingAssembly().Location 
         && currentProc.Id != process.Id) 
       return true; 
     } 
     catch (Exception) 
     { 

     } 
    } 

    return false; 
} 

je vérifie alors la sortie de cette méthode au démarrage du programme.

+0

Sur le noyau .net (linux au moins) il semble que ça vaut la peine de vérifier si process.Modules.Count> 0. Mieux vaut prévenir les exceptions que de les laisser se passer et d'ignorer les droits? – Theyouthis

2

Ajout de cette réponse car les précédentes ne fonctionnaient pas sous linux (testé avec ubuntu 14.0.4) avec .net core1.1 et parce que cette question est très haute dans les résultats de recherche. Variation de la solution de @ MusuNaji, si ce n'était pas déjà évident pour vous.

private static bool AlreadyRunning() 
    { 
     Process[] processes = Process.GetProcesses(); 
     Process currentProc = Process.GetCurrentProcess(); 
     logger.LogDebug("Current proccess: {0}", currentProc.ProcessName); 
     foreach (Process process in processes) 
     { 
      if (currentProc.ProcessName == process.ProcessName && currentProc.Id != process.Id) 
      { 
       logger.LogInformation("Another instance of this process is already running: {pid}", process.Id); 
       return true; 
      } 
     } 
     return false; 
    } 

Cette réponse est également affiché sur mon cœur dotnet question spécifique ici: Single instance dotnetcore cli app on linux

0

La réponse la plus droite en avant pour moi, illustré ci-dessous, extrait de Madhur Ahuja a posté lien (http://www.webskaper.no/wst/creatingasingleinstanceapplicationinc-aspx/) - reproduit ici (les solutions de projet de code m'ont été cachées).

Le point important était de maintenir le mutex jusqu'à la fin du processus (évident, je suppose).

bool createdNew; 
using (Mutex mutex = new Mutex(true, "MyApplicationName", out createdNew)) 
{ 
    if (createdNew) { 
     // process 
    } 
    else { 
     // in my case, quietly exit 
    } 
} 
Questions connexes