Jump to content

_Singleton question


Recommended Posts

Hello all,

I am using the _Singleton UDF in my programs and usually works well. However last night I found a problem related to _Singleton in one of my scripts which made me to make some tests so as to realize exactly how the function works.

Have a look at this piece of code please:

#include <Misc.au3>

$app = "MyProg"
$title = "Title"

If _Singleton($app, 1) = 0 Then
    CError(_Singleton($app, 1) & @LF & @LF & "Already running.")
Else
    CError(_Singleton($app, 1) & @LF & @LF & "End of script.")
EndIf

Func CError($msg)
    MsgBox(16, $title, $msg)
    Exit
EndFunc

Notice that even if you run the program once, the number on the message box is zero (meaning _Singleton($app, 1) = 0). Since = 0 means "already running" why the return of _Singleton is always zero? And since in that script the "Else" part is executed successfully, why the report number on that msgbox remains zero and not something else?

Please explain because I have a script where _Singleton behaves abnormally.

Thank you.

Link to comment
Share on other sites

There is a rather cryptic remark in the the help file entry for _Singleton():

Remarks

If an occurrence is already found the script is exited.

The second call to the function in the same running script will fail.

You are making a second and third call to the function in the same script... and it's failing?

Seems odd, but that is an odd remark.

:)

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

More information: Here is Valik's _Singleton() UDF from Misc.au3:

; ------------------------------------------------------------------------------
;
; AutoIt Version: 3.1.1++
; Language:       English
; Description:    Functions that assist with Common Dialogs.
;
; ------------------------------------------------------------------------------

; <snip>

;===============================================================================
;
; Description:    _Singleton
; Parameter(s): $occurenceName
;               $flag
; User CallTip:   _Singleton($occurenceName [,$flag = 0]) Check if no other occurence is running. (required: <Misc.au3>)
; Return Value(s):  if $flag = 1
; Author(s):      Valik
;
;===============================================================================
Func _Singleton($occurenceName, $flag = 0)
    Local $ERROR_ALREADY_EXISTS = 183
    $occurenceName = StringReplace($occurenceName, "\", "") ; to avoid error
    ;    Local $handle = DllCall("kernel32.dll", "int", "CreateSemaphore", "int", 0, "long", 1, "long", 1, "str", $occurenceName)
    Local $handle = DllCall("kernel32.dll", "int", "CreateMutex", "int", 0, "long", 1, "str", $occurenceName)
    Local $lastError = DllCall("kernel32.dll", "int", "GetLastError")
    If $lastError[0] = $ERROR_ALREADY_EXISTS Then
        If $flag = 0 Then
            Exit -1
        Else
            SetError($lastError[0])
            Return 0
        EndIf
    EndIf
    Return $handle[0]
EndFunc   ;==>_Singleton

He test for the process by creating a process (or at least a Mutex which appears to be equivilent) with the same name - "CreateMutex". After returning results that mutex/process seems to be abandoned, meaning it will still be there and throw off the results if you run it again. Seems like there ought to be code in there to get rid of the just-created object once it's not required, but if you think about it, it's not a big deal.

It's only meant to be run once, so only one extra object should be created. Since it is a child process of the running script, it should die when the script exits, I guess.

Seems like the UDF could clean up after itself with a "ReleaseMutex" call using the handle of the one just created. But smarter people may know why it doesn't work that way.

:)

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

Maybe Valik can enlight us on this. I have no clue.

Thank you very much for this tip. I had miss the part on the helpfile where it says that "The second call to the function in the same running script will fail.". Apparently this seems to be my problem.

However, I can understand the initial purpose of the _Singleton function, however it is not standard that one would like to call it only once in his script. And I will explain you why. In my script I give the user the option to make a setting so as different script's parts to be allowed to execute while another instance of the script is already running. Let's say:

piece of code here...

If $MultiCheck = "3" And _Singleton($app, 1) = 0 Then CError("Please close all previous instances of " & $app & " first."); disallow multiple instances completely

more code here...

If $MultiCheck = "2" And _Singleton($app, 1) = 0 Then CError("Please close all previous instances of " & $app & " first."); allow preview of the GUI only

more code here...

If $MultiCheck = "1" And _Singleton($app, 1) = 0 Then CError("Please close all previous instances of " & $app & " first."); allow preview of the GUI + button press but nothing more

more code here...

The code is almost 500 lines and I wouldn't like to publish it, but you got the point. However the _Singleton command does not always work the way I want. So, if Valik consider this as a bug, or a new feature to add to this function he can let us know (maybe we both are wrong, I don't know).

To be honest, I suspected something like that and added Sleep() pauses before calling _Singleton to do if this would do the trick. But it didn't...

Or else I don't know, maybe I should check in a different manner for multiple instances to do what I want.

So far,

Edited by erebus
Link to comment
Share on other sites

However the _Singleton command does not always work the way I want.

So code a function that does, or a wrapper around _Singleton().

I don't see anything that isn't straightforward that would be required for you to get what you want (though I admit I skipped over quite a bit of verbage :) )

Reading the help file before you post... Not only will it make you look smarter, it will make you smarter.

Link to comment
Share on other sites

@flyingboz: If I knew the way to do something better than this, trust me I would have done it already. Please do not just use irony if you don't have something useful to add on the issue. I am not a kiddy to just tell me "use it if you like it or write up your own". I have a problem with a function and I propose a new idea to expand its functionality. If Valik (or anybody else) likes that and finds it can do something (if he also thinks that there is a good reason to do so), that's fine, I would be glad and thankful. If not, it's ok too, I will find another workaround and would be all happy again. So what is the problem now? Why is this forum made for if not for discussing problems and new ideas?

