Jump to content

Recommended Posts

Hi all,

I'm having some trouble restoring a program which uses a normal AutoIT-GUI and is used as a ToolKit for our customers to open different (external) tools, check their network connections or ping different destinations. Almost all customers are running this script on Win7 x64. 

What do I want to do?

When the program is already running and the user tries to start it for a second time, it should exit the second instance after activating/restoring the first instance.

What did I do to integrate this?

I used a little piece of script found on the forums to prevent opening a second instance and modified it as follows:

$g_szVersion = "VSOL ToolKit"
If WinExists($g_szVersion) Then
    Local $gState = WinGetState($g_szVersion)
    MsgBox(0,"","gState = " & $gState) ;For debugging purposes
    MsgBox(0,"","gState = " & $gState) ;For debugging purposes
    MsgBox(0,"","gState = " & $gState) ;For debugging purposes

I have tried it with only the @SW_SHOW, only the @SW_RESTORE, both of them in a different order, same difference, it doesn't work.

What does happen then?

It detects the current state (when it's minimized) as '5', which means enabled and hidden. After setting the state to show, the state changes to 7. Restoring doesn't change the state. But what is really odd, is that the window doesn't appear but AutoIt seems to create a néw window with the same title as the existing one. 


It doesn't matter if the window was originally minimized by clicking the minimize button in the GUI or by a line of code in my script. For example, when users open a software package from within my script, a similar function to this one will be called:

   ShellExecute(@UserProfileDir & "\Downloads")

The only thing that does work, is when the window is running in a non-minimized state (somewhere behind the current window), it gets activated and receives the focus when trying to start the second instance.

If anyone could help me out with this one, I'd be forever thankful :-)

Thanks in advance!

Kind regards,

Jan Geurts

Edited by jantograaf
Link to post
Share on other sites

Okay, @Earthshine, I've tried it by adding the following code at the beginning of my code:

; Search for another instance of this script
Local $singleton = _SingletonPID('YourScript',1)

; If another instance was found
if $singleton <> 0 Then
    MsgBox(0,"Oops","ToolKit is already running")    ;for debugging purposes
    ; Get a handle on that instance
    $handle = _GetHwndFromPID($singleton)

    ; Activate that window

    ; Exit this script

And this at the end (I've included the comments to attribute the original poster):

; #FUNCTION# ====================================================================================================================
; Name ..........: _SingletonPID
; Description ...: Enforce a design paradigm where only one instance of the script may be running.
; Syntax ........: _SingletonPID($sOccurenceName[, $iFlag = 0])
; Parameters ....: $sOccurenceName      - String to identify the occurrence of the script.
;                  $iFlag               - [optional] Optional parameters (see below). Default is 0.
;                       0 - Exit the script with the exit code -1 if another instance already exists.
;                       1 - Return the PID of the initial executable.
; Return values .: Success - 0 (no additional instances exist).
;                  Failure - The PID of the initial instance.
; Author ........: guinness with initial ideas by Valik for _Singleton() & KaFu for _EnforceSingleInstance().
; Example .......: Yes
; ===============================================================================================================================
Func _SingletonPID($sOccurenceName, $iFlag = 0)
    Local $iReturn = 0
    Local $hAutoItWnd = WinGetHandle($sOccurenceName)
    If @error Then
        AutoItWinSetTitle($sOccurenceName & @AutoItPID)
        $hAutoItWnd = WinGetHandle($sOccurenceName & @AutoItPID)

        Local Const $hControl = ControlGetHandle($hAutoItWnd, '', 'Edit1')
        ControlSetText($hAutoItWnd, '', $hControl, ControlGetText($hAutoItWnd, '', $hControl) & @CRLF & _
                '|SINGLETON_PID:' & @AutoItPID & @CRLF)
        If $iFlag = Default Then $iFlag = 0
        If BitAND($iFlag, 1) Then ; $SINGLETON_PID
            $iReturn = Int(StringRegExp(ControlGetText($hAutoItWnd, '', ControlGetHandle($hAutoItWnd, '', 'Edit1')) & @CRLF & _
                    '|SINGLETON_PID:0' & @CRLF, _
                    '\|SINGLETON_PID:(\d+)\R', $STR_REGEXPARRAYGLOBALMATCH)[0])
            Exit -1
    Return $iReturn
EndFunc   ;==>_SingletonPID

Func _GetHwndFromPID($PID)
    $hWnd = 0
    $winlist = WinList()
        For $i = 1 To $winlist[0][0]
            If $winlist[$i][0] <> "" Then
                $iPID2 = WinGetProcess($winlist[$i][1])
                If $iPID2 = $PID Then
                    $hWnd = $winlist[$i][1]
    Until $hWnd <> 0
    Return $hWnd

So, what happens now: if my script is already running and it's hidden behind another window, I first get a MsgBox saying that there is already a ToolKit running. After clicking OK, it succesfully activates the running instance and exits the second instance. However, when I minimize the window first and then run a second instance, it doesn't pop up. Seems logical, since WinGetState returns 5 (it's hidden and enabled). So I tried adjusting the code so it doesn't just activate the window but also changes the state of the window. Like this :

; Search for another instance of this script
Local $singleton = _SingletonPID('YourScript',1)

; If another instance was found
if $singleton <> 0 Then
    ;MsgBox(0,"Oeps","Er draait al een ToolKit")
    ; Get a handle on that instance
    $handle = _GetHwndFromPID($singleton)
    ; Restore the window
    ; Activate that window

    ; Exit this script

What happens this time?

If the window is active and on the foreground, it minimizes and immediately restores. Strange.
If the window is active and in the background, it seems to restore from taskbar and pop up. Good.
If the window is minimized, it pops up a new window called 'Your Script' as seen in attached screenshot. WT*.


I can't seem to figure out what happens. The _SingletonPID-function gives me the exact PID, okay, but is the handle returned still the wrong one? Since it doesn't restore the correct window? :(


Edited by jantograaf
Link to post
Share on other sites

Thanks for pointing me to the help file, but I tried this already. Using the _Singleton()-function, the return value is 0 when another instance is already running. This can be used perfectly to close the second instance (which I also need), but this cannot be used to activate the first, already running instance. That's why I needed the _SingletonPID() :)

The _SingletonPID() however points me to the hidden AutoIT-window (after getting the window handle for the returned PID) instead of the handle of the GUI window.

I don't expect anyone to write my script for me, I'm just asking for anyone to see where the flaw is. Is it in the _Singleton() or _SingletonPID()-functions, is it in what I'm trying to do or the way I am approaching this or is this some kind of AutoIT GUI specification I just don't seem to grasp yet? It is a normal GUI window which is minimized and for the love of god, I just can't seem to restore it when the user accidentally starts a second instance :lol:

Edited by jantograaf
Link to post
Share on other sites

not suggesting we write it for you. could you try the ProcessExists function so that you can get the handle from process you care about? oh and there are GUI experts here who can probably help you, I just automate stuff, not much of a gui guy

My resources are limited. You must ask the right questions


Link to post
Share on other sites

GUICreate returns a handle, why can't you use that?

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to post
Share on other sites

@BrewManNH because the handle is created in the first instance of my Toolkit. It needs to be activated when a user tries to start a second instance.

But on another note, close this thread, I've been looking waaaaaaay to far by trying to restore the window using the handle and everything. I just started from scratch, trying to use the _Singleton()-function to detect an already running instance, but using a way simpler solution to reactivate the window. And. It. Worked.

Sometimes when the solution looks to easy, I get fooled. thanks @Earthshine anyways...

The code I ended up using:

Local $SingletonHandle = _Singleton("VSOL ToolKit",1)
If $SingletonHandle = 0 Then
    WinActivate("VSOL ToolKit")

I feel so enormously stupid right now. 


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

    No registered users viewing this page.

  • Similar Content

    • By poddex
      Hello everyone.
      I always try to work with old Windows 10 versions as much as possible because I know mane compatibility issues with Windows 10 upgrading. 
      But I couldn't do anything else (I got drivers problem), and nothing couldn't help me besides upgrading, so I upgraded from 1807 to 1903.
      And...get another problem 😃
      I use AutoitX library in external project like this.
      ObjectAutoIt=New COMObject("AutoItX3.Control");
              While ObjectAutoit.WinExists("",WindowHeader) Cycle 
      After upgrade I get that this line code 
      While ObjectAutoit.WinExists("",WindowHeader)
      become extremely low - ~ 20 seconds even if 10 windows open. But before upgrade it takes 0.5 s for a max.
      And every time that this code line passes through  - it takes ~20s, (20.115, for example), not less, not more. Something pauses it to work.
      How can I diagnose, what is that?
      I tried reinstall whole AutoIt, but no results.
      Thanks to all.
    • By cabrunco
      Hi all, I am writing some scripts to control some lab equipment, and sometimes I observe that the script "misses" one of the steps, leading to cascading errors. For example, at one part of the code I wrote this:
      Most of the times this works, but I found that in some occasions the windows fail to close. Then, the code becomes a mess, because a second instance of the program will launch, and both windows now have the same title. I think I can solve this problem with this code:
      While WinExists("Hype")
      I would like to know if anybody has any other suggestions for this kind of redundant code. Thanks,
    • By AndyK70
      I'm trying to fill a ListView with all normal viewable windows to act with them.
      First I tried with WinList:
      Local $aWinList = WinList("[REGEXPTITLE:(?i)(.+)]") Local $aTmp, $iID ;~ _ArrayDisplay($aWinList) For $i = $aWinList[0][0] To 1 Step -1 ; going backwards not disturbing the index while cycling through and deleting some If StringStripWS( $aWinList[$i][0], 3) == "" Or _ Not BitAND(WinGetState($aWinList[$i][1]), $WIN_STATE_VISIBLE) Or _ BitAND(WinGetState($aWinList[$i][1]), $WIN_STATE_MINIMIZED ) Then _ArrayDelete($aWinList, $i) Else ; Window has a Title and is "visible" $aTmp = WinGetPos($aWinList[$i][1]) If $aTmp[0] < -1000 Or $aTmp[1] < -1000 Then ; Window is minimized or tray icon _ArrayDelete($aWinList, $i) EndIf EndIf Next $aWinList[0][0] = UBound($aWinList)-1 ; getting actual # of windows ; Each row is now [ID]=> [Title], [hWnd] But it keeps getting Windows which are definitely not there at least not visible:

      Those windows "Rechner", "Einstellungen", "Netflix", "Microsoft Store", ... are not there!?! 
      It should list only the first three windows, which are real.
      I even tried it with _WinAPI_ UDF:
      $hWnd = _WinAPI_GetForegroundWindow() ; Add items _GUICtrlListView_BeginUpdate($idListview) If $hWnd <> 0 Then $iI = 0 Do If _WinAPI_IsWindow($hWnd) And _WinAPI_IsWindowVisible Then _GUICtrlListView_AddItem($idListview, WinGetTitle($hWnd)) _GUICtrlListView_AddSubItem($idListview, $iI, $hWnd, 1) $iI += 1 $hWnd = _WinAPI_GetWindow($hWnd, $GW_HWNDNEXT) EndIf Until $hWnd = 0 EndIf But it is the same...
      How can i distinguish those invisible windows from normal ones?
      PS: I'm using Windows 10, maybe it is important to know?
    • By SteveStrop
      I'm trying to:
      1) Open a hidden browser session
      2) Do some stuff in the background
      3)  Make the hidden window visible
      This is my code:
      Opt("WinTitleMatchMode", 2) ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase $oIE = _IECreate("https://www.google.co.uk/",0,0) $oSearchBox = _IEGetObjById($oIE, "lst-ib") $oSearchBox.innertext = "AutoIT" $oForm = _IEFormGetObjByName($oIE,"f") _IEFormSubmit($oForm) WinSetState("Google","",@SW_SHOW)  
      It dosen't work
      The last line does make the window visible but it is an empty greyed out box that disappears as soon as I click on it.
      I have a sort of workaround that hides the browser window as soon as I have created it which works fine:
      $oIE = _IECreate("https://www.google.co.uk/") WinSetState("Google","",@SW_HIDE) . . . WinSetState("Google","",@SW_SHOW) But this looks a bit pants as the newly created window flashes on then off of the screen.
      Am I using the wrong method to make the browser window visible?
    • By anthonyjr2
      I have come across a weird issue that I am not sure how to solve. For some reason, whenever I call WinActivate in certain scenarios instead of opening the single window that already exists, it will create a new blank tab. It should be able to be recreated with this:
      AutoItSetOption("WinTitleMatchMode", 2) Sleep(1000) For $i=0 To 10 WinActivate("Internet Explorer") Next I am not actually doing this in my code, it is just to demonstrate the fact that new tabs keep popping up. Does anyone know why this happens?
      EDIT: So I am not sure how reproducible this is, because it only happens every once in a while for me. I will update with more info if I find out anything.
  • Create New...