HOWTO: Detect instances running in any user session with AppMutex

Under Windows XP with Fast User Switching or Windows NT/2000/2003 with Terminal Services, AppMutex by default will not find mutexes created in user sessions other than the one Setup/Uninstall is running under. This is because each user session has its own kernel namespace.

To detect mutexes created in other sessions, your application must create two mutexes: one with a Global\ prefix and the other without.

Mutexes with the Global\ prefix are accessible from any user session. A like-named mutex must also be created in the session namespace (i.e. without the Global\ prefix) in case the creation of the Global mutex failed due to security restrictions or lack of operating system support (versions of Windows NT prior to 4.0 Terminal Server Edition don't support the Global\ prefix).

Additionally, a special security descriptor must be passed in each of the CreateMutex() calls to ensure the mutex is accessible by different users.

Here is an example of how to create the two mutexes in Delphi:

procedure CreateMutexes(const MutexName: String);
{ Creates the two mutexes checked for by the installer/uninstaller to see if
the program is still running.
One of the mutexes is created in the global name space (which makes it
possible to access the mutex across user sessions in Windows XP); the other
is created in the session name space (because versions of Windows NT prior
to 4.0 TSE don't have a global name space and don't support the 'Global\'
prefix). }
const
SECURITY_DESCRIPTOR_REVISION = 1; { Win32 constant not defined in Delphi 3 }
var
SecurityDesc: TSecurityDescriptor;
SecurityAttr: TSecurityAttributes;
begin
{ By default on Windows NT, created mutexes are accessible only by the user
running the process. We need our mutexes to be accessible to all users, so
that the mutex detection can work across user sessions in Windows XP. To
do this we use a security descriptor with a null DACL. }
InitializeSecurityDescriptor(@SecurityDesc, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(@SecurityDesc, True, nil, False);
SecurityAttr.nLength := SizeOf(SecurityAttr);
SecurityAttr.lpSecurityDescriptor := @SecurityDesc;
SecurityAttr.bInheritHandle := False;
CreateMutex(@SecurityAttr, False, PChar(MutexName));
CreateMutex(@SecurityAttr, False, PChar('Global\' + MutexName));
end;
...
begin
CreateMutexes('YourMutexNameGoesHere');
end;