Jump to content

Recommended Posts

Posted

I have used _Singleton function in my script to restrict only one instance to run.

For testing, I have written below code, and triggered multiple instances.

#include <Misc.au3>
MsgBox(0,"",@ScriptName)
if _Singleton(@ScriptName, 1) = 0 Then
    Msgbox(64, @ScriptName, "The program is already running.")
    Exit
Else
    MsgBox(0,@ScriptName,"No other instances running")
EndIf

But all are going to else block.

 

Please suggest.

Posted
#include <Misc.au3>
MsgBox(0,"",@ScriptName)
if _Singleton(@ScriptName, 1) = 0 Then
    Msgbox(64, @ScriptName, "The program is already running.")
    Exit
Else
    MsgBox(0,@ScriptName,"No other instances running")
EndIf

Is this your complete script? It ends after clicking the message box.

 

Put

While 1
Wend

at the end of your script to keep it running-

Rule #1: Always do a backup         Rule #2: Always do a backup (backup of rule #1)

Posted

You can also try using the full path of your script for singleton as the identifier, here is an example from one of my projects:

Handle_MultipleInstance()

Func Handle_MultipleInstance()
    If _Singleton(StringReplace(@ScriptFullPath, '\', '/'), 1) = 0 Then
        Local $iMsgBoxParams = $MB_ICONWARNING + $MB_YESNO + $MB_DEFBUTTON2
        Local $sMsgBoxMsg = "ProxAllium seems to be already running, do you still want to create a new instance?"
        Local $iUserChoice = MsgBox($iMsgBoxParams, "ProxAllium is already running!", $sMsgBoxMsg)
        If $iUserChoice = $IDYES Then Return
        Exit
    EndIf
EndFunc

Feel free to adapt it as you wish :)

EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time)

DcodingTheWeb Forum - Follow for updates and Join for discussion

Posted

Thanks @KaFu and @ajag

 

It is the script used for testing singleton.

If I run the script and hold it without clicking ok for message box and run another instance again, it is still going to else section only.

Posted
4 minutes ago, TheDcoder said:

You can also try using the full path of your script for singleton as the identifier, here is an example from one of my projects:

Handle_MultipleInstance()

Func Handle_MultipleInstance()
    If _Singleton(StringReplace(@ScriptFullPath, '\', '/'), 1) = 0 Then
        Local $iMsgBoxParams = $MB_ICONWARNING + $MB_YESNO + $MB_DEFBUTTON2
        Local $sMsgBoxMsg = "ProxAllium seems to be already running, do you still want to create a new instance?"
        Local $iUserChoice = MsgBox($iMsgBoxParams, "ProxAllium is already running!", $sMsgBoxMsg)
        If $iUserChoice = $IDYES Then Return
        Exit
    EndIf
EndFunc

Feel free to adapt it as you wish :)

Thank you .. it is working for my requirement.

Posted

And also if I replace @ScriptFullPath with some random name (test), it is working.

 

While(_Singleton("test", 1) = 0)
    Sleep(5000)
    MsgBox(0,"","Another instance of MainScript is running..so waiting in the background to complete")
WEnd

 

Posted

@ur Good to see that it is working, I use @ScriptFullPath because it is kind of good and unique identifier, though you should be aware that you can run multiple instances of the same script but a different copy of it in a different location if you use my method. The string parameter is totally arbitrary and you can have it as anything you want. :)

EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time)

DcodingTheWeb Forum - Follow for updates and Join for discussion

Posted (edited)

That string needs to be unique per script though.

Here is another way to use the _Singleton command.

$status = _Singleton("unique-name-here", 1)
If $status = 0 Then
    ; Attempt to retore and activate a non-active or minimized window.
    If @Compiled = 1 Then
        $pid = ProcessExists(@ScriptName)
        $exe = @ScriptName
    Else
        $pid = ProcessExists("AutoIt3.exe")
        $exe = "AutoIt3.exe"
    EndIf
    $script = @AutoItPID
    If $script <> $pid Then
        $wins = WinList($Scriptname, "")
        For $w = 1 to $wins[0][0]
            $handle = $wins[$w][1]
            If WinGetProcess($handle, "") = $pid Then
                WinSetState($handle, "", @SW_RESTORE)
                WinActivate($handle, "")
                ExitLoop
            EndIf
        Next
        Exit
    EndIf
EndIf

or

