Jump to content

TSR80

Members
  • Posts

    13
  • Joined

  • Last visited

Everything posted by TSR80

  1. Junkew, I think some of your functions should be updated to support caching (see the MSDN documentation here) . For example, in my code, I would like to respond to a window created event by finding an object in the window and also caching the values of AutomationId properties of children of the object. Then, when determining the AutomationId for these child objects later, I won't have to use a further cross-process communication. Does that make sense? I think some of your functions can be expanded pretty easily to include a Boolean parameter for specifying whether you wish to make a cached call or not. But it looks like some supporting functions would be needed to activate the cache request. What do you think?
  2. Thanks for trying to figure that one out LarsJ. I guess it's not essential to be able read that value right now. I think it could help with performance though. I wonder is there is something wrong with the way the function handler is defined or being added? I'm glad my code for the propertychanged event handler is working for you as well!
  3. Thanks LarsJ! You saved me a lot of time with the safearray UDF. I'm still not sure how to correctly read the variant $newValue parameter that is passed into my oIUIAutomationPropertyChangedEventHandler_HandlePropertyChangedEvent event handler. (See post #337.) Any idea how to read that value?
  4. BINGO! You can pass the $pRuntimeID parameter directly to the SafeArrayGetElement function defined in SafeArray.au3. It looks like there is an incorrectly-specified type in that function though. According to the MSDN documentation, the HRESULT returned by the SafeArrayGetElement function in the ole32.dll is a long, not an int. So I made the following change to the DllCall line in the SafeArrayGetElement function in SafeArray.au3: I changed Local $aRet = DllCall( "oleaut32.dll", "int", "SafeArrayGetElement", "ptr", $pSafeArray, "long*", $iIndex, $sType, 0) to Local $aRet = DllCall( "oleaut32.dll", "long", "SafeArrayGetElement", "ptr", $pSafeArray, "long*", $iIndex, $sType, 0) Here's some sample code for my event handler (not compilable): Func oIUIAutomationStructureChangedEventHandler_HandleStructureChangedEvent( $pSelf, $pSender, $iChangeType, $pRuntimeId ) ; Ret: long Par: ptr;long;ptr # Local $oSender = ObjCreateInterface( $pSender, $sIID_IUIAutomationElement, $dtagIUIAutomationElement ) $oSender.AddRef() ; Ignore events that aren't related to the processes associated with your executable. If StringInStr(__WinAPI_GetProcessFileName(_UIA_getPropertyValue( $oSender, $UIA_ProcessIdPropertyId )), '<filename.exe>') Then ; ConsoleWrite( @CRLF & "oIUIAutomationStructureChangedEventHandler_HandleStructureChangedEvent: " & $pSender & " " & $iChangeType & @CRLF ) Switch $iChangeType Case $StructureChangeType_ChildAdded ; ConsoleWrite( " StructureChangeType=ChildAdded: " & @CRLF ) ; $StructureChangeType_ChildRemoved is the only $iChangeType for which the $pRuntimeId parameter is not void. Case $StructureChangeType_ChildRemoved ; ConsoleWrite( " StructureChangeType=ChildRemoved: " & @CRLF ) Local $sAutomationIdPropertyValue = _UIA_getPropertyValue( $oSender, $UIA_AutomationIdPropertyId) ; Make sure this is the parent you are interested in (e.g., check the AutomationId property of $oSender. Local $sAutomationPropertyValue = _UIA_getPropertyValue( $oSender, $UIA_AutomationIdPropertyId )f If ($sAutomationIdPropertyValue = "<propertyvalue>") Then Local $pValue0, $pValue1, $pValue2 ; Get the three values referenced from the pRuntimeId SAFEARRAY. SafeArrayGetElement( $pRuntimeId, 0, $pValue0 ) ; ConsoleWrite($pValue0 & @CRLF) SafeArrayGetElement( $pRuntimeId, 1, $pValue1 ) ; ConsoleWrite($pValue1 & @CRLF) SafeArrayGetElement( $pRuntimeId, 2, $pValue2 ) ; ConsoleWrite($pValue0 & @CRLF) ; Make the format of the values match the format of the string returned from _UIA_getPropertyValue( $oSender, $UIA_RunTimeIdPropertyId (called when the row is added) Local $sConstructedRunTimeId = $pValue0 & ";" & $pValue1 & ";" & $pValue2 ; Here, do matching of $sContructionRunTimeId to previous RuntimeIDs collected EndIf Case $StructureChangeType_ChildrenInvalidated ; ConsoleWrite( " StructureChangeType=ChildrenInvalidated: " & @CRLF ) Case $StructureChangeType_ChildrenBulkAdded ; ConsoleWrite( " StructureChangeType=ChildrednBulkAdded: " & @CRLF ) Case $StructureChangeType_ChildrenBulkRemoved ; ConsoleWrite( " StructureChangeType=ChildrenBulkRemoved: " & @CRLF ) Case $StructureChangeType_ChildrenReordered ; ConsoleWrite( " StructureChangeType=ChildrenReordered: " & @CRLF ) EndSwitch EndIf Return $S_OK EndFunc
  5. Aha. It looks like LarsJ may have answered my question back in post #172. I should be able to access the elements of the safe array using the safearray UDF. I'll let you know if this works.
  6. I have yet another question that I'm hoping somebody (Junkew?) can answer for me. I hope I'm not being too much of a bother! Using inspect.exe, I can view the RuntimeId property of each row in a grid control. According to the MSDN documentation, the RuntimeId property is an array of three int32 values. So, if I get the value of the RuntimeId property of a particular row and write it to the console, it is displayed like this: "7;4988;63749147." If I view the same RuntimeId property of the same row in inspect.exe, it is displayed like this: [7.137C.3CCBC1B]. In other words, inspect.exe is just showing me the hexadecimal values of each of the three integers, whereas the console is showing me the decimal values of the three integers. So far so good. Now when a row is removed from the grid, my structurechanged eventhandler is called. Here is the prototype of the function, as taken from the examples: Func oIUIAutomationStructureChangedEventHandler_HandleStructureChangedEvent( $pSelf, $pSender, $iChangeType, $pRuntimeId ) ; Ret: long Par: ptr;long;ptr According to the MSDN documentation, when the iChangeType indicates a child has been removed, the pRuntimeId parameter is set to the RuntimeId of the child that was removed. Thus, to determine which row has been removed from my grid control, I would like to match the pRuntimeId parameter that is passed into the event handler (and which also identifies the RuntimeId of the object that has been removed) to one of RuntimeIds of the rows I have previously identified as having been added to the grid control. However, the pRuntimeId is a pointer to the RuntimeId. So, for example, printing the value of the pRuntimeId parameter to the console gives me a hexadecimal value that I think is the address of the pointer, not the values of the three integers that the pointer is pointing to. So I get something like this when I print the value of the pRuntimeId parameter of the event handler to the console: 0x042BC8A8. How do I get the three integer values that the pointer is pointing to so that I can do the comparison in my event handler? Once I'm able to get the three integer values from the pRuntimeId pointer passed into the event handler, I think I'll be able to use the IUIAutomation::CompareRuntimeIds method (in conjunction with the safearray UDF) to do the comparison. But I need to get the values from the pointer first. This would be relatively straightforward in C, but I'm not understanding how to do it in AutoIt. I believe an answer to this question might also solve the problem I noted with getting the value of a VARIANT parameter that is passed into a different event handler (see post #337).
  7. Oh, what I meant was that I can visually see the values that I want to read into my script in the grid control of the application. Using inspect.exe, I can also navigate to the grid control (ControlType = UIADataGridControlTypeId) and its children (including UIA data item control type and some custom control types). However, none of the properties of any of the objects I can navigate to in the object tree contain the values I can visually see in the grid control. Thus, I can't figure out a way to load the values into my script. I'll try some of the other tools to see if there might be additional data that is not being shown in inspect.exe. Thanks!
  8. Hi Junkew, The problem is that I cannot find the info in the automation objects through inspect.exe or Simple UI Spy. I can only see the values through visual inspection of the grid control in the user interface.
  9. 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?
  10. 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?
  11. 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
  12. 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.
  13. 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!
×
×
  • Create New...