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.