Le sémaphore mondial ignore le sémaphore local

J’ai une application qui accède à certains fichiers et ressources système, il ne peut y avoir qu’une seule instance de l’application active. Pour ce faire, créez un sémaphore nommé et arrêtez l’application lorsque le sémaphore est déjà affecté. Dans le passé (lire: lorsque Windows XP était le système d’exploitation le plus courant), cela fonctionnait bien, mais nous avons maintenant remarqué que l’ancien code ne fonctionnait pas avec plusieurs sessions utilisateur.

Voici l’ancien code:

hInstanceSem := CreateSemaphore(nil, 0, 1, PChar(GetProductName(Application.ExeName))); if (hInstanceSem  0) and (GetLastError = ERROR_ALREADY_EXISTS) then // do not run the Application 

J’ai donc fait des recherches, appris sur les sémaphores mondiaux et changé le code en ceci:

 function CreateGlobalSemaphor(SemaphorName: Ssortingng): Cardinal; var desc: SECURITY_DESCRIPTOR; att : TSecurityAtsortingbutes; sem : Cardinal; begin att.nLength := SizeOf(TSecurityAtsortingbutes); att.bInheritHandle := true; att.lpSecurityDescriptor := @desc; InitializeSecurityDescriptor(att.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(att.lpSecurityDescriptor, True, nil, False); sem := CreateSemaphore(@att, 0, 1, PChar('Global\' + SemaphorName)); if (sem  0) and (GetLastError()  ERROR_ALREADY_EXISTS) then begin Result := sem; end else begin Result := 0; CloseHandle(sem); end; end; if CreateGlobalSemaphor(GetProductName(Application.ExeName)) = 0 then // do not run the Application 

Maintenant, lorsque je lance l’application sur User1, passez à User2 et essayez de démarrer l’application, elle ne s’exécutera pas (comme prévu).

MAIS lorsque je lance une ancienne version de mon programme et que je lance la version actuelle avec le nouveau code dans la même session utilisateur, le nouveau code ignore le sémaphore créé par l’ancien code et une seconde instance de mon application est démarrée. (Inutile de dire que ça plante …)

Il me semble que le sémaphore local est hors de scope du sémaphore global, sinon un deuxième object du même nom ne pourrait pas être créé. Ma question est la suivante: comment le sémaphore global (nouveau code) peut-il détecter qu’un sémaphore local (ancien code) portant le même nom est déjà atsortingbué?

N’oubliez pas qu’il s’agit d’un problème de compatibilité ascendante. Je ne peux pas simplement recomstackr et redissortingbuer les anciennes versions de mon application.

La documentation des espaces de noms des objects du kernel explique que:

Pour les processus démarrés sous une session client, le système utilise par défaut l’espace de noms de session.

L’ancien programme n’incluant pas explicitement un espace de noms, l’espace de noms de session, Local\ est utilisé. Cela signifie que l’ancien programme crée un sémaphore nommé Local\xxx . Maintenant, le nouveau programme utilise un sémaphore nommé Global\xxx . Donc, vous avez deux sémaphores distincts et les programmes ne sont pas du tout conscients d’eux-mêmes.

  • Si vous souhaitez que le nouveau programme interagisse avec l’ancien programme, vous devez utiliser un object nommé Local\xxx .
  • Si vous souhaitez que le nouveau programme bloque d’autres nouveaux programmes dans différentes sessions, vous devez utiliser un object nommé Global\xxx .

La conclusion évidente à tirer ici est que vous devez créer deux objects. Un nommé Local\xxx et un nommé Global\xxx .

Notez qu’il n’est pas possible de reconfigurer l’exclusion des sessions entre les programmes existants. Ils utilisent déjà Local\xxx et vous n’avez aucun moyen de changer cela maintenant.

Vous devez également corriger la gestion des erreurs dans votre nouveau code. Vous appelez CreateSemaphore , puis appelez GetLastError sans vérifier d’abord la valeur renvoyée par l’appel à CreateSemaphore .