Jump to content

Problem with Mutex


Recommended Posts

#RequireAdmin

Global Const $MUTEX_ALL_ACCESS = 0x1F0001
Global $hMutexGlobal

$name = "SciTE-UniqueInstanceMutex-Default"

ConsoleWrite("Mutex Exists: " & (_MutexExists($name) = 1) & @CRLF)
$hMutexGlobal = _MutexOpen($name)
ConsoleWrite("Mutex Handle: " & $hMutexGlobal & @CRLF)
ConsoleWrite("Mutex Released: " &  (_ReleaseMutex($hMutexGlobal) = 1) & @CRLF)
ConsoleWrite("Mutex Exists: " & (_MutexExists($name) = 1) & @CRLF)

Func _MutexOpen($szMutexName)
    Local $hMutex = DllCall("kernel32.dll", "hwnd", "OpenMutex", "int", $MUTEX_ALL_ACCESS, "int", 0, "str", $szMutexName)
    If IsArray($hMutex) And $hMutex[0] Then
        Return $hMutex[0]
    EndIf
    Return 0
EndFunc

Func _MutexExists($szMutexName)
    Local $hMutex = DllCall("Kernel32.dll", "hwnd", "OpenMutex", "int", 0x1F0001, "int", 1, "str", $szMutexName)
    Local $aGLE = DllCall("Kernel32.dll", "int", "GetLastError")
    If IsArray($hMutex) And $hMutex[0] Then
        DllCall("Kernel32.dll", "int", "CloseHandle", "hwnd", $hMutex[0])
    EndIf
    If IsArray($aGLE) And $aGLE[0] = 127 Then Return 1
    Return 0
EndFunc  ;==>_MutexExists

Func _ReleaseMutex($hMutex)
    Local $aRM = DllCall("kernel32.dll", "int", "ReleaseMutex", "hwnd", $hMutex)
    Local $aCH = DllCall("Kernel32.dll", "int", "CloseHandle", "hwnd", $hMutex)
    If (IsArray($aRM) And $aRM[0] > 0) And (IsArray($aCH) And $aCH[0] > 0) Then Return 1
    Return 0
EndFunc  ;==>ExitScript

I guess most have Scite so to make it easier to test I'm using the Scite mutex.

This is my output:

Mutex Exists: True

Mutex Handle: 0x000006FC

Mutex Released: False

Mutex Exists: True

It appears to me that the problem is either in _MutexOpen or _ReleaseMutex. Most likely because the current thread doesn't own the mutex. So my question is how do I make the thread to have ownership of the mutex?

OpenMutex: http://msdn.microsoft.com/en-us/library/ms684315(VS.85).aspx

ReleaseMutex: http://msdn.microsoft.com/en-us/library/ms685066(VS.85).aspx

Link to comment
Share on other sites

It appears to me that the problem is either in _MutexOpen or _ReleaseMutex. Most likely because the current thread doesn't own the mutex. So my question is how do I make the thread to have ownership of the mutex?

I don't think you can "Take Ownership" of the mutex unless the current owner releases it. You are just in the que to get ownership when available. Since you are using SciTE's mutex, that would mean closing SciTE.

:D

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

PsaltyDS is right of course. Run this to see (run and then close SciTE):

#RequireAdmin

HotKeySet("{ESC}", "_Escape"); ESC to exit


#include <WinAPI.au3>

Global Const $MUTEX_ALL_ACCESS = 0x1F0001
Global $hMutexGlobal

$name = "SciTE-UniqueInstanceMutex-Default"



While 1

    ConsoleWrite("Mutex Exists: " & (_MutexExists($name) = 1) & @CRLF)
    $hMutexGlobal = _MutexOpen($name)
    ConsoleWrite("Mutex Handle: " & $hMutexGlobal & @CRLF)

    If _ReleaseMutex($hMutexGlobal) = 1 Then
        MsgBox(0, '', "Mutex Released!" & @CRLF & "Mutex Exists: " & (_MutexExists($name) = 1))
    Else
        ConsoleWrite("Mutex Released: False" & @CRLF)
        ConsoleWrite("Mutex Exists: " & (_MutexExists($name) = 1) & @CRLF)
    EndIf
    Sleep(1000)
WEnd



