Jump to content

IUIAutomation MS framework automate chrome, FF, IE, ....


junkew
 Share

Recommended Posts

This is the version with the "click", the expected result is when you click an item ( only one at once ) you have the ConsoleWrite with the name, whatever folder is opened

The bugs i don't know to solve:

2) The errors like:

$oSHFolderView = $oIEObject.Document
$oSHFolderView = $oIEObject.Document^ ERROR

or

$oIEObject.HWND 

$oIEObject.HWND^ ERROR

When don't find a working folder ( i have add the _CorrectClass but seems not useful at 100% )

Thanks for any help to accomplish this script ( and if is possible without the click and only with the hovering but one things at time )

EDIT: For the errors i have opened another thread

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to comment
Share on other sites

whats the simplespy giving as output properties and source for a "click"

normally you could just replace "click" with "getvalue"

Please follow steps in first post with simplespy and post your output in a new thread of general help and support section

Your goal with hovering and showing it you can get from simplespy.au3 logic as thats triggered by ctrl+w and based on mouseposition retrieves the handle to the element and after that you can get all properties of that specific element (and one of them is name/text etc)

Link to comment
Share on other sites

  • 1 month later...
  • 2 weeks later...
  • Moderators

I downloaded UIA 5, I need to move the AU3 files it contains to the "Includes" folder in AI right?

Just put them int he same directory your script is running in.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

  • 3 weeks later...

Depends on your cpu and how you write your scripts.

Its hard to say with the information you give. Whats the logfile telling you.

The algorithm to determine the right control is not perfect and can be slow when its not finding it easily in the object hierarchy. When not immediately found it will try the parent and all its descendants (and if not found repeats with grandparent up until the desktop)

The fallback algorithm is not perfect (and I think it has defects in it at the moment)

So please show me which demo you try to run and in which language of windows you are and whats the logfile telling you

Link to comment
Share on other sites

My computer has an i5 2500k and a SSD

Here is the code I'm running :

#include "UIAWrappers.au3"

AutoItSetOption("MustDeclareVars", 1)

;~ Start the application
run("notepad.exe")

#REGION UIA_LOGICAL_NAMES
;~ Give logical names
_UIA_setVar("notepad.mainwindow","title:=((.*Bloc-notes)|(.*Notepad));classname:=Notepad")
_UIA_setVar("notepad.mainwindow.edit","title:=;classname:=Edit")

;~ When closing when text is changed
_UIA_setVar("Notepad.closewindow","title:=((Bloc-notes)|(Notepad));classname:=#32770")
;~ The three buttons
_UIA_setVar("Notepad.closewindow.Save","title:=Sauvegarder;classname:=CCPushButton")
_UIA_setVar("Notepad.closewindow.Don'tSave","title:=((Don't Save)|(Ne pas enregistrer));classname:=CCPushButton")
_UIA_setVar("Notepad.closewindow.Cancel","title:=((Cancel)|(Annuler));classname:=CCPushButton")
#ENDREGION

#REGION ACTIONS
;~ Do some actions on the logical named objects
_UIA_action("notepad.mainwindow","setfocus")
_UIA_action("notepad.mainwindow","move",300,300)
_UIA_action("notepad.mainwindow","resize",300,300)
_UIA_action("notepad.mainwindow","minimize",300,300)
_UIA_action("notepad.mainwindow","maximize",300,300)
_UIA_action("notepad.mainwindow","resize",400,400)

_UIA_action("notepad.mainwindow.edit","setfocus")
_UIA_action("notepad.mainwindow.edit","setvalue","set value: hello world")
_UIA_action("notepad.mainwindow.edit","type","type command: hello world")

_UIA_action("notepad.mainwindow","close",400,400)
if _UIA_action("Notepad.closewindow","exists") Then
    _UIA_action("Notepad.closewindow.Don'tSave","click")
Else
EndIf
#ENDREGION 

It took 17s to finish this !!!

I'm sending you the log by private message

Edit : OOps can't send private message, here is the log file : https://www.dropbox.com/s/pfewretume8c7ob/20150111-212420074.XML?dl=0

Edited by JorisB
Link to comment
Share on other sites

Hi all,

I'm new to the forum and having a blast catching up with the latest in automation scripting. 

