Jump to content

Recommended Posts

Posted

I think they are all different means of accessing shared memory... and that there's something underlying principle that prevents my un-compiled 32bit scripts, on a x64 OS, run through SciTE to access this shared memory space. No need to change to WinExist or something, as the compiled code works fine. Just testing on the fly won't work, only  hard-coded through msgbox or similar debugging means.

Posted (edited)
4 hours ago, KaFu said:

I think they are all different means of accessing shared memory... and that there's something underlying principle that .......

Local $hSemaphore = _SingletonSemaphore
If _SingletonSemaphore("TestSemaphore", 2) = 0 Then
    MsgBox(16, "Warning - " & @ScriptName, "An occurrence of test is already running", 30)
    Exit
EndIf
MsgBox(64, "OK - " & @ScriptName, "The first occurrence of test is running", 30)
DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hSemaphore)

Func _SingletonSemaphore($sOccurrenceName, $iFlag = 0)
    Local Const $ERROR_ALREADY_EXISTS = 183
    Local Const $SECURITY_DESCRIPTOR_REVISION = 1
    Local $tSecurityAttributes = 0
    Local $tagSECURITY_ATTRIBUTES = "dword Length;ptr Descriptor;bool InheritHandle"

    If BitAND($iFlag, 2) Then
        ConsoleWrite('If BitAND($iFlag, 2) Then = ' & BitAND($iFlag, 2) & @CRLF)
        ; 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 $aCall = DllCall("advapi32.dll", "bool", "InitializeSecurityDescriptor", _
                "struct*", $tSecurityDescriptor, "dword", $SECURITY_DESCRIPTOR_REVISION)
        If @error Then Return SetError(@error, @extended, 0)
        If $aCall[0] Then
            ; Add the NULL DACL specifying access to everybody.
            $aCall = DllCall("advapi32.dll", "bool", "SetSecurityDescriptorDacl", _
                    "struct*", $tSecurityDescriptor, "bool", 1, "ptr", 0, "bool", 0)
            If @error Then Return SetError(@error, @extended, 0)
            If $aCall[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

    $hStartEvent = DllCall('kernel32.dll', 'handle', 'CreateSemaphoreW', 'struct*', $tSecurityAttributes, 'long', 0, 'long', 1, 'wstr', $sOccurrenceName)
    If @error Then Return SetError(@error, @extended, 0)
    Local $hError = DllCall("kernel32.dll", "dword", "GetLastError")
    If $hError[0] = $ERROR_ALREADY_EXISTS Then
        DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hStartEvent[0])
        If @error Then Return SetError(@error, @extended, 0)
        If BitAND($iFlag, 1) Then
            Return SetError($hError[0], $hError[0], 0)
        Else
            Return 0 ; meh
            Exit -1
        EndIf
    EndIf
    Return $hStartEvent[0]
EndFunc   ;==>_SingletonSemaphore

give it a try.

Parameters
[in, optional] lpSemaphoreAttributes
A pointer to a SECURITY_ATTRIBUTES structure. If this parameter is NULL, the handle cannot be inherited by child processes.

( https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createsemaphorew )

 

Edited by argumentum
better ?

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted (edited)

Wow, now it's getting really wild 🙄. After reading this post by @therks (which I didn't see that time, kudos!), I gave it a try.

Now if I don't call the dlls directly, but open the kernel32.dll frist via dllopen, then it works for my uncompiled 32bit scripts too :blink:.

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Compile_Both=y
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****


Local $hSemaphore = _SingletonSemaphore_Org("TestSemaphore", 1)
If $hSemaphore = 0 Then
    MsgBox(16, "Warning - _SingletonSemaphore_Org - Does not work for me from an uncompiled 32bit script", "An occurrence of test is already running", 30)
    Exit
Else
    MsgBox(64, "OK - _SingletonSemaphore_Org - Does not work for me from an uncompiled 32bit script", "The first occurrence of test is running", 30)
    DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hSemaphore)
EndIf