Func _MutexOpen($szMutexName)

    Local $tSECURITY_ATTRIBUTES = DllStructCreate("dword Length;" & _
            "ptr SecurityDescriptor;" & _
            "int InheritHandle")

    DllStructSetData($tSECURITY_ATTRIBUTES, "Length", DllStructGetSize($tSECURITY_ATTRIBUTES))
    DllStructSetData($tSECURITY_ATTRIBUTES, "InheritHandle", 1); inherit the handle;<- THIS!!!

    Local $hMutex = DllCall("kernel32.dll", "hwnd", "CreateMutex", _
            "ptr", DllStructGetPtr($tSECURITY_ATTRIBUTES), _
            "int", 1, _
            "str", $szMutexName)

    If @error Or Not $hMutex[0] Then
        Return 0
    EndIf

    Return $hMutex[0]

EndFunc  ;==>_MutexOpen



Func _MutexOpen_($szMutexName)
    Local $hMutex = DllCall("kernel32.dll", "hwnd", "OpenMutex", "int", $MUTEX_ALL_ACCESS, "int", 0, "str", $szMutexName)
    If IsArray($hMutex) And $hMutex[0] Then
        Return $hMutex[0]
    EndIf
    Return 0
EndFunc  ;==>_MutexOpen_




Func _MutexExists($szMutexName)
    Local $hMutex = DllCall("Kernel32.dll", "hwnd", "OpenMutex", "int", 0x1F0001, "int", 1, "str", $szMutexName)
    Local $aGLE = DllCall("Kernel32.dll", "int", "GetLastError")
    If IsArray($hMutex) And $hMutex[0] Then
        DllCall("Kernel32.dll", "int", "CloseHandle", "hwnd", $hMutex[0])
    EndIf
    If IsArray($aGLE) And $aGLE[0] = 127 Then Return 1
    Return 0
EndFunc  ;==>_MutexExists

Func _ReleaseMutex($hMutex)
    Local $aRM = DllCall("kernel32.dll", "int", "ReleaseMutex", "hwnd", $hMutex)
    ConsoleWrite("!!!!" & _WinAPI_GetLastErrorMessage())
;ConsoleWrite("!!!!" & $aRM[0] & @CRLF)
    Local $aCH = DllCall("Kernel32.dll", "int", "CloseHandle", "hwnd", $hMutex)
    If (IsArray($aRM) And $aRM[0] > 0) And (IsArray($aCH) And $aCH[0] > 0) Then Return 1
    Return 0
EndFunc  ;==>_ReleaseMutex



Func _Escape()
    Exit
EndFunc  ;==>_Escape

I changed _MutexOpen() and added _WinAPI_GetLastErrorMessage().

ESC to exit

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

Do it like this and you can run it from SciTE, then close SciTE to see what happens:

#RequireAdmin

HotKeySet("{ESC}", "_Escape"); ESC to exit

#include <WinAPI.au3>

Global Const $MUTEX_ALL_ACCESS = 0x1F0001
Global $hMutexGlobal
Global $name = "SciTE-UniqueInstanceMutex-Default"

Global $hGUI = GUICreate("Mutex Test", 400, 600)
Global $ctrlEdit = GUICtrlCreateEdit("Start...", 10, 10, 380, 580)
GUISetState()

While 1
    _EditWrite("Mutex Exists: " & (_MutexExists($name) = 1) & @CRLF)
    $hMutexGlobal = _MutexOpen($name)
    _EditWrite("Mutex Handle: " & $hMutexGlobal & @CRLF)

    If _ReleaseMutex($hMutexGlobal) = 1 Then
        _EditWrite("Mutex Released!" & @CRLF & "Mutex Exists: " & (_MutexExists($name) = 1) & @CRLF & @CRLF)
    Else
        _EditWrite("Mutex Released: False" & @CRLF)
        _EditWrite("Mutex Exists: " & (_MutexExists($name) = 1) & @CRLF & @CRLF)
    EndIf
    Sleep(1000)
WEnd

Func _MutexOpen($szMutexName)
    Local $tSECURITY_ATTRIBUTES = DllStructCreate("dword Length;" & _
            "ptr SecurityDescriptor;" & _
            "int InheritHandle")

    DllStructSetData($tSECURITY_ATTRIBUTES, "Length", DllStructGetSize($tSECURITY_ATTRIBUTES))
    DllStructSetData($tSECURITY_ATTRIBUTES, "InheritHandle", 1); inherit the handle;<- THIS!!!

    Local $hMutex = DllCall("kernel32.dll", "hwnd", "CreateMutex", _
            "ptr", DllStructGetPtr($tSECURITY_ATTRIBUTES), _
            "int", 1, _
            "str", $szMutexName)

    If @error Or Not $hMutex[0] Then
        Return 0
    EndIf

    Return $hMutex[0]
