Jump to content
Sign in to follow this  
Pain

Problem with Mutex

Recommended Posts

Pain

#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

Share this post


Link to post
Share on other sites
PsaltyDS

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

Share this post


Link to post
Share on other sites
trancexx

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

Share this post


Link to post
Share on other sites
PsaltyDS

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

Share this post


Link to post
Share on other sites
Pain

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.

Share this post


Link to post
Share on other sites
PsaltyDS

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

Share this post


Link to post
Share on other sites
Pain

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

Share this post


Link to post
Share on other sites
PsaltyDS

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

Share this post


Link to post
Share on other sites
Pain

So the question still remains, how is it done?

Share this post


Link to post
Share on other sites
PsaltyDS

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

Share this post


Link to post
Share on other sites
simon387

@ #10:

I need it :idea:

Share this post


Link to post
Share on other sites

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
Sign in to follow this  

×