jantograaf Posted April 4, 2018 Posted April 4, 2018 (edited) 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. 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 April 4, 2018 by jantograaf
Earthshine Posted April 4, 2018 Posted April 4, 2018 perhaps this My resources are limited. You must ask the right questions
jantograaf Posted April 4, 2018 Author Posted April 4, 2018 Alright, thanks @Earthshine, I'll try to implent this and see what it does. I'll keep you posted :-) Kind regards, Jan
jantograaf Posted April 4, 2018 Author Posted April 4, 2018 (edited) 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): expandcollapse popup; #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*. 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 April 4, 2018 by jantograaf
Earthshine Posted April 5, 2018 Posted April 5, 2018 have you tried the built in _Singleton? You don't need the PID one probably _Singleton Look at the help file please. My resources are limited. You must ask the right questions
jantograaf Posted April 5, 2018 Author Posted April 5, 2018 (edited) 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 Edited April 5, 2018 by jantograaf
Earthshine Posted April 5, 2018 Posted April 5, 2018 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 jantograaf 1 My resources are limited. You must ask the right questions
BrewManNH Posted April 5, 2018 Posted April 5, 2018 GUICreate returns a handle, why can't you use that? Earthshine 1 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 GudeHow 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
jantograaf Posted April 5, 2018 Author Posted April 5, 2018 @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 Earthshine 1
Earthshine Posted April 5, 2018 Posted April 5, 2018 (edited) you rock dude! happy programming! You can probably edit the very first post and add SOLVED to the Thread Title so other people searching one day will see how you solved it Edited April 5, 2018 by Earthshine jantograaf 1 My resources are limited. You must ask the right questions
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now