$exist = _Singleton("use-unique-name", 1)
If $exist = 0 Then
     If @Compiled = 1 Then
         $pid = ProcessExists(@ScriptName)
         $exe = @ScriptName
     Else
         $pid = ProcessExists("AutoIt3.exe")
         $exe = "AutoIt3.exe"
     EndIf
     $script = @AutoItPID
     $ans = MsgBox(262177, "Close Running Instance Query", _
         "This program is already running." & @LF & @LF & _
         "Do you want to close it for this new instance?" & @LF & @LF & _
         "NOTE - If all work has been saved, then OK" & @LF & _
         "could be clicked, else click CANCEL." & @LF & @LF & _
         $pid & " (" & $exe & ") " & $script & @LF & @LF & _
         "(will default to CANCEL in 30 seconds)", 30)
     If $ans = 1 Then
         If $pid <> $script Then
             ProcessClose($pid)
         Else
             MsgBox(262192, "Close Error", "OK process failed!", 0)
             Exit
         EndIf
     ElseIf $ans = 2 Or $ans = -1 Then
         Exit
     EndIf
EndIf

Extracted from a couple of my programs, with slight modification.

Edited by TheSaint

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

Posted
8 minutes ago, TheSaint said:

That string needs to be unique per script though.

It doesn't have to be, you can also choose to deliberately generate a string according to whatever set of rules you want for you want. A good example is my code which uses the full path of the script, it is designed to be totally portable and conflict free from other instances of the program excluding the it's own executable ;)

EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time)

DcodingTheWeb Forum - Follow for updates and Join for discussion

Posted (edited)
31 minutes ago, TheDcoder said:

It doesn't have to be, you can also choose to deliberately generate a string according to whatever set of rules you want for you want.

Not correct. _Singleton is using that value as the query marker.

If two programs have the exact same string, then _Singleton will see them as the same.

P.S. On further reading your reply, it appears you contradicted yourself, because yes you can do the latter of what you said, but the former negation does not apply for a string. I said nothing about a variable or generated string ... I was keeping it simple.

Edited by TheSaint

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

Posted (edited)
41 minutes ago, TheDcoder said:

The string parameter is totally arbitrary and you can have it as anything you want.

I was also replying to that, which is incorrect or incomplete. It should be the following.

Quote

The string parameter is totally arbitrary and you can have it as anything you want, so long as it is unique per script.

How you make it unique, is up to you.

You can do a fancy generated string or you can do something quick like I normally do, which is to use name parts of the program name, separated by dashes, plus a dash and my name on the end. That for me, should ensure no-one else will come up with the same name.

i.e. _Singleton("azw-plugin-thsaint", 1)

Edited by TheSaint

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

Posted

@TheSaint I don't see why it is incorrect. For programs which can handle multiple copies (separate instances running in different locations/folders), it is useful to limit to only that particular executable file, if the program had a single constant string for singleton that would obviously not work.

Take my program ProxAllium for example, you can have 2 copies of it and have them run simultaneously, but it will warn you if you try to start another instance of the same copy.

So it is would be wrong to strictly say "the string for singleton must be unique for the script", your script should be able to supply unique strings according to the conflict conditions. (like the path of the script in ProxAllium's case)

Of course you could still go the easy way and just use a hardcoded string, but that doesn't make my usage incorrect :D

EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time)

DcodingTheWeb Forum - Follow for updates and Join for discussion

Posted (edited)

@TheDcoder - I am not saying your approach is wrong, and you have indeed explained a good reason. However, you said I was wrong, which I wasn't ... not in the simple context, which was all I used.

In any case, whichever way you look at it, you are still providing a unique string for the string value, which is exactly what I said.

My own later example, was my usage only ... as an example. That was not what you responded to when you said I was wrong. :)

As for my examples, they were just a couple of illustrations of the possibilities. There are others. You could also combine mine or tweak certain elements to do exactly as you suggested, without the need to provide a different path, just work on a response to a query, which is perhaps more correct when running two separate copies of the same program ... but that depends on the program. ;)

Edited by TheSaint

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

  • 7 months later...
Posted
On 9/18/2018 at 5:48 AM, TheSaint said:

 . . . 

