Introduction
This is just a brief follow-up on the excellent article submitted by Liviu Birjega: Windows-based application over Terminal Services using WtsAPI32.
In my own experience, under WTS, the function CreateMutex
can be called simply like this:
hMutex = CreateMutex(NULL, FALSE, csAppName);
BUT, doing so for a 2nd and subsequent sessions resolves with a return error 5 (ERROR_ACCESS_DENIED
) when calling GetLastError()
.
On further reading the MSDN documentation, it provides some explanation as follows:
“… Pointer to a security descriptor for the object that controls the sharing of it. If NULL
is specified for this member, the object is assigned the default security descriptor of the calling process.
This is not the same as granting access to everyone by assigning a null DACL.
The default security descriptor is based on the default DACL of the access token belonging to the calling process. By default, the default DACL in the access token of a process allows access only to the user represented by the access token. If other users must access the object, you can either create a security descriptor with a null DACL, or add ACEs to the DACL that grants access to a group of users.”
This is explained in more detail in Rob Manderson’s excellent article: Using Access Control Lists to secure access to your objects.
So, in order to get back the desired result (183 = ERROR_ALREADY_EXISTS
) when calling GetLastError()
you will have to actually do something like this…
BOOL IsAnotherWTSUserLoggedIn(LPCTSTR sAppName)
{
if(GetSystemMetrics(SM_REMOTESESSION))
{
HANDLE hMutex = NULL;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, 0, FALSE);
SECURITY_ATTRIBUTES sa = { sizeof sa, &sd, FALSE };
CString csAppName;
csAppName.Format(_T("Global\\%s"), sAppName);
hMutex = ::CreateMutex(&sa, FALSE, csAppName);
if( GetLastError() == ERROR_ALREADY_EXISTS )
{
CloseHandle(hMutex);
return TRUE;
}
}
return FALSE;
}
Yes, and just one more little comment for Liviu, it seems that the correct “Verb” to use is “Global” – not “Session” as suggested – this is also supported in the MSDN documentation. Hope someone finds some use for all this, I know I did.
Born in Romania in 1945, lived for some 30 years in Israel and moved to join the family in Australia in 1985.
Started programming in 1973 (yes, the stone age…) on WANG, with BASIC, Assembler, then some Fortran around 1979, in 1981 got my first home “Personal Computer” – A Dragon 32 (had it connected to a TV monitor and a cassette deck for data / program storage)..
Later on PDP-11 , Data General AOS/VS for some 8 years, IBM 32/34/36 with RPG II and III, real “Fun” language to work with (NOT).
In 1985 moved to Australia, started a love affair with dBase III, then Clipper 87 and finally in 1991 switched 100% to work in C and later in C++
In my “Spare time” I build and fly Radio Control Model Airplanes.