@MHZ: I didn't exactly understand this... If I translate correctly, yes the check is done in the new instance but since it is the same script, the code is the same. The problem is that I cannot reproduce this in a small script - because then it works fine. So I need a verification on this - was _Singleton() made in the first place to be called multiple times in a script? Is there any chance (even theoritically) for the function to fail if used in that way? The only reason I am thinking of this is because of what PsaltyDS said about the "ReleaseMutex" thing. I am sorry, I do not have the knowledge to examine the _Singleton() function and analyze step-by-step what it does to understand if something is going wrong. That's why I am asking here...

Thank you all so far,

Edited by erebus
Link to comment
Share on other sites

Script a.au3

#include <Misc.au3>

$app = "MyProg"
$title = "Title"

If _Singleton($app, 1) = 0 Then
    CError(_Singleton($app, 1) & @LF & @LF & "Already running.")
EndIf

Sleep(10000)

Func CError($msg)
    MsgBox(16, $title, $msg)
    Exit
EndFuncoÝ÷ ÚØ^»§m«·jëh×6#include <Misc.au3>

$app = "MyProg"
$title = "Title"

If _Singleton($app, 1) = 0 Then
    CError(_Singleton($app, 1) & @LF & @LF & "Already running.")
EndIf

Func CError($msg)
    MsgBox(16, $title, $msg)
    Exit
EndFunc

then tell me singleton is not working... if it was not, then you would see same from both scripts.

Link to comment
Share on other sites

Yes it works as expected. That is why I said 'sometimes' in a previous post. Anyway, I have sent you a PM with the code to see for yourself if you want to examine it a little further.

Thank you all very much for your help.

Link to comment
Share on other sites

Seems like the UDF could clean up after itself with a "ReleaseMutex" call using the handle of the one just created. But smarter people may know why it doesn't work that way.

The Mutex created by a process must be cleaned up by Windows when an application closes because if you end end a script which uses _singleton with Ctrl Alt Del the script will run again.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

  • 6 years later...

sorry for bumping an old topic, but this had a lot of very useful, relevant information, and I thought it would be a good idea to keep all this info in one thread for anyone looking for it later

Is there a way to clear a singleton after it's made? In my script, I'm useing ProgressOn boxes to show a file copying. Since the window remains inactive for most of the copy, moving it is award. I was using singletons to check if there are any other progress windows and offset the new window when created

Func ProgressCopy($src, $dst, $copygap = 2)
    Local $OptEnv, $OptVar, $size, $in, $out
    Local $progress = 0, $count = 0, $chunk = 524288, $timer = TimerInit(), $size = FileGetSize($src)
    ConsoleWrite("Copy  "&$src&@CRLF&"To    "&$dst&@CRLF)

    $OptEnv = Opt("ExpandEnvStrings", 0)
    $OptVar = Opt("ExpandVarStrings", 0)

    for $y = 0 to 9
        If _Singleton("Progress-"&$y, 1) <> 0 Then ExitLoop
    Next

    ProgressOn("File Copy Progress", "Copying " & $src & " ...", "0 of " & Round($size / 1024 / 1024, 2) & " MB copied. (0%)", 0, 100*$y, 18)

    ; Open input and output files (exit if error)
    $in = FileOpen($src, 0)
    If @error <> 0 Then Return 0
    $out = FileOpen($dst, 10)
    If @error <> 0 Then
        FileClose($in)
        Return 0
    EndIf

    ; Start reading input
    $bin = FileRead($in, $chunk)
    While @error = 0
        ; Write chunk of data, keep trying for up to 10 seconds if failed
        Do
            FileWrite($out, $bin)
        Until (@error = 0) Or (TimerDiff($timer) > 10000)
        If @error <> 0 Then
            FileClose($in)
            FileClose($out)
            Return 0
        EndIf

        $count = $count + $chunk
        If TimerDiff($timer) > 150 Then
            $progress = Int(($count / $size) * 100)
            ProgressSet($progress, Round($count / 1024 / 1024, 2) & " of " & Round($size / 1024 / 1024, 2) & " MB copied. (" & $progress & "%)")
            $timer = TimerInit()
        EndIf
        Sleep($copygap)

        $bin = FileRead($in, $chunk)
    WEnd

    ProgressSet(100, $size & " of " & $size & " bytes copied. (100%)")

    FileClose($in)
    FileClose($out)
    Sleep(100)
    ProgressOff()

    Opt("ExpandEnvStrings", $OptEnv)
    Opt("ExpandVarStrings", $OptVar)

    ; Return success
    Return 1
EndFunc   ;==>ProgressCopy

(From someone on the forum, don;t remember whom. Credit goes to him and/or her)

I added the singleton bit and the offset, so if it is called by more than one program, the windows won't overlap. The problem is if the same program calls it twice, the second progress window will be moved down because the singleton exists form the first one

If I could remove a singleton after the copy completes, It would always position the windows correctly. Anyone know how?

Edited by corgano

0x616e2069646561206973206c696b652061206d616e20776974686f7574206120626f64792c20746f206669676874206f6e6520697320746f206e657665722077696e2e2e2e2e

Link to comment
Share on other sites

  • 6 months later...

Isn't it simpler to go around and use the builtin AutoIT functions?

To check if our program (whatever the name is) is already running (the way I do it, of course):

; Check if this program is already running. If so then exit.
$p = ProcessList(StringReplace(@ScriptName,".au3",".exe"))
If $p[0][0] > 1 Then
    MsgBox(0,"Error", @ScriptName & " is already running! Exiting...", 3)
    Exit
EndIf
Link to comment
Share on other sites

Abilio_KID,

Don't necro old posts. Create a new support thread in the future please.

UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Link to comment
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
 Share

  • Recently Browsing   0 members

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