|
Imports System.Runtime.InteropServices
' ------------------------------------------------------------------------------
' The .NET Framework has a Mutex-class built-in under System.Threading.Mutex.
' The problem with mutexes created with this class is that these mutexes are
' using the default security. Because of this, gui- or console-appications
' don't have sufficient access to open a mutex created in a service running
' under the Local System Account.
'
' To work-around this limitation, I've created my own Mutex-class which doesn't
' create mutexes using default security.
'
' For more information about this problem and a more detailed explanation of
' the work-around, read Ask Dr. GUI #49:
' http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaskdr/html/drgui49.asp
' ------------------------------------------------------------------------------
Friend NotInheritable Class Mutex
Implements IDisposable
Private mMutex As Integer = 0
Private mName As String = ""
Public Sub New(ByVal lcName As String)
mName = lcName
End Sub
Private Sub Create()
Dim objSidEveryone As IntPtr = IntPtr.Zero
' First we're going to create a NULL DACL. An object with NULL-DACL security grants all
' access to everyone, regardless of security context. One downside of this approach is
' that the object is now completely unsecured. This should be reprogrammed in a safer way!
' TODO Develop without using a NULL DACL. More information can be found in MSDN in
' Ask Dr. GUI #49.
Dim objSecurityDescriptor As ApiHelper.SECURITY_DESCRIPTOR
Dim intResult As Integer = ApiHelper.InitializeSecurityDescriptor(objSecurityDescriptor, ApiHelper.SECURITY_DESCRIPTOR_REVISION)
If intResult = 0 Then
Throw New Exception("InitializeSecurityDescriptor failed: " & ApiHelper.GetWin32ErrorMessage(Marshal.GetLastWin32Error))
End If
intResult = ApiHelper.SetSecurityDescriptorDacl(objSecurityDescriptor, 1, New IntPtr(0), 0)
If intResult = 0 Then
Throw New Exception("SetSecurityDescriptorDacl failed: " & ApiHelper.GetWin32ErrorMessage(Marshal.GetLastWin32Error))
End If
Dim objSecurityAttributes As ApiHelper.SECURITY_ATTRIBUTES
objSecurityAttributes = New ApiHelper.SECURITY_ATTRIBUTES
objSecurityAttributes.nLength = Marshal.SizeOf(objSecurityAttributes)
objSecurityAttributes.bInheritHandle = 0
objSecurityAttributes.lpSecurityDescriptor = ApiHelper.VarPtr(objSecurityDescriptor)
mMutex = ApiHelper.CreateMutex(objSecurityAttributes, 0, mName)
If mMutex = 0 Then
Throw New Exception("CreateMutex failed: " & Marshal.GetLastWin32Error.ToString)
End If
End Sub
Public Sub Wait()
Dim intResult As Integer
' The following document gives more information about the mutex-workflow
' ms-help://MS.VSCC.2003/MS.MSDNQTR.2004APR.1033/dllproc/base/using_mutex_objects.htm
' Create a mutex with no initial owner.
Call Create()
' Request ownership of Mutex
intResult = ApiHelper.WaitForSingleObject(mMutex, ApiHelper.INFINITE)
Select Case intResult
Case ApiHelper.WAIT_OBJECT_0
' the thread got mutex ownership...
Exit Sub
Case ApiHelper.WAIT_TIMEOUT
' cannot get mutex ownership due to time-out
Throw New Exception("Timed out waiting for mutex-ownership.")
Case ApiHelper.WAIT_ABANDONED
' The specified object is a mutex object that was not released
' by the thread that owned the mutex object before the owning thread
' terminated. Ownership of the mutex object is granted to the calling
' thread, and the mutex is set to nonsignaled.
Throw New Exception("WAIT_ABANDONED returned by WaitForSingleObject")
Case Else
Throw New Exception("Unexpected result returned by WaitForSingleObject")
End Select
End Sub
Public Sub Release()
If mMutex <> 0 Then
If ApiHelper.ReleaseMutex(mMutex) = 0 Then
Throw New Exception("ReleaseMutex failed: " & Marshal.GetLastWin32Error.ToString)
End If
mMutex = 0
End If
End Sub
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
Private Sub Dispose(ByVal lcDisposing As Boolean)
SyncLock Me
If mMutex <> 0 Then
Call ApiHelper.CloseHandle(New IntPtr(mMutex))
mMutex = 0
End If
End SyncLock
End Sub
Public Sub Dispose() Implements System.IDisposable.Dispose
' Because the object is explicitely cleaned up, stop the garbage
' collector from caling the Finalize-method.
GC.SuppressFinalize(Me)
' Cleaning up...
Dispose(True)
End Sub
' Personally, I find it more logical to Close a Mutex than to Dispose it. So users
' can call Close if they want to.
Public Sub Close()
Call Dispose()
End Sub
End Class
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I am a developer spending most of my time in C#, .NET 2.0 and Sql Server 2005. I am working for a Belgium company called Adam Software developing Asset Management Software. More information about my company and our software can be found at http://www.adamsoftware.net