Jump to content

Recommended Posts

Posted (edited)

Here another approach to check if a script was already started using atoms and semaphores.

 

Atom:

#include <MsgBoxConstants.au3>

Global $iSingleton = Singleton()
If Not $iSingleton Then
    Exit MsgBox($MB_TOPMOST, "Singleton Test", "Process is already running!")
EndIf
MsgBox($MB_TOPMOST, "Singleton Test", "Singleton atom initialized: " & $iSingleton)
Singleton_Delete($iSingleton)


; #FUNCTION# ====================================================================================================================
; Name ..........: Singleton
; Description ...: Checks if the script has been started already.
; Syntax ........: Singleton([$sOccurrenceName = @ScriptFullPath])
; Parameters ....: $sOccurrenceName     - [optional] a string value. Default is @ScriptFullPath.
; Return values .: If the function succeeds, the return value is the newly created atom or 0 else error is set and false is returned.
; Author ........:  UEZ
; Modified ......:
; Remarks .......: If Singleton finds the atom it will return 0 and the atom token will be set to extended macro. It can be used to get the atom string using _WinAPI_AtomGlobalGetName.
; Related .......:
; Link ..........: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalfindatomw
;                     https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globaladdatomw
; Example .......: No
; ===============================================================================================================================
Func Singleton($sOccurrenceName = @ScriptFullPath)
    Local $iFind = _WinAPI_AtomGlobalFind($sOccurrenceName)
    If @error Then Return SetError(1, 0, False)
    If $iFind Then Return SetExtended($iFind, 0)
    Local $iAtom = _WinAPI_AtomGlobalAdd($sOccurrenceName)
    If @error Then Return SetError(2, 0, False)
    Return $iAtom
EndFunc   ;==>Singleton

; #FUNCTION# ====================================================================================================================
; Name ..........: Singleton_Delete
; Description ...: Deletes the atom generated by the first started script.
; Syntax ........: Singleton_Delete($iAtom)
; Parameters ....: $iAtom               - an integer value which was generated by Singleton
; Return values .: True if successful else false.
; Author ........: UEZ
; Modified ......:
; Remarks .......: Don't forget to call Singleton_Delete before first started script ends.
; Related .......:
; Link ..........: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globaldeleteatom
; Example .......: No
; ===============================================================================================================================
Func Singleton_Delete($iAtom)
    _WinAPI_AtomGlobalDelete($iAtom)
    If @error Then Return SetError(1, 0, False)
    Return True
EndFunc   ;==>Singleton_Delete

;internal functions
Func _WinAPI_AtomGlobalFind($sAtomString)
    Local $aReturn = DllCall("kernel32.dll", "short", "GlobalFindAtomW", "wstr", $sAtomString)
    If @error Then Return SetError(1, 0, -1)
    Return $aReturn[0]
EndFunc   ;==>_WinAPI_AtomGlobalFind

Func _WinAPI_AtomGlobalAdd($sAtomString)
    Local $aReturn = DllCall("kernel32.dll", "short", "GlobalAddAtomW", "wstr", $sAtomString)
    If @error Then Return SetError(1, 0, -1)
    Return $aReturn[0]
EndFunc   ;==>_WinAPI_AtomGlobalAdd

Func _WinAPI_AtomGlobalDelete($nAtom)
    Local $aReturn = DllCall("kernel32.dll", "short", "GlobalDeleteAtom", "short", $nAtom)
    If @error Then Return SetError(1, 0, -1)
    Return $aReturn[0] = 0
EndFunc   ;==>_WinAPI_AtomGlobalDelete

Func _WinAPI_AtomGlobalGetName($nAtom, $iBufferSize = 512)
    Local $tBufferAtom = DllStructCreate("wchar name[" & $iBufferSize & "]")
    Local $aReturn = DllCall("kernel32.dll", "uint", "GlobalGetAtomNameW", "short", $nAtom, "struct*", $tBufferAtom, "int", $iBufferSize)
    If @error Or Not $aReturn[0] Then Return SetError(1, 0, -1)
    Return $tBufferAtom.name
EndFunc   ;==>_WinAPI_AtomGlobalGetName

 

Semaphore:

#include <MsgBoxConstants.au3>
#include <WinAPIError.au3>

Global $iSingleton = Singleton("&]8h/x87</htFV4-K*&.b.w~")
If Not $iSingleton Then
    Exit MsgBox($MB_TOPMOST, "Singleton Test", "Process is already running!")
EndIf
MsgBox($MB_TOPMOST, "Singleton Test", "Singleton Semaphore initialized: " & $iSingleton)



; #FUNCTION# ====================================================================================================================
; Name ..........: Singleton
; Description ...: Checks if the script has been started already.
; Syntax ........: Singleton($sOccurrenceName)
; Parameters ....: $sOccurrenceName     - a string value which will be used to create the semaphore handle.
; Return values .: True if Singleton started the first time. False if script was already started
; Author ........: UEZ
; Modified ......:
; Remarks .......: The system closes the handle automatically when the process terminates. The semaphore object is destroyed when its last handle has been closed.
; Related .......:
; Link ..........: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsemaphorea
; Example .......: No
; ===============================================================================================================================
Func Singleton($sOccurrenceName)
    If StringLen($sOccurrenceName) > 260 Then $sOccurrenceName = StringLeft($sOccurrenceName, 260)
    Local $aReturn = DllCall("kernel32.dll", "handle", "CreateSemaphoreA", "ptr", Null, "long", 0, "long", 1, "str", $sOccurrenceName)
    If @error Or Not $aReturn[0] Then Return SetError(1, 0, -1)
    Return SetExtended($aReturn[0], $aReturn[0] And _WinAPI_GetLastErrorMessage()  = "The operation completed successfully.")
