supercat Posted August 24, 2012 Posted August 24, 2012 Hi everyone, I am currently working on automating an install and just have a quick question. The install process can be different from machine to machine depending on the configuration of the machine. The install process can have 1 extra window to interact with depending on this configuration, so I currently have 2 exe's built. I would really like just 1 exe file to push out across the network. So I wanted to know is this scenario possible and how would I script it:- If WinActive (THE EXTRA WINDOW) then ControlClick (THE REQUIRED BUTTON) Else (CONTINUE WITH SCRIPT) I have tried various ways using If WinExists and WinWaitActive but cannot get it to complete. I hope this makes sense and someone can enlighten me!
Mechaflash Posted August 24, 2012 Posted August 24, 2012 (edited) Having two different windows open for the same function is a bit tricky. The reason why it's probably failing is because WinWait() is running before the window comes up, so it resolves to 'else'. Try a loop looking for either window and perform the action there: While 1 Sleep(100) If WinExists("THE EXTRA WINDOW") Then ControlClick(THE REQUIRED BUTTON) [... do whatever you need to do after the click ...] ElseIf WinExists("THE OTHER WINDOW") Then ExitLoop EndIf WEnd [... continue script ...] Edited August 24, 2012 by mechaflash213 Spoiler “Hello, ladies, look at your man, now back to me, now back at your man, now back to me. Sadly, he isn’t me, but if he stopped using ladies scented body wash and switched to Old Spice, he could smell like he’s me. Look down, back up, where are you? You’re on a boat with the man your man could smell like. What’s in your hand, back at me. I have it, it’s an oyster with two tickets to that thing you love. Look again, the tickets are now diamonds. Anything is possible when your man smells like Old Spice and not a lady. I’m on a horse.”
MrMitchell Posted August 24, 2012 Posted August 24, 2012 (edited) Just throwing this out there...whatever the installer is, check to see if it has a command line for installation rather than automating the windows. Edit: Nevermind, just saw your other thread! Edited August 24, 2012 by MrMitchell
supercat Posted August 24, 2012 Author Posted August 24, 2012 Thanks guys, I just got it! Start of script here If WinActive (THE EXTRA WINDOW) then ControlClick (THE REQUIRED BUTTON) REST OF SCRIPT HERE Else (NO EXTRA WINDOW) then REST OF SCRIPT HERE ENDIF (REST OF SCRIPT HERE) is the same after navigating past the (THE EXTRA WINDOW) All works well now. A couple of things though, I have tested on XP, Win7, 2k3, 2k8 and it seems that one of the screens (where I specify destination folder) in Win7 has a different instance of the "Next" button than all other OS's. So I have a different script for Win7, not an issue really but just strange. The way I navigate every window in the install process is by using: WinWaitActive (WINDOW) ControlClick (WINDOW) I have found if a user clicks elsewhere and unactivates a window the script pauses. Understandable. Would I be better using: WinWait (Window) WinActivate (Window) ControlClick (Window) Thanks
jdelaney Posted August 24, 2012 Posted August 24, 2012 (edited) What I would do, is use the below function, based on the run commands returned PID...it retrieves all the windows that are created for the process, then you just have to loop through until you find the active one. Then, if you have a switch case statement for the title/text in the window, you can easily automate it. I use the same thing on all my companies applications, because they love adding warning messages for everything. expandcollapse popupFunc _ProcessGetWindow($p_PID, $p_ReturnBestGuess = False) ; #FUNCTION# ============================================================================================================================ ; Name...........: _ProcessGetWindow ; ; Description ...: Returns an array of HWNDs containing all windows owned by the process $p_PID, or optionally a single "best guess." ; ; Syntax.........: _ProcessGetWindow( $p_PID [, $p_ReturnBestGuess = False ]) ; ; Parameters ....: $p_PID - The PID of the process you want the Window for. ; $p_ReturnBestGuess - If True, function will return only 1 reult on a best-guess basis. ; The "Best Guess" is the VISIBLE window owned by $p_PID with the longest title. ; ; Return values .: Success - Return $_array containing HWND info. ; $_array[0] = Number of results ; $_array[n] = HWND of Window n ; ; Failure - Returns 0 ; ; Error - Returns -1 and sets @error ; 1 - Requires a non-zero number. ; 2 - Process does not exist ; 3 - WinList() Error ; ; Author ........: Andrew Bobulsky, contact: RulerOf <at that public email service provided by Google>. ; Remarks .......: The reverse of WinGetProcess() ; ======================================================================================================================================= Local $p_ReturnVal[1] = [0] Local $p_WinList = WinList() If @error Then ;Some Error handling SetError(3) Return -1 EndIf If $p_PID = 0 Then ;Some Error handling SetError(1) Return -1 EndIf If ProcessExists($p_PID) = 0 Then ;Some Error handling ConsoleWrite("_ProcessGetWindow: Process " & $p_PID & " doesn't exist!" & @CRLF) SetError(2) Return -1 EndIf For $i = 1 To $p_WinList[0][0] Step 1 Local $w_PID = WinGetProcess($p_WinList[$i][1]) ; ConsoleWrite("Processing Window: " & Chr(34) & $p_WinList[$i][0] & Chr(34) & @CRLF & " with HWND: " & $p_WinList[$i][1] & @CRLF & " and PID: " & $w_PID & @CRLF) If $w_PID = $p_PID Then ;ConsoleWrite("Match: HWND " & $p_WinList[$i][1] & @CRLF) $p_ReturnVal[0] += 1 _ArrayAdd($p_ReturnVal, $p_WinList[$i][1]) EndIf Next If $p_ReturnVal[0] > 1 Then If $p_ReturnBestGuess Then Do Local $i_State = WinGetState($p_ReturnVal[2]) Local $i_StateLongest = WinGetState($p_ReturnVal[1]) Select Case BitAND($i_State, 2) And BitAND($i_StateLongest, 2) ;If they're both visible If StringLen(WinGetTitle($p_ReturnVal[2])) > StringLen(WinGetTitle($p_ReturnVal[1])) Then ;And the new one has a longer title _ArrayDelete($p_ReturnVal, 1) ;Delete the "loser" $p_ReturnVal[0] -= 1 ;Decrement counter Else _ArrayDelete($p_ReturnVal, 2) ;Delete the failed challenger $p_ReturnVal[0] -= 1 EndIf Case BitAND($i_State, 2) And Not BitAND($i_StateLongest, 2) ;If the new one's visible and the old one isn't _ArrayDelete($p_ReturnVal, 1) ;Delete the old one $p_ReturnVal[0] -= 1 ;Decrement counter Case Else ;Neither window is visible, let's just keep the first one. _ArrayDelete($p_ReturnVal, 2) $p_ReturnVal[0] -= 1 EndSelect Until $p_ReturnVal[0] = 1 EndIf Return $p_ReturnVal ElseIf $p_ReturnVal[0] = 1 Then Return $p_ReturnVal ;Only 1 window. Else Return 0 ;Window not found. EndIf EndFunc ;==>_ProcessGetWindow Edited August 24, 2012 by jdelaney IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.
jdelaney Posted August 24, 2012 Posted August 24, 2012 (edited) If you want a completely blind installer, just update the button text array, and it will do it's thing untill the process finishes: expandcollapse popupDim $aButtonClickOrder[8] = ["Continue", "&Continue", "OK", "&OK", "Yes", "&Yes", "Install", "&Install"] Dim $aExpectedWindowState[3] = [1, 2, 4] ; Window exists, visible, and enabled $PID = Run() While ProcessExists($PID) $bButtonClicked = False $aHWnds = _ProcessGetWindow ( $PID ) If IsArray ( $aHWnds ) Then For $i = 0 To UBound ( $aHWnds ) - 1 If WaitForWindowState ( $aHWnds[$i], $aExpectedWindowState, 0, 0 ) Then ; window exists, is visible, and is enabled. For $j = To UBound ( $aButtonClickOrder ) - 1 $hButton = ControlGetHandle ( $aHWnds[$i], "", "[CLASS:Button; TEXT:" & $aButtonClickOrder[$j] & "]" If IsHWnd ( $hButton ) Then ; button exists If ControlCommand ( $aHWnds[$i], "", $hButton, "IsEnabled", "" ) Then ControlFocus ( $aHWnds[$i], "", $hButton ) ControlClick ( $aHWnds[$i], "", $hButton ) Sleep (2000) $bButtonClicked = True ExitLoop EndIf EndIf Next If $bButtonClicked Then ExitLoop EndIf Next EndIf Sleep ( 1000 ) WEnd Func _ProcessGetWindow($p_PID, $p_ReturnBestGuess = False) ; #FUNCTION# ============================================================================================================================ ; Name...........: _ProcessGetWindow ; ; Description ...: Returns an array of HWNDs containing all windows owned by the process $p_PID, or optionally a single "best guess." ; ; Syntax.........: _ProcessGetWindow( $p_PID [, $p_ReturnBestGuess = False ]) ; ; Parameters ....: $p_PID - The PID of the process you want the Window for. ; $p_ReturnBestGuess - If True, function will return only 1 reult on a best-guess basis. ; The "Best Guess" is the VISIBLE window owned by $p_PID with the longest title. ; ; Return values .: Success - Return $_array containing HWND info. ; $_array[0] = Number of results ; $_array[n] = HWND of Window n ; ; Failure - Returns 0 ; ; Error - Returns -1 and sets @error ; 1 - Requires a non-zero number. ; 2 - Process does not exist ; 3 - WinList() Error ; ; Author ........: Andrew Bobulsky, contact: RulerOf <at that public email service provided by Google>. ; Remarks .......: The reverse of WinGetProcess() ; ======================================================================================================================================= Local $p_ReturnVal[1] = [0] Local $p_WinList = WinList() If @error Then ;Some Error handling SetError(3) Return -1 EndIf If $p_PID = 0 Then ;Some Error handling SetError(1) Return -1 EndIf If ProcessExists($p_PID) = 0 Then ;Some Error handling ConsoleWrite("_ProcessGetWindow: Process " & $p_PID & " doesn't exist!" & @CRLF) SetError(2) Return -1 EndIf For $i = 1 To $p_WinList[0][0] Step 1 Local $w_PID = WinGetProcess($p_WinList[$i][1]) ; ConsoleWrite("Processing Window: " & Chr(34) & $p_WinList[$i][0] & Chr(34) & @CRLF & " with HWND: " & $p_WinList[$i][1] & @CRLF & " and PID: " & $w_PID & @CRLF) If $w_PID = $p_PID Then ;ConsoleWrite("Match: HWND " & $p_WinList[$i][1] & @CRLF) $p_ReturnVal[0] += 1 _ArrayAdd($p_ReturnVal, $p_WinList[$i][1]) EndIf Next If $p_ReturnVal[0] > 1 Then If $p_ReturnBestGuess Then Do Local $i_State = WinGetState($p_ReturnVal[2]) Local $i_StateLongest = WinGetState($p_ReturnVal[1]) Select Case BitAND($i_State, 2) And BitAND($i_StateLongest, 2) ;If they're both visible If StringLen(WinGetTitle($p_ReturnVal[2])) > StringLen(WinGetTitle($p_ReturnVal[1])) Then ;And the new one has a longer title _ArrayDelete($p_ReturnVal, 1) ;Delete the "loser" $p_ReturnVal[0] -= 1 ;Decrement counter Else _ArrayDelete($p_ReturnVal, 2) ;Delete the failed challenger $p_ReturnVal[0] -= 1 EndIf Case BitAND($i_State, 2) And Not BitAND($i_StateLongest, 2) ;If the new one's visible and the old one isn't _ArrayDelete($p_ReturnVal, 1) ;Delete the old one $p_ReturnVal[0] -= 1 ;Decrement counter Case Else ;Neither window is visible, let's just keep the first one. _ArrayDelete($p_ReturnVal, 2) $p_ReturnVal[0] -= 1 EndSelect Until $p_ReturnVal[0] = 1 EndIf Return $p_ReturnVal ElseIf $p_ReturnVal[0] = 1 Then Return $p_ReturnVal ;Only 1 window. Else Return 0 ;Window not found. EndIf EndFunc ;==>_ProcessGetWindow Func WaitForWindowState($hwndCallersWindow, $aCallersExpectedWindowState, $sCallersTotalWaitSeconds, $sCallersWaitChecks) $iTotalWaitMilSec = $sCallersTotalWaitSeconds * 1000 $iSleepMilSec = $iTotalWaitMilSec / $sCallersWaitChecks ; Get states to log $sExpectedStates = "" For $i = 0 To UBound($aCallersExpectedWindowState) - 1 Switch $aCallersExpectedWindowState[$i] Case 1 $sExpectedStates = $sExpectedStates & "Exists " Case 2 $sExpectedStates = $sExpectedStates & "Visible " Case 4 $sExpectedStates = $sExpectedStates & "Enabled " Case 8 $sExpectedStates = $sExpectedStates & "Active " Case 16 $sExpectedStates = $sExpectedStates & "Minimized " Case 32 $sExpectedStates = $sExpectedStates & "Maximized " Case Else ;If $lgbPerformLog Then Call("SetLogAndActOnState", 0, 2, "WaitForWindowState()", "Callers Win State=[" & $aCallersExpectedWindowState[$i] & "], but values must be in (1,2,4,8,16,32).", False, False) Return False EndSwitch Next $sExpectedStates = StringStripWS($sExpectedStates, 7) ; Strip double spaces, trailing, and leading For $i = 0 To $sCallersWaitChecks $iWinState = WinGetState($hwndCallersWindow) $bExpectedState = True For $iCurrentCheck = 0 To UBound($aCallersExpectedWindowState) - 1 If Not BitAND($iWinState, $aCallersExpectedWindowState[$iCurrentCheck]) Then $bExpectedState = False ExitLoop EndIf Next If $bExpectedState Then ; Log State is as expected ;If $lgbPerformLog Then Call("SetLogAndActOnState", 2, 2, "WaitForWindowState()", "Window State=[" & $iWinState & "] matches callers expected window state[s]=[" & $sExpectedStates & "].", False, False) Return True EndIf Sleep($iSleepMilSec) Next ; Log State did not match expected ;Call("SetLogAndActOnState", 0, 2, "WaitForWindowState()", "Window State=[" & $iWinState & "] did NOT match callers expected window state[s]=[" & $sExpectedStates & "] within expected seconds=[" & $sCallersTotalWaitSeconds & "]", False, False) Return False EndFunc ;==>WaitForWindowState #include <Array.au3> #include <GuiToolbar.au3> $array = ProcessList("UnivMgr.exe") _ArrayDisplay($array) ;~ $array = _ProcessGetWin ( $array[1][1] ) Exit ;~ #include <Array.au3> ;~ $test = "this is a string" ;~ $array = StringToASCIIArray ( $test ) ;~ _ArrayDisplay ( $array ) ;~ For $i = 0 To UBound ( $array ) - 1 ;~ If $array[$i] ;~ Exit Dim $array[1] $iCounter = 1 While 1 If Not WinExists("[CLASS:IEFrame; INSTANCE:" & $iCounter & "]") Then ExitLoop ReDim $array[$iCounter] $array[$iCounter - 1] = WinGetTitle("[CLASS:IEFrame; INSTANCE:" & $iCounter & "]") $iCounter += 1 WEnd _ArrayDisplay($array) Exit Switch $SomeValuea & $SomeValueb Case False & False MsgBox(1, 1, "00") Case True & False MsgBox(1, 1, "10") Case False & True MsgBox(1, 1, "01") Case True & True MsgBox(1, 1, "11") EndSwitch Edited August 24, 2012 by jdelaney IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.
Mechaflash Posted August 24, 2012 Posted August 24, 2012 I just got it!I know you're feeling excitement because it has worked for you based on the way you've coded it. However, let me explain why I think you may want to alter this section of code.The way the code is written, it is error prone in the case of delays of the proper window popping up. For example, your script hits the next button to bring up one of the two windows. Right after that command, your WinActive() fires... BUT the window lagged when coming up so the WinActive() doesn't resolve as true. So instead, your script continues on with its normal operation not running any of your code for that extra window.And on another note, it's advisable to use a WinActivate() followed by ControlCommand() to click on buttons for the installer, as some controls need to have the window in question in focus at the time the command is sent to interact with a control. Spoiler “Hello, ladies, look at your man, now back to me, now back at your man, now back to me. Sadly, he isn’t me, but if he stopped using ladies scented body wash and switched to Old Spice, he could smell like he’s me. Look down, back up, where are you? You’re on a boat with the man your man could smell like. What’s in your hand, back at me. I have it, it’s an oyster with two tickets to that thing you love. Look again, the tickets are now diamonds. Anything is possible when your man smells like Old Spice and not a lady. I’m on a horse.”
supercat Posted August 29, 2012 Author Posted August 29, 2012 Many thanks JDelaney and mechaflash213 - great help. I will go away and read your advice a few times and see if I can improve my script. I am very new to AutoIT and scripting but I am learning fast and appreciate the help.
supercat Posted August 30, 2012 Author Posted August 30, 2012 Having studied the above code I must admit I don't understand it. I do however want to improve my script and install process. I have gone through the install again using Control View program by Yashied. This time I have retrieved the Class, Instance, ID, Handle and Text of all control's and also the Title, Class, Handle and PID of all window's. Which method will prove best to ensure the install process goes to plan?
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