Comment éviter plusieurs instances d’utilisateurs différents tout en autorisant plusieurs instances sur une session utilisateur unique

J’ai une application Windows. Je souhaite autoriser plusieurs instances pour une session utilisateur unique, mais je ne veux pas de plusieurs instances d’utilisateurs différents. En termes simples, si A se connecte à Windows, il pourra alors exécuter une application autant de fois qu’il le voudra, mais plus tard, B se connectera également. Il devra attendre que toutes les applications de A soient fermées.

Est-ce possible?

Cette exigence peut être remplie à l’aide d’un object Mutex nommé dans l’ espace de noms d’objects de kernel global. Un object mutex est créé à l’aide de la fonction CreateMutex . Voici un petit programme pour illustrer son utilisation:

int _tmain(int argc, _TCHAR* argv[]) { if ( ::CreateMutexW( NULL, FALSE, L"Global\\5BDC0675-2318-404A-96CA-DBDE9BC2F71D" ) != NULL ) { std::wcout << L"Mutex acquired. GLE = " << GetLastError() << std::endl; // Continue execution } else { std::wcout << L"Mutex not acquired. GLE = " << GetLastError() << std::endl; // Exit application } _getch(); return 0; } 

La première instance d'application crée l'object mutex et GetLastError renvoie ERROR_SUCCESS (0). Les instances suivantes acquerront une référence à l'object mutex existant et GetLastError renvoie ERROR_ALREADY_EXISTS (183). Les instances lancées à partir d'une autre session client n'obtiendront aucune référence à l'object mutex et GetLastError renvoie ERROR_ACCESS_DENIED (5).

Quelques notes sur la mise en œuvre:

  • Un object mutex est créé dans l'espace de noms d'object kernel global en ajoutant le préfixe "Global \" .
  • L'object mutex doit avoir un nom unique pour pouvoir s'y référer de n'importe où. Le moyen le plus simple de créer un nom unique consiste à utiliser la représentation sous forme de chaîne d'un GUID (les GUID peuvent être générés à l'aide de l'outil guidgen.exe de Visual Studio). N'utilisez pas le GUID de l'exemple de code, car quelqu'un d'autre le fera également.
  • Il n'y a pas d'appel à CloseHandle pour libérer l'object mutex. C'est intentionnel. (Voir CreateMutex : le système ferme automatiquement le descripteur à la fin du processus. L'object mutex est détruit à la fermeture du dernier descripteur . )
  • L'object mutex est créé à l'aide du descripteur de sécurité par défaut. Les listes de contrôle d'access dans le descripteur de sécurité par défaut proviennent du jeton principal ou d'emprunt d'identité du créateur. Si des processus dans différentes sessions client s'exécutent avec le même jeton primaire / d'emprunt d'identité, le mutex peut toujours être acquis à partir des deux sessions. Dans cette situation, la solution proposée ne répond potentiellement pas aux exigences. Il est difficile de savoir ce qui devrait se passer si un utilisateur exécute l'application en imitant l'identité d'une autre session client.
  • L'object mutex est utilisé uniquement comme sentinelle et ne participe pas à la synchronisation.

J’ai utilisé le code précédent sous Win10 / VS 2017/64 bits

Il est faux de tester si (:: CreateMutex ..

nous devons vérifier l’erreur, alors utilisez:

 BOOL checkUniqueInstance() { if (::CreateMutexW(NULL, FALSE, L"Global\\27828F4B-5FC9-40C3-9E81-6C485020538F") != NULL) { auto err = GetLastError(); if (err == 0) { return TRUE; } } CSsortingng msg; msg.Format(_T("err: %d - Mutex NOT acquired"), GetLastError()); OutputDebugSsortingng(msg); // Exit application return FALSE; }