EndFunc  ;==>_MutexOpen

Func _MutexOpen_($szMutexName)
    Local $hMutex = DllCall("kernel32.dll", "hwnd", "OpenMutex", "int", $MUTEX_ALL_ACCESS, "int", 0, "str", $szMutexName)
    If IsArray($hMutex) And $hMutex[0] Then
        Return $hMutex[0]
    EndIf
    Return 0
EndFunc  ;==>_MutexOpen_

Func _MutexExists($szMutexName)
    Local $hMutex = DllCall("Kernel32.dll", "hwnd", "OpenMutex", "int", 0x1F0001, "int", 1, "str", $szMutexName)
    Local $aGLE = DllCall("Kernel32.dll", "int", "GetLastError")
    If IsArray($hMutex) And $hMutex[0] Then
        DllCall("Kernel32.dll", "int", "CloseHandle", "hwnd", $hMutex[0])
    EndIf
    If IsArray($aGLE) And $aGLE[0] = 127 Then Return 1
    Return 0
EndFunc  ;==>_MutexExists

Func _ReleaseMutex($hMutex)
    Local $aRM = DllCall("kernel32.dll", "int", "ReleaseMutex", "hwnd", $hMutex)
    _EditWrite("!!!!" & _WinAPI_GetLastErrorMessage())
;_EditWrite("!!!!" & $aRM[0] & @CRLF)
    Local $aCH = DllCall("Kernel32.dll", "int", "CloseHandle", "hwnd", $hMutex)
    If (IsArray($aRM) And $aRM[0] > 0) And (IsArray($aCH) And $aCH[0] > 0) Then Return 1
    Return 0
EndFunc  ;==>_ReleaseMutex

Func _EditWrite($sString)
    ControlSetText($hGUI, "", $ctrlEdit, ControlGetText($hGUI, "", $ctrlEdit) & $sString)
EndFunc  ;==>_EditWrite

Func _Escape()
    Sleep(5000)
    Exit
EndFunc  ;==>_Escape

:D

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

So, how is Process Explorer working where you can close the mutex without the the program have to be closed?

If more than one thread is waiting on a mutex, a waiting thread is selected. Do not assume a first-in, first-out (FIFO) order. External events such as kernel-mode APCs can change the wait order.

http://msdn.microsoft.com/en-us/library/ms684266(VS.85).aspx

I guess this refers to NtQueueApcThread.

Link to comment
Share on other sites

So, how is Process Explorer working where you can close the mutex without the the program have to be closed?

http://msdn.microsoft.com/en-us/library/ms684266(VS.85).aspx

I guess this refers to NtQueueApcThread.

Time for my daily stupid question: How did you get to the mutex via Process Explorer? What view do you see SciTE's mutex in?

:D

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

Show Lower Pane, Lower Pane View > Handle and click on Scite and you'll see it.

I think you already know that mutant = mutex but I'll tell it anyways.

Right click on the mutex and close it and you will see that Scite didn't close but the mutex has been closed.

Edited by Pain
Link to comment
Share on other sites

Show Lower Pane, Lower Pane View > Handle and click on Scite and you'll see it.

I think you already know that mutant = mutex but I'll tell it anyways.

Right click on the mutex and close it and you will see that Scite didn't close but the mutex has been closed.

Sho'nuf! I ran my version of the demo above and closing the handle to the mutex in Process Explorer is clearly visible to the script, while SciTE is still running.

Thanks for the tip.

:D

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

So the question still remains, how is it done?

No clue here. But those tools come from Mark Russinovich, which means much deeper JuJu is available if required. I don't know it's the case, but the API used may not be documented for us mere mortals.

:D

Edit: After consulting with the deep JuJu (herewasplato and Valik) I eventually got from here: Close Mutex of another process

To here: 5. Need a CloseHandleEx? (Remote Handle Closing) (last post by "Matts_User_Name", numbered item 5. in his list).

What you are doing is duplicating the handle with a flag set to close the original ( $DUPLICATE_CLOSE_SOURCE = 0x1 ). Then you close your duplicate. So you call DuplicateHandle() with $DUPLICATE_CLOSE_SOURCE, and then call CloseHandle() on your returned duplicate handle.

Hope that helps! It was at least educational for me.

:D

Edited by PsaltyDS
Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
Share on other sites

  • 10 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...