I'm in the process of trying to using AutoIt to automate some tasks associated with a client that uses custom user interface components.  I have been unable to manipulate these custom components using standard AutoIt scripts, but the IUIAutomation wrapper is working!

I originally discovered that the elements in the client were accessible using the Inspect Object (inspect.exe) application that comes with the Windows Kits for Windows 8.1.  I have been using both inspect.exe and Simple UIA Spy to get information on the components in the client that I wish to automate.

I have some noobie questions that I'm hoping some of the experts here can answer.

First, I'm running AutoIt under Windows 8.1 (64-bit).  I'm unsure of whether the client I'm attempting to automate is 32-bit or 64-bit.  With this configuration, is there anything I need to be aware of or careful with when creating a script that uses the IUIAutomation wrapper?

Second, the source code generated by Simple UIA Spy for a UI component in the client that I wish to access gives me a list of code statements for getting objects for the ancestors of the client and says "First find the object in the parent before you can do something."  This approach seems different from the latest notepad and calc examples, which use setvar and _UIA_Action without explicitly getting an object first. Why are there two different approaches and which approach is the best approach to use?  (In my test code, I seem to be having better luck using the approach of explicitly getting the object before acting on it.)

Third, is there an example script that shows how to retrieve data from a control having the UIA_DataGridControlTypeId control type?

Fourth, is there some support in the wrapper for responding to IUIAutomation events?  For example, currently I'm using code like the sample code shown in the help topic for _WinAPI_SetWinEventHook function.  Can I respond to IUIAutomation events using the same code?  Or is there another way?

Thanks in advance for any insights you can provide!

 

 

 

 

Link to comment
Share on other sites

0. 17 seconds is not an issue for me, speed is more related in my perspective compared to a human doing it manually. But I agree its a little slow and I will investigate that and most likely is related to the searching algorithm in my au3 framework. IUIAutomation native commands should be able to do it quicker (but more code and less flexible/recovery)

1. 32/64 bits not sure no problems so far but in CUIAutomation definition I can imagine that there are incorrect definitions for 32/64 bits (I have not hit all components/definitions)

2. Next simple spy will deliver the different approaches source directly. The framework itselfs tries to be smarter as 98% of the time the first action is on a mainwindow and 2nd, 3rd actions are within the object of the first action and as such framework tries to remember smartly the context to operate in. The concept of UIA_Setvar is nothing more then giving objects meaningfull names instead of the technical identification names.
And I preferr my technical definitions to be in a different place compared to the actual script for easy maintenance when developers are changing id's of controls etc.

Getting objects directly or use the searchlogic of my framework is a balance between speed, flexibility, readability, maintainability, complexity, ......

Quick and Dirty straightforward probably the source of the simple spy is good enough but if you have dozens of scripts you will be having need for more structure (i read my scripts from excelsheets which transforms to the UIA_Setvar/UIA_Action logic))

3. No example from me but If you search on internet for C/C#/C++ examples you can probably transform them to this framework

4. The CUIAutomation is having the definitions for events and there are some nice examples in the examples zip.

Link to comment
Share on other sites

Hi Junkew,

Thank you for your prompt response and for all of the work you have been doing to support UIAutomation in AutoIt!  I should've reviewed the examples before asking my question about events.  Now I have done so and I have a few more questions that I'm hoping you can answer.  Some of these probably fall into the general "programming for windows" category, so I hope I'm not being too much of a bother.

As I mentioned, the current problem I'm trying to solve is reading the contents of a custom grid control of a client that exposes the grid control via the UIAutomation interfaces.  (I can see the grid control in the UIAutomation object tree using both the MS inspect.exe tool and the Simple UIA Spy tool.)

Question 1: Can I use the sample code for one of the UIAutomation event handlers as a basis to solve my problem?

For example, if I had an object in my AutoIt script that corresponded to the Windows DataGridView Class for the grid control, I believe I could simply override an event handler in a derived class to respond to grid control events, such as the DataGridView.CellValuePushed event or the RowsAdded event. 

However, I'm not sure how these standard Windows grid control events correspond to the UIAutomation events for the grid control.

It looks like there is an example for each of the possible UIAutomation callback Interfaces, which include IUIAutomationFocusChangedEventHandler, IUIAutomationPropertyChangedEventHandler, IUIAutomationStructureChangedEventHandler, and UIAutomationEventHandler.

