Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CreateMutexwithatwist

0.00/5 (No votes)
1 Dec 2004 1  
CreateMutex with a twist�. some non default arguments.

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here