$exist = _Singleton("use-unique-name", 1)
If $exist = 0 Then
     If @Compiled = 1 Then
         $pid = ProcessExists(@ScriptName)
         $exe = @ScriptName
     Else
         $pid = ProcessExists("AutoIt3.exe")
         $exe = "AutoIt3.exe"
     EndIf
     $script = @AutoItPID
     $ans = MsgBox(262177, "Close Running Instance Query", _
         "This program is already running." & @LF & @LF & _
         "Do you want to close it for this new instance?" & @LF & @LF & _
         "NOTE - If all work has been saved, then OK" & @LF & _
         "could be clicked, else click CANCEL." & @LF & @LF & _
         $pid & " (" & $exe & ") " & $script & @LF & @LF & _
         "(will default to CANCEL in 30 seconds)", 30)
     If $ans = 1 Then
         If $pid <> $script Then
             ProcessClose($pid)
         Else
             MsgBox(262192, "Close Error", "OK process failed!", 0)
             Exit
         EndIf
     ElseIf $ans = 2 Or $ans = -1 Then
         Exit
     EndIf
EndIf

Extracted from a couple of my programs, with slight modification.

This was super helpful, but I think a key element is missing. If you have a click happy user (no idea who that could be :whistle:), then a third program can enter the mix. The third program won't return 0 when running _Singleton("use-unique-name", 1), and then you have two programs running again. The call to _Singleton needs to be placed again after this code to ensure that other copies don't get past. :)

All my code provided is Public Domain... but it may not work. ;) Use it, change it, break it, whatever you want.

Spoiler

My Humble Contributions:
Personal Function Documentation - A personal HelpFile for your functions
Acro.au3 UDF - Automating Acrobat Pro
ToDo Finder - Find #ToDo: lines in your scripts
UI-SimpleWrappers UDF - Use UI Automation more Simply-er
KeePass UDF - Automate KeePass, a password manager
InputBoxes - Simple Input boxes for various variable types

Posted
21 hours ago, seadoggie01 said:

This was super helpful, but I think a key element is missing. If you have a click happy user (no idea who that could be :whistle:), then a third program can enter the mix. The third program won't return 0 when running _Singleton("use-unique-name", 1), and then you have two programs running again. The call to _Singleton needs to be placed again after this code to ensure that other copies don't get past. :)

I'm sorry, but that doesn't make much sense to me, unless you have allowed a queue to build. Even then, you should be aware you have done so, and act accordingly, by not killing the first (original) instance. If you don't do the right thing, well you are on your own ... Click-Happy users beware. :P

Really, it is a convenience thing having a prompt to respond to. The more normal approach, is to not allow a second etc instance at all ... which should be prevented instantly. Except in one rare instance for me, I want the original process to remain running, and all later ones prevented. Generally, it is just a reminder you already have the program running ... no doubt minimized and forgotten.

But hey, if you want to create some elaborate looping check, go right ahead ... and don't forget to post it. :)

P.S. Perhaps there is a way to get a count of instances running, to trigger or exit the loop.

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

Posted (edited)

A mutex is just a unique, user-named flag; it either exists or it doesn't, and it doesn't do anything other than enabling the OS to check whether it exists, allowing your code to decide what to do next based upon the result. If you want a limited number of processes (>1) to have access, use a semaphore instead. This Toilet example may clarify.;)

Edited by RTFC
Posted (edited)

@TheSaint I absolutely see your point for it not being needed most of the time. I was thinking about automation I do for work. When I'm not here, someone else will run my program. If it takes a long time (cause I did something annoying like use a WinWaitActive), they might try restarting. And restarting again if that one doesn't work.

As for posting my code, it would look like this: :)

; Awesome code from TheSaint

; Loop because after closing the process it takes about 10 milliseconds for the Mutex object to be released
Do
    ; Capture the singleton again
    $singleton = _Singleton("your-unique-code", 1)
Until Not ($singleton = 0)

You could use a ProcessWaitClose instead of looping, but this took ~10 milliseconds vs ~250 milliseconds for waiting for the process.

Edited by seadoggie01

All my code provided is Public Domain... but it may not work. ;) Use it, change it, break it, whatever you want.

Spoiler

My Humble Contributions:
Personal Function Documentation - A personal HelpFile for your functions
Acro.au3 UDF - Automating Acrobat Pro
ToDo Finder - Find #ToDo: lines in your scripts
UI-SimpleWrappers UDF - Use UI Automation more Simply-er
KeePass UDF - Automate KeePass, a password manager
InputBoxes - Simple Input boxes for various variable types

Posted

@seadoggie01 - That looks simple enough, but .......

And in your scenario, surely you want all other instances to fail anyway, and don't really want a query prompt ... perhaps just a quick splash - 'Program is already running!'.
Or are you wanting to give your users the ability to quick kill and restart?

My code was for a specific scenario, and not really appropriate outside of that.

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

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...