Func _SingletonSemaphore_Org($sOccurrenceName, $iFlag = 0)
    Local Const $ERROR_ALREADY_EXISTS = 183



    $hStartEvent = DllCall("kernel32.dll", 'handle', 'CreateSemaphoreW', 'struct*', 0, 'long', 0, 'long', 1, 'wstr', $sOccurrenceName)
    If @error Then Return SetError(@error, @extended, 0)
    Local $hError = DllCall("kernel32.dll", "dword", "GetLastError")
    If $hError[0] = $ERROR_ALREADY_EXISTS Then
        DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hStartEvent[0])
        If @error Then Return SetError(@error, @extended, 0)
        If BitAND($iFlag, 1) Then
            Return SetError($hError[0], $hError[0], 0)
        Else
            Return 0 ; meh
            Exit -1
        EndIf
    EndIf
    Return $hStartEvent[0]
EndFunc





Global $hDLL_Kernel32 = DllOpen("kernel32.dll")

Local $hSemaphore = _SingletonSemaphore_DllOpen("TestSemaphore", 1)
If $hSemaphore = 0 Then
    MsgBox(16, "Warning - _SingletonSemaphore_DllOpen - Works for me from an uncompiled 32bit script too", "An occurrence of test is already running", 30)
    Exit
Else
    MsgBox(64, "OK - _SingletonSemaphore_DllOpen - Works for me from an uncompiled 32bit script too", "The first occurrence of test is running", 30)
    DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hSemaphore)
endif

Func _SingletonSemaphore_DllOpen($sOccurrenceName, $iFlag = 0)
    Local Const $ERROR_ALREADY_EXISTS = 183

    ; Local $hDLL_Kernel32 = DllOpen("kernel32.dll")

    $hStartEvent = DllCall($hDLL_Kernel32, 'handle', 'CreateSemaphoreW', 'struct*', 0, 'long', 0, 'long', 1, 'wstr', $sOccurrenceName)
    If @error Then Return SetError(@error, @extended, 0)
    Local $hError = DllCall($hDLL_Kernel32, "dword", "GetLastError")
    If $hError[0] = $ERROR_ALREADY_EXISTS Then
        DllCall($hDLL_Kernel32, "bool", "CloseHandle", "handle", $hStartEvent[0])
        If @error Then Return SetError(@error, @extended, 0)
        If BitAND($iFlag, 1) Then
            Return SetError($hError[0], $hError[0], 0)
        Else
            Return 0 ; meh
            Exit -1
        EndIf
    EndIf
    Return $hStartEvent[0]
EndFunc   ;==>_SingletonSemaphore

 

Edit: Same result for CreateFileMappingW. Using a handle from dllopen it works for uncompiled 32bit scripts, using a direct dllcall to kernel32.dll it does not work.

Edited by KaFu
Posted
1 hour ago, KaFu said:

Edit: Same result for CreateFileMappingW.

Then CreateSemaphoreW works well with global DllOpen() ?, only CreateFileMappingW fails ?
To me this is important because I can not know an edge case ( like yours ) where a "single-on" will fail. Also, have you tried with older AutoIt3 versions ? ( just in case it needs "higher up" attention )

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted

No, all uncompiled 32bits scripts using CreateFileMappingW, CreateSemaphoreW and also CreateMutexW fail when called like

Local $aHandle = DllCall("kernel32.dll", "handle", "CreateMutexW", "struct*", $tSecurityAttributes, "bool", 1, "wstr", $sOccurrenceName)

but work when called with a either a global or local variable for kernel32.dll like 
 

Local $h_DLL_Kernel32 = DllOpen("kernel32.dll")

Local $aHandle = DllCall($h_DLL_Kernel32, "handle", "CreateMutexW", "struct*", $tSecurityAttributes, "bool", 1, "wstr", $sOccurrenceName)
Posted

...yes it is @Nine. Hence, either AutoIt3, on a direct call internally opens the  DLL and keeps it ( that would be a bad move ) or, we change all UDFs to implement a global DllOpen ala GDI UDFs ?. It would be more efficient anyway at the price of loading more than needed.
No clue, just an idea.

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted

It's hard to tell the reason without knowing the internal workings of DllOpen() vs DllCall() with and without a handle.

Also that it's only related to uncompiled 32bit scripts makes it even more hard to explain. 

And that it seems not a common problem, but only few people seem to experience (or realize) it or seem to be able to reproduce it. 

It seems to be related to a certain system setup only, though I think at least @UEZ, @@therks and myself stumbled over it now.

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
  • Recently Browsing   0 members

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