Jump to content

WinGetState 5 and restoring/showing windows


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
    WinSetState($g_szVersion,"",@SW_SHOW)
    MsgBox(0,"","gState = " & $gState) ;For debugging purposes
    WinSetState($g_szVersion,"",@SW_RESTORE)
    MsgBox(0,"","gState = " & $gState) ;For debugging purposes
    WinActivate($g_szVersion)
    Exit
EndIf
AutoItWinSetTitle($g_szVersion)

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. 

Untitled.png.9c1e43de7a0b7ac51905ba2636b8e168.png

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:

Func VSOL_FFTOOLS_SHOW_DOWNLOADS()
   GUISetState(@SW_MINIMIZE,$VSOL_BACKEND)
   ShellExecute(@UserProfileDir & "\Downloads")
EndFunc

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 comment
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
    WinActivate($handle)

    ; Exit this script
    Exit
EndIf

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)
        AutoItWinSetTitle($sOccurenceName)

        Local Const $hControl = ControlGetHandle($hAutoItWnd, '', 'Edit1')
        ControlSetText($hAutoItWnd, '', $hControl, ControlGetText($hAutoItWnd, '', $hControl) & @CRLF & _
                '|SINGLETON_PID:' & @AutoItPID & @CRLF)
    Else
        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])
        Else
            Exit -1
        EndIf
    EndIf
    Return $iReturn
EndFunc   ;==>_SingletonPID

Func _GetHwndFromPID($PID)
    $hWnd = 0
    $winlist = WinList()
    Do
        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]
                    ExitLoop
                EndIf
            EndIf
        Next
    Until $hWnd <> 0
    Return $hWnd
EndFunc;==>_GetHwndFromPID

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
    WinSetState($handle,"",7)
    ; Activate that window
    WinActivate($handle)

    ; Exit this script
    Exit
EndIf

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

Naamloos.png.848d3fb84376d05ebc0f4b6def10d3f0.png

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 comment
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 comment
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 comment
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 comment
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:

Opt('WinTitleMatchMode',2)
Local $SingletonHandle = _Singleton("VSOL ToolKit",1)
If $SingletonHandle = 0 Then
    WinActivate("VSOL ToolKit")
    Exit
EndIf

I feel so enormously stupid right now. 

#sorryforwastingyourtime

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

×
×
  • Create New...