seadoggie01 Posted November 7, 2019 Share Posted November 7, 2019 I'm making my own "simple" wrapper for UI automation and I started realizing that a lot of the functions need the UI Automation object. I'm especially wondering here because I don't know of a situation that you would need two UI Automation objects. Does it make sense to make this a global variable so the user doesn't have to pass it to each individual function, or is this bad practice in general? 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 functionsAcro.au3 UDF - Automating Acrobat ProToDo Finder - Find #ToDo: lines in your scriptsUI-SimpleWrappers UDF - Use UI Automation more Simply-erKeePass UDF - Automate KeePass, a password managerInputBoxes - Simple Input boxes for various variable types Link to comment Share on other sites More sharing options...
junkew Posted November 20, 2019 Share Posted November 20, 2019 Let me know what you would like to see simplified in the uiawrappers I made maybe I can put it in the udf. For udf the convention is to have $__g_ as a prefix so its completely clear its a global variable. It just depends on the full coding style you have to keep it readable, maintainable,etc. How big is your program. Many pros and many cons to use global variables. If you do not like it you could look at https://github.com/genius257/AutoItObject-Internal FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets Link to comment Share on other sites More sharing options...
seadoggie01 Posted November 20, 2019 Author Share Posted November 20, 2019 (edited) I honestly don't understand the UIA wrappers much at all. I tried making a program with them and it took nearly 45 seconds to find a single control when I was as specific as (reasonably) possible. My code looks a lot more like LarsJ's UI automation code, just shortened with function calls. A lot of what I'm doing is really passing properties to get parsed into objects... So saving a Notepad document looks like this: Func __UIW__Testing() WinActivate("Untitled - Notepad") WinWaitActive("Untitled - Notepad") Local $oUIAutomation = _UIW_Create() Local $oDesktop = _UIW_RootObject($oUIAutomation) Local $oNotepad = _UIW_ParseObject($oUIAutomation, $oDesktop, "NAME:Untitled - Notepad;CLASS:Notepad") Local $oNoteEdit = _UIW_ParseObject($oUIAutomation, $oNotepad, "NAME:Text Editor;TYPE:" & $UIA_EditControlTypeId) _UIW_SetValue($oNoteEdit, "temporary file contents") Local $oFileMenu = _UIW_ParseObject($oUIAutomation, $oNotepad, "NAME:File;TYPE:" & $UIA_MenuItemControlTypeId) _UIW_Invoke($oFileMenu) Sleep(250) Local $oSaveAsMenu = _UIW_ParseObject($oUIAutomation, $oNotepad, "NAME:Save As...;TYPE:" & $UIA_MenuItemControlTypeId) _UIW_Invoke($oSaveAsMenu) WinWait("Save As", "") Local $oSaveAs = _UIW_ParseObject($oUIAutomation, $oNotepad, "NAME:Save As;TYPE:" & $UIA_WindowControlTypeId) Local $oFileName = _UIW_ParseObject($oUIAutomation, $oSaveAs, "CLASS:Edit;ACCESSKEY:Alt+n") _UIW_SetValue($oFileName, "temp.txt") Local $oSaveBtn = _UIW_ParseObject($oUIAutomation, $oSaveAs, "CLASS:Button;NAME:Save") _UIW_Invoke($oSaveBtn) EndFunc _UIW_ParseObject splits the property arrays on semicolons, property value pairs on colons, creates an And condition, and finds the first object in the parent. The rest of the code is pretty much just wrappers around the UI Automation object and controls Edit: and with AutoItObject-Internal I would still need to pass the object around a lot or have a global variable... that wouldn't change anything Though I do keep meaning to play with that project, it looks neat. Edited November 20, 2019 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 functionsAcro.au3 UDF - Automating Acrobat ProToDo Finder - Find #ToDo: lines in your scriptsUI-SimpleWrappers UDF - Use UI Automation more Simply-erKeePass UDF - Automate KeePass, a password managerInputBoxes - Simple Input boxes for various variable types Link to comment Share on other sites More sharing options...
junkew Posted November 21, 2019 Share Posted November 21, 2019 The 45 seconds is long but probably means it starts dynamically searching the whole parent hierarchy (or your logging is turned on with all details, writing to a file slows down a lot) I favor the UDF to find an object over a fail to find as frequently I encounter "weird" object hierarhies. In general it means you search in wrong part of the hierarchy. Simplespy will help you with the inital coding and initial hierarchy. Global variable yes, still would be a global object but then within that global object you can have dozens of other properties/variables. So give your global variable the same name of your module and it looks like this $__g_module1_vars=idispatch() $__g_module1_vars.oUIAutomation = _UIW_Create() $__g_module1_vars.oDesktop = _UIW_RootObject() local $oNotepad = _UIW_ParseObject($__g_module1_vars.oDesktop, "NAME:Untitled - Notepad;CLASS:Notepad") whole goal of not having many globals is maintainability of your coding and as best practice in certainly larger projects is to not use them. In your case I feel its perfectly fine to have 1 global instance of the UIA object. Similar to $__g_xlApp=objCreate("excel.application"). In general I try to compare this with: What would I have done in a OO language as Java/C#/... most likely in a class you also would define your $oUIAutomation at class level and not pass it around to every method. In a procedural language you then can handle that only by convention with prefixes as we do not have module level variables. Background UIAWrappers The UIAWrappers are written around UIA findall in general 1 level deep. If its multiple levels deep it will indeed find a lot of objects but still within 2-3 seconds the array is created. (but I have seen longer on large listviews and html pages) Main reason is to have flexible properties implemented like index and indexrelative to go +/-n positions from the found object. frequently needed when you have multiple objects with same name/pattern and you need 2nd object use regular expression matching This is one of the things I miss most in multilanguage testing I can use controltype:=((button)|(knop)) to match in english and in dutch a button class or more logical example name:=((Notepad.*)|(Kladblok.*)) I will put on my long list to make UIA wrappers more flexible If findstring does not contain (*,?,index,..........) then split properties and do a find with and conditions. FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets Link to comment Share on other sites More sharing options...
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