EndFunc   ;==>Singleton

 

Just start the script twice to see if it works.

The disadvantage of using atoms is that atoms have a memory that means when your app is crashing or you forgot to delete the atom then the atom does still have the $sOccurrenceName saved and thus Singleton will not work if you use the same same value for $sOccurrenceName.

With semaphore you don't have this issue.

 

Thanks to jj2007 and SARG.

Edited by UEZ
Update

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted
39 minutes ago, argumentum said:

hmmm, let's say that I did not call the "Singleton_Delete($iSingleton)" and wanted to run the script again, how do I clear a previous $iSingleton ?

You can use 

Global $iSingleton = Singleton()
Singleton_Delete(@extended)

to delete the atom.

But you cannot use this in you main script because how do you know if it was called the 1st time?

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted

I always use this:

 

Global $sAppName = 'My App'

_RunOnce($sAppName, _OnSecondRun)
MsgBox(64, @ScriptName, 'Run me again')

;Main code...

Func _OnSecondRun()
    MsgBox(48, @ScriptName, 'Second copy detected, exiting...', 3)
    Exit
EndFunc

Func _RunOnce($sAppName = '', $sCallback = '')
    Local $iOld_WTMM = Opt('WinTitleMatchMode', 3)
    Local $sTitle = @ScriptName & '_@#$%^&*_' & $sAppName
    
    If WinExists('[CLASS:AutoIt v3;TITLE:' & $sTitle & ']') Then
        If Not $sCallback Then
            Exit
        EndIf
        
        Call(FuncName($sCallback))
    EndIf
    
    AutoItWinSetTitle($sTitle)
    Opt('WinTitleMatchMode', $iOld_WTMM)
EndFunc

You can use it even as UDF, without do anything...

RunOnce.au3:

#include-once
#OnAutoItStartRegister '__RunOnce'

Func __RunOnce()
    Local $iOld_WTMM = Opt('WinTitleMatchMode', 3)
    Local $sTitle = @ScriptName & '_@#$%^&*_' & @ScriptName
    
    If WinExists('[CLASS:AutoIt v3;TITLE:' & $sTitle & ']') Then
        MsgBox(48, @ScriptName, 'Second copy detected, exiting...', 3)
        Exit
    EndIf
    
    AutoItWinSetTitle($sTitle)
    Opt('WinTitleMatchMode', $iOld_WTMM)
EndFunc

Just add #include <RunOnce.au3> to your script.

 

Spoiler

Using OS: Win 7 Professional, Using AutoIt Ver(s): 3.3.6.1 / 3.3.8.1

AutoIt_Rus_Community.png AutoIt Russian Community

My Work...

Spoiler

AutoIt_Icon_small.pngProjects: ATT - Application Translate Tool {new}| BlockIt - Block files & folders {new}| SIP - Selected Image Preview {new}| SISCABMAN - SciTE Abbreviations Manager {new}| AutoIt Path Switcher | AutoIt Menu for Opera! | YouTube Download Center! | Desktop Icons Restorator | Math Tasks | KeyBoard & Mouse Cleaner | CaptureIt - Capture Images Utility | CheckFileSize Program

AutoIt_Icon_small.pngUDFs: OnAutoItErrorRegister - Handle AutoIt critical errors {new}| AutoIt Syntax Highlight {new}| Opera Library! | Winamp Library | GetFolderToMenu | Custom_InputBox()! | _FileRun UDF | _CheckInput() UDF | _GUIInputSetOnlyNumbers() UDF | _FileGetValidName() UDF | _GUICtrlCreateRadioCBox UDF | _GuiCreateGrid() | _PathSplitByRegExp() | _GUICtrlListView_MoveItems - UDF | GUICtrlSetOnHover_UDF! | _ControlTab UDF! | _MouseSetOnEvent() UDF! | _ProcessListEx - UDF | GUICtrl_SetResizing - UDF! | Mod. for _IniString UDFs | _StringStripChars UDF | _ColorIsDarkShade UDF | _ColorConvertValue UDF | _GUICtrlTab_CoverBackground | CUI_App_UDF | _IncludeScripts UDF | _AutoIt3ExecuteCode | _DragList UDF | Mod. for _ListView_Progress | _ListView_SysLink | _GenerateRandomNumbers | _BlockInputEx | _IsPressedEx | OnAutoItExit Handler | _GUICtrlCreateTFLabel UDF | WinControlSetEvent UDF | Mod. for _DirGetSizeEx UDF
 
AutoIt_Icon_small.pngExamples: 
ScreenSaver Demo - Matrix included | Gui Drag Without pause the script | _WinAttach()! | Turn Off/On Monitor | ComboBox Handler Example | Mod. for "Thinking Box" | Cool "About" Box | TasksBar Imitation Demo

Like the Projects/UDFs/Examples? Please rate the topic (up-right corner of the post header: Rating AutoIt_Rating.gif)

* === My topics === *

==================================================
My_Userbar.gif
==================================================

 

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

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
×
×
  • Create New...