Which of these examples, if any, should I be using to approximate handling events as I would with a standard Windows DataGridView object?  It would be ideal to read the data that is added to the grid control at the very moment it is being added to the grid control, which makes me think I should be using the StructureChangedEventHandler.  Is this right?

Is there a parameter coming into the StructureChangedEvent handler that would allow me to get the values of each cell of a new row that is being added to the grid control?  Or perhaps one that would let me get the values of each cell that is being added or changed?

Question 2: How do I determine whether to use UIAutomation, IAccessibility, or MSAA event handlers?

Given that my client appears to support the UIAutomation interfaces, it seems like I should only need to use the UIAutomation event handlers.  But perhaps one of the older types of interfaces would work better for what I'm trying to do.  How do I figure out which of the various sets of event handler interfaces to use? 

Question 3: How does COM relate to the Accessibility API?

I'm just unsure how COM relates to UIAutomation or if maybe I should be using COM objects in my script?

Question 4: As an alternative or in addition to using event handlers to solve my problem, couldn't I use the UIAutomation object corresponding to the grid control to get access to all of its child elements?

Apparently the grid control supports the IGridProvider interface, which has a GetItem method to get the UIAutomation provider for a specific cell (see, e.g., http://msdn.microsoft.com/en-us/library/system.windows.automation.provider.igridprovider.getitem(v=vs.110).aspx).  So, in theory, I should just be able to iterate over all of the cells of the grid control and read the contents of each cell.  In practice, I'm not sure how to do this though.  Is there a particular example you could point me to that would help me figure this out?

 

I know these are noobie questions and I'm very sorry if these questions are off-topic for this thread.

Thank you again for any guidance you can provide.

Edited by TSR80
Link to comment
Share on other sites

Question 1: Can I use the sample code for one of the UIAutomation event handlers as a basis to solve my problem?

Not sure, personally I work less with events and prefer searching for certain windows / areas myself but my approach is from testautomation / user simulation and as such many things are predictable situations

Question 2: How do I determine whether to use UIAutomation, IAccessibility, or MSAA event handlers?

Does not matter. You should use what suits your situation most. UIAutomation is most flexible but as its a wrapper sometimes over IAccessibility/MSAA you do not get all information

Question 3: How does COM relate to the Accessibility API?

Not although it has the same basics the UIAutomationCore.DLL is not a com component by nature 

see http://msdn.microsoft.com/en-us/library/windows/desktop/dd561882%28v=vs.85%29.aspx

Question 4: As an alternative or in addition to using event handlers to solve my problem, couldn't I use the UIAutomation object corresponding to the grid control to get access to all of its child elements?

I would prefer this approach as you are more in control with your scripts
Link to comment
Share on other sites

Hello,

I am trying to get this working and tried to launch SimpleSpy and ex5_chrome. Both are coming up with this error:  

>"C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.exe" /run /prod /ErrorStdOut /in "\\box574.bluehost.com@SSL@2078\DavWWWRoot\ad\AI\simplespy.au3" /UserParams    
+>14:56:21 Starting AutoIt3Wrapper v.2.1.4.4 SciTE v.3.3.7.0 ;  Keyboard:00000409  OS:WIN_7/Service Pack 1  CPU:X64 OS:X64    Environment(Language:0409  Keyboard:00000409  OS:WIN_7/Service Pack 1  CPU:X64 OS:X64)
>Running AU3Check (3.3.10.2)  from:C:\Program Files (x86)\AutoIt3
"\\box574.bluehost.com@SSL@2078\DavWWWRoot\ad\AI\UIAWrappers.au3"(978,82) : warning: $STR_REGEXPMATCH: possibly used before declaration.
                    $iMatch = StringRegExp($propertyActualValue, $propertyVal, $STR_REGEXPMATCH )
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
"\\box574.bluehost.com@SSL@2078\DavWWWRoot\ad\AI\UIAWrappers.au3"(978,82) : error: $STR_REGEXPMATCH: undeclared global variable.
                    $iMatch = StringRegExp($propertyActualValue, $propertyVal, $STR_REGEXPMATCH )
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
\\box574.bluehost.com@SSL@2078\DavWWWRoot\ad\AI\simplespy.au3 - 1 error(s), 1 warning(s)
!>14:56:22 AU3Check ended. Press F4 to jump to next error.rc:2
+>14:56:22 AutoIt3Wrapper Finished..
>Exit code: 2    Time: 1.112

b6f6636edd.png

Hoping someone might be able to direct me towards my problems... Or at least this problem as I have to many to be solved... Ha! Tyia

-K

Link to comment
Share on other sites

Hi all,
 
Here is an updated version of the IUIAutomationPropertyChangedEventHandler that uses AddPropertyChangedEventHandler instead of AddPropertyChangedEventHandlerNativeArray.
 
Basically I combined the IUIAutomationPropertyChangedEventHandler example from post #112 with the safe arrays of post #135.
 
I ended up testing the IUIAutomationPropertyChangedEventHandler because the application I'm automating was not triggering my event handler for ChangedEventHandlerNativeArray even though I could see the events were being heard by the Windows  Accessible Event Watcher (accevent.exe).
 
When I switched to using the AddPropertyChangedEventHandler (with the pointer to the safe array), I could finally hear the events in my script.

Hopefully this will be useful to someone. 

#include "CUIAutomation2.au3"
#include "SafeArray.au3"

Opt( "MustDeclareVars", 1 )

Global Const $S_OK = 0x00000000
Global Const $E_NOINTERFACE = 0x80004002
Global Const $sIID_IUnknown = "{00000000-0000-0000-C000-000000000046}"

Global $tIUIAutomationPropertyChangedEventHandler, $oIUIAutomationPropertyChangedEventHandler

Global $oUIAutomation

MainFunc()



Func MainFunc()

  $oIUIAutomationPropertyChangedEventHandler = ObjectFromTag( "oIUIAutomationPropertyChangedEventHandler_", $dtagIUIAutomationPropertyChangedEventHandler, $tIUIAutomationPropertyChangedEventHandler, True )
  If Not IsObj( $oIUIAutomationPropertyChangedEventHandler ) Then Return

  $oUIAutomation = ObjCreateInterface( $sCLSID_CUIAutomation, $sIID_IUIAutomation, $dtagIUIAutomation )
  If Not IsObj( $oUIAutomation ) Then Return

  Local $pUIElement
  $oUIAutomation.GetRootElement( $pUIElement ) ; Desktop
  If Not $pUIElement Then Return

#cs
  ; Use this code to call the AddPropertyChangedEventHandlerNativeArray method, which takes a normal array of property identifiers instead of a SAFEARRAY.
  ; Because of threading issues, calling this method instead of AddPropertyChangedEventHandler may lead to unexpected/incomplete results.
  Local $tPropertyArray = DllStructCreate( "int[2]" )
  DllStructSetData( $tPropertyArray, 1, $UIA_NamePropertyId, 1 )
  DllStructSetData( $tPropertyArray, 1, $UIA_ToggleToggleStatePropertyId, 2 )
  $oUIAutomation.AddPropertyChangedEventHandlerNativeArray( $pUIElement, $TreeScope_Descendants, 0, $oIUIAutomationPropertyChangedEventHandler, $tPropertyArray, 2 )
#ce

  ; Use this code to call the AddPropertyChangedEventHandlerNativeArray method, which takes a pointer to a SAFEARRAY of property identifiers.
  ; Because of threading issues, calling this method instead of AddPropertyChangedEventHandler appears to be preferable for automation of some applications.

  ; Create a SAFEARRAY vector having a number of rows equal to the number of property identifiers you will be monitoring for changes
  Local $ptrSafeArray = SafeArrayCreateVector( "int", 2 )

  ; Write SAFEARRAY structure
  Local Const $tagSAFEARRAY = "ushort cDims; ushort fFeatures; ulong cbElements; ulong cLocks; ptr pvData; ulong cElements; long lLbound"
  Local $tSAFEARRAY = DllStructCreate( $tagSAFEARRAY, $ptrSafeArray )

#cs
  ConsoleWrite( @CRLF & "SafeArray structure" & @CRLF )
  ConsoleWrite( "$tSAFEARRAY size       = " & DllStructGetSize( $tSAFEARRAY ) & @CRLF )
  ConsoleWrite( "$tSAFEARRAY cDims      = " & DllStructGetData( $tSAFEARRAY, "cDims" ) & @CRLF )
  ConsoleWrite( "$tSAFEARRAY fFeatures  = " & "0x" & Hex( DllStructGetData( $tSAFEARRAY, "fFeatures" ) ) & @CRLF )
  ConsoleWrite( "$tSAFEARRAY cbElements = " & DllStructGetData( $tSAFEARRAY, "cbElements" ) & @CRLF )
  ConsoleWrite( "$tSAFEARRAY cLocks     = " & DllStructGetData( $tSAFEARRAY, "cLocks" ) & @CRLF )
  ConsoleWrite( "$tSAFEARRAY pvData     = " & DllStructGetData( $tSAFEARRAY, "pvData" ) & @CRLF )
  ConsoleWrite( "$tSAFEARRAY cElements  = " & DllStructGetData( $tSAFEARRAY, "cElements" ) & @CRLF )
  ConsoleWrite( "$tSAFEARRAY lLbound    = " & DllStructGetData( $tSAFEARRAY, "lLbound" ) & @CRLF )
#ce


  ; Put the property identifiers corresponding to the properties you will be monitoring as elements into the SafeArray
  SafeArrayPutElement( $ptrSafeArray, 0, $UIA_NamePropertyId )
  SafeArrayPutElement( $ptrSafeArray, 1, $UIA_AutomationIdPropertyId )

  #cs
  Local $pValue
  ConsoleWrite( @CRLF & "Get the two conditions" & @CRLF )
  SafeArrayGetElement( $ptrSafeArray, 0, $pValue )
  ConsoleWrite( "int 1 = " &  $pValue & @CRLF )
  SafeArrayGetElement( $ptrSafeArray, 1, $pValue )
  ConsoleWrite( "int 2 = " &  $pValue & @CRLF )
  #ce

  ; Add the PropertyChangedEventHandler
  $oUIAutomation.AddPropertyChangedEventHandler( $pUIElement, $TreeScope_Descendants, 0, $oIUIAutomationPropertyChangedEventHandler, Ptr($ptrSafeArray))

  HotKeySet( "{ESC}", "Quit" )

  While Sleep(100)
  WEnd

EndFunc

Func Quit()
  $oIUIAutomationPropertyChangedEventHandler = 0
  DeleteObjectFromTag( $tIUIAutomationPropertyChangedEventHandler )
  SafeArrayDestroy( $ptrSafeArray )
  Exit
EndFunc



Func _UIA_getPropertyValue( $obj, $id )
  Local $vVal
  $obj.GetCurrentPropertyValue( $id, $vVal )
  Return $vVal
EndFunc

Func oIUIAutomationPropertyChangedEventHandler_HandlePropertyChangedEvent( $pSelf, $pSender, $iPropertyId, $newValue ) ; Ret: long  Par: ptr;int;variant
  ConsoleWrite( @CRLF & "oIUIAutomationPropertyChangedEventHandler_HandlePropertyChangedEvent: $iPropertyId = " & $iPropertyId & ", $newValue = " & $newValue & @CRLF )

  Local $oSender = ObjCreateInterface( $pSender, $sIID_IUIAutomationElement, $dtagIUIAutomationElement )
  $oSender.AddRef(  )

  ConsoleWrite( "AutomationId    " & _UIA_getPropertyValue( $oSender, $UIA_AutomationIdPropertyId ) & @CRLF )
  ConsoleWrite( "Handle    " & _UIA_getPropertyValue( $oSender, $UIA_NativeWindowHandlePropertyId ) & @CRLF )
  ConsoleWrite( "Name      " & _UIA_getPropertyValue( $oSender, $UIA_NamePropertyId ) & @CRLF )
  ConsoleWrite( "Class     " & _UIA_getPropertyValue( $oSender, $UIA_ClassNamePropertyId ) & @CRLF )
  ConsoleWrite( "Ctrl type " & _UIA_getPropertyValue( $oSender, $UIA_ControlTypePropertyId ) & @CRLF )
  ConsoleWrite( "Ctrl name " & _UIA_getPropertyValue( $oSender, $UIA_LocalizedControlTypePropertyId ) & @CRLF )
  ConsoleWrite( "Value     " & _UIA_getPropertyValue( $oSender, $UIA_LegacyIAccessibleValuePropertyId ) & @CRLF )

  Return $S_OK
EndFunc

Func oIUIAutomationPropertyChangedEventHandler_QueryInterface( $pSelf, $pRIID, $pObj ) ; Ret: long  Par: ptr;ptr*
  Local $sIID = StringFromGUID( $pRIID )
  If $sIID = $sIID_IUnknown Then
    ConsoleWrite( "oIUIAutomationPropertyChangedEventHandler_QueryInterface: IUnknown" & @CRLF )
    DllStructSetData( DllStructCreate( "ptr", $pObj ), 1, $pSelf )
    Return $S_OK
  ElseIf $sIID = $sIID_IUIAutomationPropertyChangedEventHandler Then
    ConsoleWrite( "oIUIAutomationPropertyChangedEventHandler_QueryInterface: IUIAutomationPropertyChangedEventHandler" & @CRLF )
    DllStructSetData( DllStructCreate( "ptr", $pObj ), 1, $pSelf )
    Return $S_OK
  Else
    ConsoleWrite( "oIUIAutomationPropertyChangedEventHandler_QueryInterface: " & $sIID & @CRLF )
    Return $E_NOINTERFACE
  EndIf
EndFunc

Func oIUIAutomationPropertyChangedEventHandler_AddRef( $pSelf ) ; Ret: ulong
  ConsoleWrite( "oIUIAutomationPropertyChangedEventHandler_AddRef" & @CRLF )
  Return 1
EndFunc

Func oIUIAutomationPropertyChangedEventHandler_Release( $pSelf ) ; Ret: ulong
  ConsoleWrite( "oIUIAutomationPropertyChangedEventHandler_Release" & @CRLF )
  Return 1
EndFunc



Func StringFromGUID( $pGUID )
  Local $aResult = DllCall( "ole32.dll", "int", "StringFromGUID2", "struct*", $pGUID, "wstr", "", "int", 40 )
  If @error Then Return SetError( @error, @extended, "" )
  Return SetExtended( $aResult[0], $aResult[2] )
EndFunc



Func ObjectFromTag($sFunctionPrefix, $tagInterface, ByRef $tInterface, $fPrint = False, $bIsUnknown = Default, $sIID = "{00000000-0000-0000-C000-000000000046}") ; last param is IID_IUnknown by default
    If $bIsUnknown = Default Then $bIsUnknown = True
    Local $sInterface = $tagInterface ; copy interface description
    Local $tagIUnknown = "QueryInterface hresult(ptr;ptr*);" & _
            "AddRef dword();" & _
            "Release dword();"
    ; Adding IUnknown methods
    If $bIsUnknown Then $tagInterface = $tagIUnknown & $tagInterface
    ; Below line is really simple even though it looks super complex. It's just written weird to fit in one line, not to steal your attention
    Local $aMethods = StringSplit(StringReplace(StringReplace(StringReplace(StringReplace(StringTrimRight(StringReplace(StringRegExpReplace(StringRegExpReplace($tagInterface, "\w+\*", "ptr"), "\h*(\w+)\h*(\w+\*?)\h*(\((.*?)\))\h*(;|;*\z)", "$1\|$2;$4" & @LF), ";" & @LF, @LF), 1), "object", "idispatch"), "hresult", "long"), "bstr", "ptr"), "variant", "ptr"), @LF, 3)
    Local $iUbound = UBound($aMethods)
    Local $sMethod, $aSplit, $sNamePart, $aTagPart, $sTagPart, $sRet, $sParams, $hCallback
    ; Allocation
    $tInterface = DllStructCreate("int RefCount;int Size;ptr Object;ptr Methods[" & $iUbound & "];int_ptr Callbacks[" & $iUbound & "];ulong_ptr Slots[16]") ; 16 pointer sized elements more to create space for possible private props
    If @error Then Return SetError(1, 0, 0)
    For $i = 0 To $iUbound - 1
        $aSplit = StringSplit($aMethods[$i], "|", 2)
        If UBound($aSplit) <> 2 Then ReDim $aSplit[2]
        $sNamePart = $aSplit[0]
        $sTagPart = $aSplit[1]
        $sMethod = $sFunctionPrefix & $sNamePart
        If $fPrint Then
            Local $iPar = StringInStr( $sTagPart, ";", 2 ), $t
            If $iPar Then
                $t = "Ret: " & StringLeft( $sTagPart, $iPar - 1 ) & "  " & _
                     "Par: " & StringRight( $sTagPart, StringLen( $sTagPart ) - $iPar )
            Else
                $t = "Ret: " & $sTagPart
            EndIf
            Local $s = "Func " & $sMethod & _
                "( $pSelf ) ; " & $t & @CRLF & _
                "EndFunc" & @CRLF
            ConsoleWrite( $s )
        EndIf
        $aTagPart = StringSplit($sTagPart, ";", 2)
        $sRet = $aTagPart[0]
        $sParams = StringReplace($sTagPart, $sRet, "", 1)
        $sParams = "ptr" & $sParams
        $hCallback = DllCallbackRegister($sMethod, $sRet, $sParams)
        ConsoleWrite(@error & @CRLF & @CRLF)
        DllStructSetData($tInterface, "Methods", DllCallbackGetPtr($hCallback), $i + 1) ; save callback pointer
        DllStructSetData($tInterface, "Callbacks", $hCallback, $i + 1) ; save callback handle
    Next
    DllStructSetData($tInterface, "RefCount", 1) ; initial ref count is 1
    DllStructSetData($tInterface, "Size", $iUbound) ; number of interface methods
    DllStructSetData($tInterface, "Object", DllStructGetPtr($tInterface, "Methods")) ; Interface method pointers
    Return ObjCreateInterface(DllStructGetPtr($tInterface, "Object"), $sIID, $sInterface, $bIsUnknown) ; pointer that's wrapped into object
EndFunc

Func DeleteObjectFromTag(ByRef $tInterface)
    For $i = 1 To DllStructGetData($tInterface, "Size")
        DllCallbackFree(DllStructGetData($tInterface, "Callbacks", $i))
    Next
    $tInterface = 0
EndFunc
Edited by TSR80
Link to comment
Share on other sites

On a related note, why is the $newValue parameter of the oIUIAutomationPropertyChangedEventHandler_HandlePropertyChangedEvent function always being set to 0x00000008?  I'm guessing it's a result of the parameter being a Windows VARIANT type. 

Here's the output on my console:

oIUIAutomationPropertyChangedEventHandler_HandlePropertyChangedEvent: $iPropertyId = 30005, $newValue = 0x00000008
  Handle    0
  Name      4
  Class     TextBlock
  Ctrl type 50020
  Ctrl name text
  Value

The above output shows that the value I'm monitoring (the Name property, as shown by $iPropertyId parameter being set to 30005) actually gets a new value of "4".  However, the $newValue parameter is  0x00000008, not "4".  In fact, the $newValue parameter seems to be set to 0x00000008 no matter what the actual new value of the property turns out to be through subsequent inspection of the oSender object.

Is it possible to examine the $newValue parameter to determine the new value without actually reading the Name property of the oSender object?

Edited by TSR80
Link to comment
Share on other sites

@Keltset: try the help file example on stringregexp to run first

#include <MsgBoxConstants.au3>
#include <StringConstants.au3>

Local $aArray = 0, _
        $iOffset = 1
While 1
    $aArray = StringRegExp('<test>a</test> <test>b</test> <test>c</Test>', '(?i)<test>(.*?)</test>', $STR_REGEXPARRAYMATCH, $iOffset)
    If @error Then ExitLoop
    $iOffset = @extended
    For $i = 0 To UBound($aArray) - 1
        MsgBox($MB_SYSTEMMODAL, "RegExp Test with Option 1 - " & $i, $aArray[$i])
    Next
WEnd

@TSR80: Thx for the example will use it in reference when updating with new version in the future

Link to comment
Share on other sites

Darn, I've spent many hours trying to solve the problem of accessing values in cells of a custom grid control of the application I'm trying to automate.  Objects corresponding to the grid control itself and data items of the grid control are visible in the UIAutomation tree.  However, viewing the properties of these UIAUtomation objects using the Spy tools shows that none of the objects exposes the underlying values of the cells in the grid.  I'm stumped.   

Is there any way to get at data that is visually associated with an UIAutomation grid control or data item object (e.g., seen in cells of the grid control by a user of the application), but that is not exposed in any properties of the object?

Edited by TSR80
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...