Jump to content

UDF Global Main object

Recommended Posts

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.

Share this post

Link to post
Share on other sites

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 


Share this post

Link to post
Share on other sites

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)
    Local $oSaveAsMenu = _UIW_ParseObject($oUIAutomation, $oNotepad, "NAME:Save As...;TYPE:" & $UIA_MenuItemControlTypeId)

    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_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 by seadoggie01

All my code provided is Public Domain... but it may not work. ;) Use it, change it, break it, whatever you want.

Share this post

Link to post
Share on other sites

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

Share this post

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

  • Create New...