﻿id	summary	reporter	owner	description	type	status	milestone	component	version	severity	resolution	keywords	cc
2108	_Singleton leaves an open handle	smartee		"It creates a mutex, however if the named mutex already exists, it gets a handle to it (that can be used with WaitForSingleObject) but it does nothing with this handle, it instead returns 0 and sets @error to ERROR_ALREADY_EXISTS. Great for a one time check at the beginning of a script, but it essentially kills its own post-run functionality by leaving the handle open.

Suggested fix:
After this line

{{{
If $lastError[0] = $ERROR_ALREADY_EXISTS Then
}}}


Drop in these lines to close the handle

{{{
DllCall(""kernel32.dll"", ""bool"", ""CloseHandle"", ""handle"", $handle[0])
If @error Then Return SetError(@error, @extended, 0)
}}}


So the updated function will look like this:

{{{
; #FUNCTION# ====================================================================================================================
; Name...........: _Singleton
; Description ...: Enforce a design paradigm where only one instance of the script may be running.
; Syntax.........: _Singleton($sOccurenceName[, $iFlag = 0])
; Parameters ....: $sOccurenceName - String to identify the occurrence of the script.  This string may not contain the \ character unless you are placing the object in a namespace (See Remarks).
;                 $iFlag          - Behavior options.
;                 |0 - Exit the script with the exit code -1 if another instance already exists.
;                 |1 - Return from the function without exiting the script.
;                 |2 - Allow the object to be accessed by anybody in the system. This is useful if specifying a ""Global\"" object in a multi-user environment.
; Return values .: Success    - The handle to the object used for synchronization (a mutex).
;                 Failure     - 0
; Author ........: Valik
; Modified.......:
; Remarks .......: You can place the object in a namespace by prefixing your object name with either ""Global\"" or ""Local\"".  ""Global\"" objects combined with the flag 2 are useful in multi-user environments.
; Related .......:
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _Singleton($sOccurenceName, $iFlag = 0)
Local Const $ERROR_ALREADY_EXISTS = 183
Local Const $SECURITY_DESCRIPTOR_REVISION = 1
Local $tSecurityAttributes = 0
If BitAND($iFlag, 2) Then
  ; The size of SECURITY_DESCRIPTOR is 20 bytes.  We just
  ; need a block of memory the right size, we aren't going to
  ; access any members directly so it's not important what
  ; the members are, just that the total size is correct.
  Local $tSecurityDescriptor = DllStructCreate(""byte;byte;word;ptr[4]"")
  ; Initialize the security descriptor.
  Local $aRet = DllCall(""advapi32.dll"", ""bool"", ""InitializeSecurityDescriptor"", _
    ""struct*"", $tSecurityDescriptor, ""dword"", $SECURITY_DESCRIPTOR_REVISION)
  If @error Then Return SetError(@error, @extended, 0)
  If $aRet[0] Then
   ; Add the NULL DACL specifying access to everybody.
   $aRet = DllCall(""advapi32.dll"", ""bool"", ""SetSecurityDescriptorDacl"", _
     ""struct*"", $tSecurityDescriptor, ""bool"", 1, ""ptr"", 0, ""bool"", 0)
   If @error Then Return SetError(@error, @extended, 0)
   If $aRet[0] Then
    ; Create a SECURITY_ATTRIBUTES structure.
    $tSecurityAttributes = DllStructCreate($tagSECURITY_ATTRIBUTES)
    ; Assign the members.
    DllStructSetData($tSecurityAttributes, 1, DllStructGetSize($tSecurityAttributes))
    DllStructSetData($tSecurityAttributes, 2, DllStructGetPtr($tSecurityDescriptor))
    DllStructSetData($tSecurityAttributes, 3, 0)
   EndIf
  EndIf
EndIf
Local $handle = DllCall(""kernel32.dll"", ""handle"", ""CreateMutexW"", ""struct*"", $tSecurityAttributes, ""bool"", 1, ""wstr"", $sOccurenceName)
If @error Then Return SetError(@error, @extended, 0)
Local $lastError = DllCall(""kernel32.dll"", ""dword"", ""GetLastError"")
If @error Then Return SetError(@error, @extended, 0)
If $lastError[0] = $ERROR_ALREADY_EXISTS Then
  DllCall(""kernel32.dll"", ""bool"", ""CloseHandle"", ""handle"", $handle[0])
  If @error Then Return SetError(@error, @extended, 0)
  If BitAND($iFlag, 1) Then
   Return SetError($lastError[0], $lastError[0], 0)
  Else
   Exit -1
  EndIf
EndIf
Return $handle[0]
EndFunc   ;==>_Singleton

 }}}

Thread showing issue:
http://www.autoitscript.com/forum/topic/136745-solved-run-scripts-in-sequence/"	Bug	closed		Standard UDFs	3.3.8.0	None	No Bug	_Singleton CreateMutex CloseHandle	
