Jump to content
Sign in to follow this  

How to get the child and control it with MSAA

Recommended Posts

I want to use AutoIt and MSAA to test the Calulator for my first step to learn the MSAA

The goal to get the button and try to click it

Now, I can use "AccessibleObjectFromPoint" to get the button, the codes are

Opt("MustDeclareVars", 1)
Opt("GUIOnEventMode", 1)

Global $oMyError = ObjEvent("AutoIt.Error", "MyErrFunc")

Global Const $hOLEACC = DllOpen("oleacc.dll")


Global $aMousePos, $aCall

While 1
    $aMousePos = MouseGetPos()
    $aCall = DllCall($hOLEACC, "int", "AccessibleObjectFromPoint", _
            "int", $aMousePos[0], _
            "int", $aMousePos[1], _
            "idispatch*", 0, _
            "ptr*", 0)

    If @error Then ContinueLoop

    If IsObj($aCall[3]) Then        
        ConsoleWrite("Title: " & $aCall[3] .accName & "       Child count: " & $aCall[3] .accChildCount & @CRLF)
        If $aCall[3].accName == "3" Then
            ConsoleWrite("accName: " & $aCall[3].accName & @CRLF)       
            ConsoleWrite("accRole: " & $aCall[3].accRole & @CRLF)
            ConsoleWrite("accState: " & $aCall[3].accState & @CRLF)     
            $aCall[3].accDoDefaultAction(); it can work
        ConsoleWrite("! NOT OBJECT" & @CRLF)



Func MyErrFunc()
    ConsoleWrite("!COM Error!   " & "Number is: " & Hex($oMyError.number, 8) & "  description is: " & $oMyError.windescription & @CRLF)
EndFunc   ;==>MyErrFunc

Func _Quit()
EndFunc   ;==>_Quit

But, the "AccessibleObjectFromPoint" is not my choice, because it must need the user uses mouse hove the button.

The "AccessibleObjectFromWindow" looks like my need, but I can not get the button, I only get the Calucator

How to get the button? use the acc_getChild? I have no any idea how to use it in AutoIt

The following is the codes use "AccessibleObjectFromPoint"

#include <WinAPI.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Global $oMyError = ObjEvent("AutoIt.Error", "_ErrFunc")

Global $hOLEACC = DllOpen("oleacc.dll")

Local $hWnd = ControlGetHandle("[CLASS:SciCalc]", "", "")

; New function
Global $oAccessibleObject = _AccessibleObjectFromWindow($hWnd)

; Gained:
If IsObj($oAccessibleObject) Then
    ConsoleWrite("accName: " & $oAccessibleObject.accName & @CRLF)
    ConsoleWrite("accRole: " & $oAccessibleObject.accRole & @CRLF)  
    ConsoleWrite("accState: " & $oAccessibleObject.accState & @CRLF)


Func _GetObjectWinHandle($oObject)

    Local $aCall = DllCall("oleacc.dll", "int", "WindowFromAccessibleObject", _
            "idispatch", $oObject, _
            "hwnd*", 0)

    If @error Or $aCall[0] Then
        Return SetError(1, 0, 0)

    Return $aCall[2]

EndFunc   ;==>_GetObjectWinHandle

Func _AccessibleObjectFromWindow($hWnd)

    Local $sIID_IAccessible = "{618736E0-3C3D-11CF-810C-00AA00389B71}"
    Local $tGUID = _WinAPI_GUIDFromString($sIID_IAccessible)
    Local $pGUID = DllStructGetPtr($tGUID)

    Local $aCall = DllCall($hOLEACC, "int", "AccessibleObjectFromWindow", _
            "hwnd", $hWnd, _
            "dword", 0, _ ; OBJID_WINDOW
            "ptr", $pGUID, _
            "idispatch*", 0)

    If @error Or $aCall[0] Then
        Return SetError(1, 0, 0)

    Return $aCall[4]

EndFunc   ;==>_AccessibleObjectFromWindow

Func _ErrFunc()

    ConsoleWrite("--- COM Error, number = " & Ptr($oMyError.number) & ", description: " & $oMyError.windescription)

EndFunc   ;==>_ErrFunc

Func _Quit()


EndFunc   ;==>_Quit

Share this post

Link to post
Share on other sites

Did you try ControlGetHandle() on the button you wanted? For example, the "=" button would be something like:

$hEquButton = ControlGetHandle("[CLASS:SciCalc]", "", "[CLASS:Button; INSTANCE:65]")
$oAccEquButton = _AccessibleObjectFromWindow($hEquButton)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post

Link to post
Share on other sites

I used the ControlGetHandle("[CLASS:SciCalc]", "", "[CLASS:Button; INSTANCE:15]") to get the obj, but the result is window, not the button,

That mean the role text of [CLASS:Button; INSTANCE:15] is "window", it has not default action

the role text of the button should be "PushButton" and the default action is "Push"

How can get the button, not the window

Thanks in advanced

Share this post

Link to post
Share on other sites

If you insist on that approach then find AutoItObject.au3 and use _AutoItObject_WrapperCreate() function to wrap IAccessible interface.

In the package you'll find several examples of how's that done with some other interfaces.




Share this post

Link to post
Share on other sites

read this topic carefully and you have the working examples


I looked this topic, but they used "AccessibleObjectFromPoint" to get the object, not the "AccessibleObjectFromWindow".

I want to test the Caculator, get the number button and click them, if use "AccessibleObjectFromPoint", it need the operation of users.

I think I don't know the button position, just know the ClassName, InstanceName.

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
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...