junkew

IAccessible/IAccessible2

9 posts in this topic

I need some help in fixing this on W10 / 64 bits system either compiled with #AutoIt3Wrapper_UseX64=Y or #AutoIt3Wrapper_UseX64=N

@Larsj : Did you ever migrate this to W10 /64 bits system. Post #154

I tried in different ways on $tagVARIANT lengths but application stops. I did partly get it running for spied object when useX64=N but then quickly after that fails on child objects when using iAccessible

 

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Hello. I did just a little adjutments. Working for me in Windows 7x86 and Windows 10 x64 (compiled x64 and x86 Version)

 

#AutoIt3Wrapper_UseX64=Y
#RequireAdmin
#include "CUIAutomation2.au3"
#include "MSAccessibility.au3"
#include "ISimpleDOM.au3"
#include <Array.au3>

Opt("MustDeclareVars", 1)

Global $aInfo[10000], $iInfo = 0

MainFunc()


Func MainFunc()

    HotKeySet("^w", "GetWindowInfo")
    HotKeySet("{ESC}", "Close")

    While Sleep(100)
    WEnd

EndFunc   ;==>MainFunc


Func GetWindowInfo()
    Local $aMousePos = MouseGetPos(), $pObject, $tVarChild, $vt, $err = 0
    If AccessibleObjectFromPoint($aMousePos[0], $aMousePos[1], $pObject, $tVarChild) = $S_OK Then
        $vt = BitAND(DllStructGetData($tVarChild, 1, 1), 0xFFFF)
        If $vt = $VT_I4 Then
            Local $oObject, $hWnd, $sName = ""
            If WindowFromAccessibleObject($pObject, $hWnd) = $S_OK Then

                AccessibleObjectFromWindow($hWnd, $OBJID_CLIENT, $tIID_IAccessible, $pObject)
                $oObject = ObjCreateInterface($pObject, $sIID_IAccessible, $dtagIAccessible)

                ; Get parent objects to top window
                Local $pParent, $pPrev, $oPrev, $iRole
                Do
                    $pPrev = $pParent
                    $oPrev = $oObject
                    If IsObj($oObject) Then
                        $oObject.get_accParent($pParent)
                        $oObject = ObjCreateInterface($pParent, $sIID_IAccessible, $dtagIAccessible)
                    EndIf

                    If IsObj($oObject) Then
                        $oObject.get_accName($CHILDID_SELF, $sName)
                    EndIf

                Until String($sName) = "Escritorio";"Desktop"

                ; Info for top window (previous to desktop)
                PrintElementInfoToArray($pPrev, $oPrev, $CHILDID_SELF, "")

                ; Info for child objects of the top window
                If $oPrev.get_accRole($CHILDID_SELF, $iRole) = $S_OK And $iRole = $ROLE_SYSTEM_WINDOW Then
                    WindowFromAccessibleObject($pPrev, $hWnd)
                    PrintWindowObjects($hWnd)
                Else
                    $err = 1
                EndIf

            Else
                $err = 1
            EndIf
        Else
            $err = 1
        EndIf
    Else
        $err = 1
    EndIf
    If $err Then _
            MsgBox(0, "ISimpleDOM interfaces", _
            "AccessibleObjectFromPoint failed." & @CRLF & _
            "Try another point e.g. the window title bar.")
EndFunc   ;==>GetWindowInfo


Func PrintWindowObjects($hWindow)

    ; Object from window
    Local $pWindow, $oWindow
    AccessibleObjectFromWindow($hWindow, $OBJID_CLIENT, $tIID_IAccessible, $pWindow)
    $oWindow = ObjCreateInterface($pWindow, $sIID_IAccessible, $dtagIAccessible)
    If Not IsObj($oWindow) Then Return

    ; Get window objects
    WalkTreeWithAccessibleChildren($pWindow, 0, 8)

    ; Print window objects
    ReDim $aInfo[$iInfo]
    _ArrayDisplay($aInfo, "ISimpleDOM interfaces")
    ReDim $aInfo[10000]
    $iInfo = 0

EndFunc   ;==>PrintWindowObjects


Func WalkTreeWithAccessibleChildren($pAcc, $iLevel, $iLevels = 0)

    If $iLevels And $iLevel = $iLevels Then Return

    ; Create object
    Local $oAcc = ObjCreateInterface($pAcc, $sIID_IAccessible, $dtagIAccessible)
    If Not IsObj($oAcc) Then Return
    $oAcc.AddRef()

    ; Indentation
    Local $sIndent = ""
    For $i = 0 To $iLevel - 1
        $sIndent &= "    "
    Next

    Local $iChildCount, $iReturnCount, $tVarChildren

    ; Get children
    If $oAcc.get_accChildCount($iChildCount) Or Not $iChildCount Then Return
    If AccessibleChildren($pAcc, 0, $iChildCount, $tVarChildren, $iReturnCount) Then Return

    Local $vt, $pChildObj, $oChildObj
    Local $pService, $oService, $pISimpleDOMNode, $oISimpleDOMNode, $pISimpleDOM, $oISimpleDOM

    ; $oISimpleDOMNode.nodeInfo
    Local $sNodeName, $iNameSpaceID, $sNodeValue, $iNumChildren, $iUniqueID, $iNodeType, $sInnerHTML

    ; $oISimpleDOMNode.attributes
    Local $iMaxAttribs = 100, $iNumAttribs
    Local $tAttribNames = DllStructCreate("ptr[" & $iMaxAttribs & "]"), $sAttribName
    Local $tNameSpaceIDs = DllStructCreate("short[" & $iMaxAttribs & "]"), $iNameSpaceID
    Local $tAttribValues = DllStructCreate("ptr[" & $iMaxAttribs & "]"), $sAttribValue

    ; $oISimpleDOMNode.computedStyle
    Local $iMaxStyleProperties = 100, $iNumStyleProperties
    Local $tStyleProperties = DllStructCreate("ptr[" & $iMaxStyleProperties & "]"), $sStyleProperty
    Local $tStyleValues = DllStructCreate("ptr[" & $iMaxStyleProperties & "]"), $sStyleValue

    ; For each child
    For $i = 1 To $iReturnCount

        ; $tVarChildren is an array of VARIANTs with information about the children
        $vt = BitAND(DllStructGetData($tVarChildren, $i, 1), 0xFFFF)

        If $vt = $VT_DISPATCH Then



            ; Child object; get correct ptr x64 or x86 version
            Local $tVariant = DllStructCreate("word vt;word r1;word r2;word r3;ptr data; ptr;", DllStructGetPtr($tVarChildren, $i))
            $pChildObj = DllStructGetData($tVariant, 5)

            ;this is wrong. You will never get the x64 ptr
;~          ; Child object
;~          $pChildObj = DllStructGetData($tVarChildren, $i, 3)
;~          $oChildObj = ObjCreateInterface($pChildObj, $sIID_IAccessible, $dtagIAccessible)




            $oChildObj = ObjCreateInterface(($pChildObj), $sIID_IAccessible, $dtagIAccessible)

            If IsObj($oChildObj) Then

                ; Try to get an ISimpleDOMNode interface pointer for the child object
                If $oChildObj.QueryInterface(DllStructGetPtr($tIID_IServiceProvider), $pService) = $S_OK Then
                    $oService = ObjCreateInterface($pService, $sIID_IServiceProvider, $dtagIServiceProvider)
                    If $oService.QueryService($tIID_ISimpleDOMNode, $tIID_ISimpleDOMNode, $pISimpleDOMNode) = $S_OK Then
                        $aInfo[$iInfo] = $sIndent & "$pISimpleDOMNode = " & Ptr($pISimpleDOMNode)
                        $iInfo += 1
                        $oISimpleDOMNode = ObjCreateInterface($pISimpleDOMNode, $sIID_ISimpleDOMNode, $dtagISimpleDOMNode)
                        If IsObj($oISimpleDOMNode) Then
                            $oISimpleDOMNode.nodeInfo($sNodeName, $iNameSpaceID, $sNodeValue, $iNumChildren, $iUniqueID, $iNodeType)
                            $aInfo[$iInfo + 0] = $sIndent & "$sNodeName       = " & $sNodeName
                            $aInfo[$iInfo + 1] = $sIndent & "$iNameSpaceID    = " & $iNameSpaceID
                            $aInfo[$iInfo + 2] = $sIndent & "$sNodeValue      = " & $sNodeValue
                            $aInfo[$iInfo + 3] = $sIndent & "$iNumChildren    = " & $iNumChildren
                            $aInfo[$iInfo + 4] = $sIndent & "$iUniqueID       = " & $iUniqueID
                            $aInfo[$iInfo + 5] = $sIndent & "$iNodeType       = " & $iNodeType & " (" & GetNodeType($iNodeType) & ")"
                            $iInfo += 6

                            ; $oISimpleDOMNode.attributes
                            $oISimpleDOMNode.attributes($iMaxAttribs, $tAttribNames, $tNameSpaceIDs, $tAttribValues, $iNumAttribs)
                            $aInfo[$iInfo] = $sIndent & "$iNumAttribs     = " & $iNumAttribs
                            $iInfo += 1
                            For $j = 1 To $iNumAttribs
                                $sAttribName = SysReadString(DllStructGetData($tAttribNames, 1, $j))
                                $sAttribValue = SysReadString(DllStructGetData($tAttribValues, 1, $j))
                                $iNameSpaceID = DllStructGetData($tNameSpaceIDs, 1, $j)
                                $aInfo[$iInfo + 0] = "    " & $sIndent & "$iAttrib      = " & $j
                                $aInfo[$iInfo + 1] = "    " & $sIndent & "$sAttribName  = " & $sAttribName
                                $aInfo[$iInfo + 2] = "    " & $sIndent & "$sAttribValue = " & $sAttribValue
                                $aInfo[$iInfo + 3] = "    " & $sIndent & "$iNameSpaceID = " & $iNameSpaceID
                                $iInfo += 4
                                ; Free memory allocated by BSTRs
                                SysFreeString(DllStructGetData($tAttribNames, 1, $j))
                                SysFreeString(DllStructGetData($tAttribValues, 1, $j))
                            Next

                            ; $oISimpleDOMNode.computedStyle
                            $oISimpleDOMNode.computedStyle($iMaxStyleProperties, 0, $tStyleProperties, $tStyleValues, $iNumStyleProperties)
                            $aInfo[$iInfo] = $sIndent & "$iNumStyleProps  = " & $iNumStyleProperties
                            $iInfo += 1
                            For $j = 1 To $iNumStyleProperties
                                $sStyleProperty = SysReadString(DllStructGetData($tStyleProperties, 1, $j))
                                $sStyleValue = SysReadString(DllStructGetData($tStyleValues, 1, $j))
                                $aInfo[$iInfo + 0] = "    " & $sIndent & "$iStyle       = " & $j
                                $aInfo[$iInfo + 1] = "    " & $sIndent & "$sStyleProp   = " & $sStyleProperty
                                $aInfo[$iInfo + 2] = "    " & $sIndent & "$sStyleValue  = " & $sStyleValue
                                $iInfo += 3
                                ; Free memory allocated by BSTRs
                                SysFreeString(DllStructGetData($tStyleProperties, 1, $j))
                                SysFreeString(DllStructGetData($tStyleValues, 1, $j))
                            Next

                            ;$oISimpleDOMNode.innerHTML( $sInnerHTML )
                            ;If String( $sInnerHTML ) <> "0" Then
                            ;  $aInfo[$iInfo] = $sIndent & "$sInnerHTML      = " & $sInnerHTML
                            ;  $iInfo += 1
                            ;EndIf

                            If $iNodeType = 3 Then ; $NODETYPE_TEXT
                                ; Try to get an ISimpleDOMText interface pointer with $oISimpleDOMNode.QueryInterface
                                If $oISimpleDOMNode.QueryInterface(DllStructGetPtr($tIID_ISimpleDOMText), $pISimpleDOM) = $S_OK Then
                                    $aInfo[$iInfo] = $sIndent & "$pISimpleDOMText = " & Ptr($pISimpleDOM)
                                    $iInfo += 1
                                    $oISimpleDOM = ObjCreateInterface($pISimpleDOM, $sIID_ISimpleDOMText, $dtagISimpleDOMText)
                                    If IsObj($oISimpleDOM) Then
                                        Local $sDomText
                                        $oISimpleDOM.domText($sDomText)
                                        $aInfo[$iInfo] = $sIndent & "$sDomText        = " & $sDomText
                                        $iInfo += 1
                                    EndIf
                                EndIf

                            ElseIf $iNodeType = 9 Then ; $NODETYPE_DOCUMENT
                                ; Try to get an ISimpleDOMDocument interface pointer with $oISimpleDOMNode.QueryInterface
                                If $oISimpleDOMNode.QueryInterface(DllStructGetPtr($tIID_ISimpleDOMDocument), $pISimpleDOM) = $S_OK Then
                                    $aInfo[$iInfo] = $sIndent & "$pISimpleDOMDocument = " & Ptr($pISimpleDOM)
                                    $iInfo += 1
                                    $oISimpleDOM = ObjCreateInterface($pISimpleDOM, $sIID_ISimpleDOMDocument, $dtagISimpleDOMDocument)
                                    If IsObj($oISimpleDOM) Then
                                        Local $sURL, $sTitle, $sMimeType, $sDocType
                                        $oISimpleDOM.URL($sURL)
                                        $oISimpleDOM.title($sTitle)
                                        $oISimpleDOM.mimeType($sMimeType)
                                        $oISimpleDOM.docType($sDocType)
                                        $aInfo[$iInfo + 0] = $sIndent & "$sURL                = " & $sURL
                                        $aInfo[$iInfo + 1] = $sIndent & "$sTitle              = " & $sTitle
                                        $aInfo[$iInfo + 2] = $sIndent & "$sMimeType           = " & $sMimeType
                                        $aInfo[$iInfo + 3] = $sIndent & "$sDocType            = " & $sDocType
                                        $iInfo += 4
                                    EndIf
                                EndIf
                            EndIf

                        EndIf
                    EndIf
                EndIf

                PrintElementInfoToArray($pChildObj, $oChildObj, $CHILDID_SELF, $sIndent)
                WalkTreeWithAccessibleChildren($pChildObj, $iLevel + 1, $iLevels)

            EndIf

        EndIf

    Next

EndFunc   ;==>WalkTreeWithAccessibleChildren


Func PrintElementInfoToArray($pElement, $oElement, $iChild, $sIndent)
    Local $hWnd, $sName, $iRole, $sRole, $iRoleLen
    Local $iState, $sState, $iStateLen
    Local $sValue, $x, $y, $w, $h
    If $iChild <> $CHILDID_SELF Then
        $aInfo[$iInfo] = $sIndent & "$iChildElem = " & $iChild
        $iInfo += 1
    EndIf
    If $iChild = $CHILDID_SELF And $oElement.get_accRole($CHILDID_SELF, $iRole) = $S_OK And $iRole = $ROLE_SYSTEM_WINDOW Then
        WindowFromAccessibleObject($pElement, $hWnd)
        $aInfo[$iInfo] = $sIndent & "$hWnd   = " & $hWnd
        $iInfo += 1
    EndIf
    $oElement.get_accName($iChild, $sName)
    $aInfo[$iInfo] = $sIndent & "$sName  = " & $sName
    $iInfo += 1
    If $oElement.get_accRole($iChild, $iRole) = $S_OK Then
        $aInfo[$iInfo] = $sIndent & "$iRole  = 0x" & Hex($iRole)
        $iInfo += 1
        $iRoleLen = GetRoleText($iRole, 0, 0) + 1
        $sRole = DllStructCreate("wchar[" & $iRoleLen & "]")
        GetRoleText($iRole, DllStructGetPtr($sRole), $iRoleLen)
        $aInfo[$iInfo] = $sIndent & "$sRole  = " & DllStructGetData($sRole, 1)
        $iInfo += 1
    EndIf
    If $oElement.get_accState($iChild, $iState) = $S_OK Then
        $aInfo[$iInfo] = $sIndent & "$iState = 0x" & Hex($iState)
        $iInfo += 1
        $iStateLen = GetStateText($iState, 0, 0) + 1
        $sState = DllStructCreate("wchar[" & $iStateLen & "]")
        GetStateText($iState, DllStructGetPtr($sState), $iStateLen)
        $aInfo[$iInfo] = $sIndent & "$sState = " & DllStructGetData($sState, 1)
        $iInfo += 1
    EndIf
    If $oElement.get_accValue($iChild, $sValue) = $S_OK Then
        $aInfo[$iInfo] = $sIndent & "$sValue = " & $sValue
        $iInfo += 1
    EndIf
    If $oElement.accLocation($x, $y, $w, $h, $iChild) = $S_OK Then
        $aInfo[$iInfo] = $sIndent & "$x, $y, $w, $h = " & $x & ", " & $y & ", " & $w & ", " & $h
        $iInfo += 1
    EndIf
    $aInfo[$iInfo] = ""
    $iInfo += 1
EndFunc   ;==>PrintElementInfoToArray


Func Close()
    Exit
EndFunc   ;==>Close

 

Saludos

Edited by Danyfirex

Share this post


Link to post
Share on other sites

I've not tested these interfaces (IAccessible, IAccessible2, IAccessibleEx, ISimpleDOM) or the examples on 64 bit or Windows 10. A few minor issues cannot be excluded.

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Weird doing nothing on my system when trying as X64

I changed some constants to come from include in MSACCESSIBILITY.AU3

#include "CUIAutomation2.au3"
#include <autoitconstants.au3>
#include <winapiconstants.au3>
#include <menuconstants.au3>

to prevent some compile errors removed const

If @AutoItX64 Then
    global $tagVARIANT = "dword[6];" ; Use this form to be able to build an
Else                               ; array in function AccessibleChildren.
    global $tagVARIANT = "dword[4];"
EndIf

using above source from @Danyfirex I get with some translation in the name of top level object in my case dutch Bureaublad

#AutoIt3Wrapper_UseX64=N
;~ #RequireAdmin

...


    consolewrite("GetWindowInfo name " & String($sName) & @CRLF)
Until stringinstr("Desktop Bureaublad Escritorio",String($sName))>0

The hotkey is calling the GetWindowInfo function when pressing ctrl+w above htmlDocument of google browser and then it works for above nice dump of elements

The problem starts when working with X64

#AutoIt3Wrapper_UseX64=Y
#RequireAdmin
Func GetWindowInfo()
    consolewrite("GetWindowInfo before first if" & @CRLF)
;~  MsgBox(0, "GetWindowInfo", "GetWindowInfo'before first if" & @CRLF)
    Local $aMousePos = MouseGetPos(), $pObject, $tVarChild, $vt, $err = 0

Consolewrite statements seems not to work at all (probably as I now am elevated running as admin? happens also in X86) but msgbox goes fine.

Testing further gives me the feeling it goes wrong in AccessibleObjectFromWindow

AccessibleObjectFromPoint gives a correct value when making an iaccessible object from it

maybe after googling hitting this feature https://bugs.webkit.org/show_bug.cgi?id=141391

Before comparing this value against the OBJID_ values, the server must cast it to DWORD; otherwise, on 64-bit Windows, the sign extension of the lParam can interfere with the comparison.

But it does not say anything on the clientside

https://groups.google.com/a/chromium.org/forum/#!topic/chromium-reviews/TY6rBImbySQ

So most likely I need to fix this function to call differently in X64 compared to X86 for the $OBJID_CLIENT value 
which is defined as Global Const $OBJID_CLIENT            = 0xFFFFFFFC

Func AccessibleObjectFromWindow( $hWnd, $iObjectID, $tRIID, ByRef $pObject )
    If @AutoItX64 Then
;~      Local $aRet = DllCall( $hdllOleacc, "int", "AccessibleObjectFromWindow", "hwnd", $hWnd, "uint64", 0xfffffffffffffffc, "struct*", $tRIID, "int*", 0 )
        Local $aRet = DllCall( $hdllOleacc, "int", "AccessibleObjectFromWindow", "hwnd", $hWnd, "uint64", 0x00000000fffffffc, "struct*", $tRIID, "int*", 0 )
    else
        Local $aRet = DllCall( $hdllOleacc, "int", "AccessibleObjectFromWindow", "hwnd", $hWnd, "dword", $iObjectID, "struct*", $tRIID, "int*", 0 )
    endif
    If @error Then
        msgbox(0,"Error",$aRet)
        Return SetError(1, 0, $S_FALSE)
    EndIf

    If $aRet[0] Then Return SetError(2, 0, $aRet[0])
    $pObject = $aRet[4]
    Return $S_OK
EndFunc

source for testing includes messageboxes

#AutoIt3Wrapper_UseX64=Y
#RequireAdmin
#include "CUIAutomation2.au3"
#include "MSAccessibility.au3"
#include "ISimpleDOM.au3"
#include <Array.au3>

Opt("MustDeclareVars", 1)

Global $aInfo[10000], $iInfo = 0

MainFunc()

Func MainFunc()

    HotKeySet("^w", "GetWindowInfo")
    HotKeySet("{ESC}", "Close")

    While Sleep(100)
    WEnd

EndFunc   ;==>MainFunc


Func GetWindowInfo()
;~  consolewrite("GetWindowInfo before first if" & @CRLF)
;~  MsgBox(0, "GetWindowInfo", "GetWindowInfo before first if" & @CRLF)
    Local $aMousePos = MouseGetPos(), $pObject, $tVarChild, $vt, $err = 0
    Local $oObject, $hWnd, $sName = ""

    If AccessibleObjectFromPoint($aMousePos[0], $aMousePos[1], $pObject, $tVarChild) = $S_OK Then
;~      MsgBox(0, "GetWindowInfo", "GetWindowInfo after first if" & @CRLF)
;~      consolewrite("GetWindowInfo after first if" & @CRLF)
        $oObject = ObjCreateInterface($pObject, $sIID_IAccessible, $dtagIAccessible)
        $oObject.get_accName($CHILDID_SELF, $sName)
;~      consolewrite("GetWindowInfo name " & String($sName) & @CRLF)
        MsgBox(0, "GetWindowInfo", "GetWindowInfo name " & String($sName) & @CRLF)
        $vt = BitAND(DllStructGetData($tVarChild, 1, 1), 0xFFFF)
        If $vt = $VT_I4 Then
;~          consolewrite("GetWindowInfo after 2nd if VT_I4" & @CRLF)
;~          MsgBox(0, "GetWindowInfo", "GetWindowInfo after 2nd if VT_I4" & @CRLF)

            If WindowFromAccessibleObject($pObject, $hWnd) = $S_OK Then
                MsgBox(0, "GetWindowInfo", "GetWindowInfo after 3rd if" & @CRLF)
;~              consolewrite("GetWindowInfo after 3rd if " & @CRLF)
                AccessibleObjectFromWindow($hWnd, $OBJID_CLIENT, $tIID_IAccessible, $pObject)
                MsgBox(0, "GetWindowInfo", "Yeah we did not break" & @CRLF)
                $oObject = ObjCreateInterface($pObject, $sIID_IAccessible, $dtagIAccessible)
                MsgBox(0, "GetWindowInfo", "But unfortunately did not come here" & @CRLF)
                $oObject.get_accName($CHILDID_SELF, $sName)
;~      consolewrite("GetWindowInfo name " & String($sName) & @CRLF)
                MsgBox(0, "GetWindowInfo", "GetWindowInfo name after 3rd if " & String($sName) & @CRLF)

                ; Get parent objects to top window
                Local $pParent, $pPrev, $oPrev, $iRole
                Do
                    $pPrev = $pParent
                    $oPrev = $oObject
                    If IsObj($oObject) Then
                        $oObject.get_accParent($pParent)
                        $oObject = ObjCreateInterface($pParent, $sIID_IAccessible, $dtagIAccessible)
                    EndIf

                    If IsObj($oObject) Then
                        $oObject.get_accName($CHILDID_SELF, $sName)
                    EndIf
;~                  consolewrite("GetWindowInfo name " & String($sName) & @CRLF)
                    MsgBox(0, "GetWindowInfo", "GetWindowInfo name " & String($sName) & @CRLF)
                Until stringinstr("Desktop Bureaublad Escritorio",String($sName))>0
;~              String($sName) = "Desktop" or "Bureaublad" ;"Escritorio";"Desktop"

                ; Info for top window (previous to desktop)
                PrintElementInfoToArray($pPrev, $oPrev, $CHILDID_SELF, "")

                ; Info for child objects of the top window
                If $oPrev.get_accRole($CHILDID_SELF, $iRole) = $S_OK And $iRole = $ROLE_SYSTEM_WINDOW Then
                    WindowFromAccessibleObject($pPrev, $hWnd)
                    PrintWindowObjects($hWnd)
                Else
                    $err = 1
                EndIf

            Else
                $err = 1
            EndIf
        Else
            $err = 1
        EndIf
    Else
        $err = 1
    EndIf
    If $err Then _
            MsgBox(0, "ISimpleDOM interfaces", _
            "Accessible function xxxxx failed." & @CRLF & _
            "Try another point e.g. the window title bar.")
EndFunc   ;==>GetWindowInfo


Func PrintWindowObjects($hWindow)

    ; Object from window
    Local $pWindow, $oWindow
    AccessibleObjectFromWindow($hWindow, $OBJID_CLIENT, $tIID_IAccessible, $pWindow)
    $oWindow = ObjCreateInterface($pWindow, $sIID_IAccessible, $dtagIAccessible)
    If Not IsObj($oWindow) Then Return

    ; Get window objects
    WalkTreeWithAccessibleChildren($pWindow, 0, 8)

    ; Print window objects
    ReDim $aInfo[$iInfo]
    _ArrayDisplay($aInfo, "ISimpleDOM interfaces")
    ReDim $aInfo[10000]
    $iInfo = 0

EndFunc   ;==>PrintWindowObjects


Func WalkTreeWithAccessibleChildren($pAcc, $iLevel, $iLevels = 0)

    If $iLevels And $iLevel = $iLevels Then Return

    ; Create object
    Local $oAcc = ObjCreateInterface($pAcc, $sIID_IAccessible, $dtagIAccessible)
    If Not IsObj($oAcc) Then Return
    $oAcc.AddRef()

    ; Indentation
    Local $sIndent = ""
    For $i = 0 To $iLevel - 1
        $sIndent &= "    "
    Next

    Local $iChildCount, $iReturnCount, $tVarChildren

    ; Get children
    If $oAcc.get_accChildCount($iChildCount) Or Not $iChildCount Then Return
    If AccessibleChildren($pAcc, 0, $iChildCount, $tVarChildren, $iReturnCount) Then Return

    Local $vt, $pChildObj, $oChildObj
    Local $pService, $oService, $pISimpleDOMNode, $oISimpleDOMNode, $pISimpleDOM, $oISimpleDOM

    ; $oISimpleDOMNode.nodeInfo
    Local $sNodeName, $iNameSpaceID, $sNodeValue, $iNumChildren, $iUniqueID, $iNodeType, $sInnerHTML

    ; $oISimpleDOMNode.attributes
    Local $iMaxAttribs = 100, $iNumAttribs
    Local $tAttribNames = DllStructCreate("ptr[" & $iMaxAttribs & "]"), $sAttribName
    Local $tNameSpaceIDs = DllStructCreate("short[" & $iMaxAttribs & "]"), $iNameSpaceID
    Local $tAttribValues = DllStructCreate("ptr[" & $iMaxAttribs & "]"), $sAttribValue

    ; $oISimpleDOMNode.computedStyle
    Local $iMaxStyleProperties = 100, $iNumStyleProperties
    Local $tStyleProperties = DllStructCreate("ptr[" & $iMaxStyleProperties & "]"), $sStyleProperty
    Local $tStyleValues = DllStructCreate("ptr[" & $iMaxStyleProperties & "]"), $sStyleValue

    ; For each child
    For $i = 1 To $iReturnCount

        ; $tVarChildren is an array of VARIANTs with information about the children
        $vt = BitAND(DllStructGetData($tVarChildren, $i, 1), 0xFFFF)

        If $vt = $VT_DISPATCH Then



            ; Child object; get correct ptr x64 or x86 version
            Local $tVariant = DllStructCreate("word vt;word r1;word r2;word r3;ptr data; ptr;", DllStructGetPtr($tVarChildren, $i))
            $pChildObj = DllStructGetData($tVariant, 5)

            ;this is wrong. You will never get the x64 ptr
;~          ; Child object
;~          $pChildObj = DllStructGetData($tVarChildren, $i, 3)
;~          $oChildObj = ObjCreateInterface($pChildObj, $sIID_IAccessible, $dtagIAccessible)




            $oChildObj = ObjCreateInterface(($pChildObj), $sIID_IAccessible, $dtagIAccessible)

            If IsObj($oChildObj) Then

                ; Try to get an ISimpleDOMNode interface pointer for the child object
                If $oChildObj.QueryInterface(DllStructGetPtr($tIID_IServiceProvider), $pService) = $S_OK Then
                    $oService = ObjCreateInterface($pService, $sIID_IServiceProvider, $dtagIServiceProvider)
                    If $oService.QueryService($tIID_ISimpleDOMNode, $tIID_ISimpleDOMNode, $pISimpleDOMNode) = $S_OK Then
                        $aInfo[$iInfo] = $sIndent & "$pISimpleDOMNode = " & Ptr($pISimpleDOMNode)
                        $iInfo += 1
                        $oISimpleDOMNode = ObjCreateInterface($pISimpleDOMNode, $sIID_ISimpleDOMNode, $dtagISimpleDOMNode)
                        If IsObj($oISimpleDOMNode) Then
                            $oISimpleDOMNode.nodeInfo($sNodeName, $iNameSpaceID, $sNodeValue, $iNumChildren, $iUniqueID, $iNodeType)
                            $aInfo[$iInfo + 0] = $sIndent & "$sNodeName       = " & $sNodeName
                            $aInfo[$iInfo + 1] = $sIndent & "$iNameSpaceID    = " & $iNameSpaceID
                            $aInfo[$iInfo + 2] = $sIndent & "$sNodeValue      = " & $sNodeValue
                            $aInfo[$iInfo + 3] = $sIndent & "$iNumChildren    = " & $iNumChildren
                            $aInfo[$iInfo + 4] = $sIndent & "$iUniqueID       = " & $iUniqueID
                            $aInfo[$iInfo + 5] = $sIndent & "$iNodeType       = " & $iNodeType & " (" & GetNodeType($iNodeType) & ")"
                            $iInfo += 6

                            ; $oISimpleDOMNode.attributes
                            $oISimpleDOMNode.attributes($iMaxAttribs, $tAttribNames, $tNameSpaceIDs, $tAttribValues, $iNumAttribs)
                            $aInfo[$iInfo] = $sIndent & "$iNumAttribs     = " & $iNumAttribs
                            $iInfo += 1
                            For $j = 1 To $iNumAttribs
                                $sAttribName = SysReadString(DllStructGetData($tAttribNames, 1, $j))
                                $sAttribValue = SysReadString(DllStructGetData($tAttribValues, 1, $j))
                                $iNameSpaceID = DllStructGetData($tNameSpaceIDs, 1, $j)
                                $aInfo[$iInfo + 0] = "    " & $sIndent & "$iAttrib      = " & $j
                                $aInfo[$iInfo + 1] = "    " & $sIndent & "$sAttribName  = " & $sAttribName
                                $aInfo[$iInfo + 2] = "    " & $sIndent & "$sAttribValue = " & $sAttribValue
                                $aInfo[$iInfo + 3] = "    " & $sIndent & "$iNameSpaceID = " & $iNameSpaceID
                                $iInfo += 4
                                ; Free memory allocated by BSTRs
                                SysFreeString(DllStructGetData($tAttribNames, 1, $j))
                                SysFreeString(DllStructGetData($tAttribValues, 1, $j))
                            Next

                            ; $oISimpleDOMNode.computedStyle
                            $oISimpleDOMNode.computedStyle($iMaxStyleProperties, 0, $tStyleProperties, $tStyleValues, $iNumStyleProperties)
                            $aInfo[$iInfo] = $sIndent & "$iNumStyleProps  = " & $iNumStyleProperties
                            $iInfo += 1
                            For $j = 1 To $iNumStyleProperties
                                $sStyleProperty = SysReadString(DllStructGetData($tStyleProperties, 1, $j))
                                $sStyleValue = SysReadString(DllStructGetData($tStyleValues, 1, $j))
                                $aInfo[$iInfo + 0] = "    " & $sIndent & "$iStyle       = " & $j
                                $aInfo[$iInfo + 1] = "    " & $sIndent & "$sStyleProp   = " & $sStyleProperty
                                $aInfo[$iInfo + 2] = "    " & $sIndent & "$sStyleValue  = " & $sStyleValue
                                $iInfo += 3
                                ; Free memory allocated by BSTRs
                                SysFreeString(DllStructGetData($tStyleProperties, 1, $j))
                                SysFreeString(DllStructGetData($tStyleValues, 1, $j))
                            Next

                            ;$oISimpleDOMNode.innerHTML( $sInnerHTML )
                            ;If String( $sInnerHTML ) <> "0" Then
                            ;  $aInfo[$iInfo] = $sIndent & "$sInnerHTML      = " & $sInnerHTML
                            ;  $iInfo += 1
                            ;EndIf

                            If $iNodeType = 3 Then ; $NODETYPE_TEXT
                                ; Try to get an ISimpleDOMText interface pointer with $oISimpleDOMNode.QueryInterface
                                If $oISimpleDOMNode.QueryInterface(DllStructGetPtr($tIID_ISimpleDOMText), $pISimpleDOM) = $S_OK Then
                                    $aInfo[$iInfo] = $sIndent & "$pISimpleDOMText = " & Ptr($pISimpleDOM)
                                    $iInfo += 1
                                    $oISimpleDOM = ObjCreateInterface($pISimpleDOM, $sIID_ISimpleDOMText, $dtagISimpleDOMText)
                                    If IsObj($oISimpleDOM) Then
                                        Local $sDomText
                                        $oISimpleDOM.domText($sDomText)
                                        $aInfo[$iInfo] = $sIndent & "$sDomText        = " & $sDomText
                                        $iInfo += 1
                                    EndIf
                                EndIf

                            ElseIf $iNodeType = 9 Then ; $NODETYPE_DOCUMENT
                                ; Try to get an ISimpleDOMDocument interface pointer with $oISimpleDOMNode.QueryInterface
                                If $oISimpleDOMNode.QueryInterface(DllStructGetPtr($tIID_ISimpleDOMDocument), $pISimpleDOM) = $S_OK Then
                                    $aInfo[$iInfo] = $sIndent & "$pISimpleDOMDocument = " & Ptr($pISimpleDOM)
                                    $iInfo += 1
                                    $oISimpleDOM = ObjCreateInterface($pISimpleDOM, $sIID_ISimpleDOMDocument, $dtagISimpleDOMDocument)
                                    If IsObj($oISimpleDOM) Then
                                        Local $sURL, $sTitle, $sMimeType, $sDocType
                                        $oISimpleDOM.URL($sURL)
                                        $oISimpleDOM.title($sTitle)
                                        $oISimpleDOM.mimeType($sMimeType)
                                        $oISimpleDOM.docType($sDocType)
                                        $aInfo[$iInfo + 0] = $sIndent & "$sURL                = " & $sURL
                                        $aInfo[$iInfo + 1] = $sIndent & "$sTitle              = " & $sTitle
                                        $aInfo[$iInfo + 2] = $sIndent & "$sMimeType           = " & $sMimeType
                                        $aInfo[$iInfo + 3] = $sIndent & "$sDocType            = " & $sDocType
                                        $iInfo += 4
                                    EndIf
                                EndIf
                            EndIf

                        EndIf
                    EndIf
                EndIf

                PrintElementInfoToArray($pChildObj, $oChildObj, $CHILDID_SELF, $sIndent)
                WalkTreeWithAccessibleChildren($pChildObj, $iLevel + 1, $iLevels)

            EndIf

        EndIf

    Next

EndFunc   ;==>WalkTreeWithAccessibleChildren


Func PrintElementInfoToArray($pElement, $oElement, $iChild, $sIndent)
    Local $hWnd, $sName, $iRole, $sRole, $iRoleLen
    Local $iState, $sState, $iStateLen
    Local $sValue, $x, $y, $w, $h
    If $iChild <> $CHILDID_SELF Then
        $aInfo[$iInfo] = $sIndent & "$iChildElem = " & $iChild
        $iInfo += 1
    EndIf
    If $iChild = $CHILDID_SELF And $oElement.get_accRole($CHILDID_SELF, $iRole) = $S_OK And $iRole = $ROLE_SYSTEM_WINDOW Then
        WindowFromAccessibleObject($pElement, $hWnd)
        $aInfo[$iInfo] = $sIndent & "$hWnd   = " & $hWnd
        $iInfo += 1
    EndIf
    $oElement.get_accName($iChild, $sName)
    $aInfo[$iInfo] = $sIndent & "$sName  = " & $sName
    $iInfo += 1
    If $oElement.get_accRole($iChild, $iRole) = $S_OK Then
        $aInfo[$iInfo] = $sIndent & "$iRole  = 0x" & Hex($iRole)
        $iInfo += 1
        $iRoleLen = GetRoleText($iRole, 0, 0) + 1
        $sRole = DllStructCreate("wchar[" & $iRoleLen & "]")
        GetRoleText($iRole, DllStructGetPtr($sRole), $iRoleLen)
        $aInfo[$iInfo] = $sIndent & "$sRole  = " & DllStructGetData($sRole, 1)
        $iInfo += 1
    EndIf
    If $oElement.get_accState($iChild, $iState) = $S_OK Then
        $aInfo[$iInfo] = $sIndent & "$iState = 0x" & Hex($iState)
        $iInfo += 1
        $iStateLen = GetStateText($iState, 0, 0) + 1
        $sState = DllStructCreate("wchar[" & $iStateLen & "]")
        GetStateText($iState, DllStructGetPtr($sState), $iStateLen)
        $aInfo[$iInfo] = $sIndent & "$sState = " & DllStructGetData($sState, 1)
        $iInfo += 1
    EndIf
    If $oElement.get_accValue($iChild, $sValue) = $S_OK Then
        $aInfo[$iInfo] = $sIndent & "$sValue = " & $sValue
        $iInfo += 1
    EndIf
    If $oElement.accLocation($x, $y, $w, $h, $iChild) = $S_OK Then
        $aInfo[$iInfo] = $sIndent & "$x, $y, $w, $h = " & $x & ", " & $y & ", " & $w & ", " & $h
        $iInfo += 1
    EndIf
    $aInfo[$iInfo] = ""
    $iInfo += 1
EndFunc   ;==>PrintElementInfoToArray


Func Close()
    Exit
EndFunc   ;==>Close

 

MSAccessibility.au3

Edited by junkew

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

above my hat

https://bugzilla.mozilla.org/show_bug.cgi?id=649236

It seems to be AccessibleObjectFromWindow with the actual problem, though AccessibleObjectFromEvent calls it internally.
A work around has been implemented in NVDA changeset:main,4474 which replaces a call to AccessibleObjectFromEvent with custom code that  sends WM_GETOBJECT, calls ObjectFromLresult, and tries accChild. All the things that I'd think AccessibleObjectFromEvent/AccessibleObjectFromWindow would do normally.

http://hg.mozilla.org/mozilla-central/rev/62cb7ce43f42 has an actual workaround but no clue for me on how to do this in AutoIT

  •  AccessibleObjectFromWindow API sends WM_GETOBJECT message to the Window so that could be used as a workaround.
Edited by junkew

Share this post


Link to post
Share on other sites

probably change this from @trancexx

Should then try something like this

;~ Func _IEControlGetObjFromHWND($hWin)
Func _AccessibleObjectFromWindow( $hWnd, $iObjectID, $tRIID, ByRef $pObject )
    Local $aCall = DllCall("user32.dll", "dword", "RegisterWindowMessageW", "wstr", "WM_GETOBJECT")

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

    Local Const $WM_GETOBJECT = $aCall[0]

    $aCall = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "dword", $WM_GETOBJECT, "wparam", 0, "lparam", $iObjectID0)

    Local $lResult = $aCall[0]

;~ Global Const $sIID_IAccessible="{618736E0-3C3D-11CF-810C-00AA00389B71}"
Local $tUUID = _WinAPI_GUIDFromString("{618736E0-3C3D-11CF-810C-00AA00389B71}") 
;~     Local $tUUID = _WinAPI_GUIDFromString("{626FC520-A41E-11CF-A731-00A0C9082637}") ; IID_IHTMLDocument

    DllCall("ole32.dll", "int", "CoInitializeEx", "ptr", 0, "dword", 2) ;COINIT_APARTMENTTHREADED

    $aCall = DllCall("oleacc.dll", "dword", "ObjectFromLresult", _
            "lresult", $lResult, _
            "ptr", DllStructGetPtr($tUUID), _
            "wparam", 0, _
            "idispatch*", 0)


    If IsObj($aCall[4]) Then
        return $aCall[4]
    Else
        Return SetError(1, 0, 0)
    EndIf

EndFunc   ;==>_AccessibleObjectFromWindow

 

Share this post


Link to post
Share on other sites

Hello. try the call this way

 

Local $aRet = DllCall( $hdllOleacc, "int", "AccessibleObjectFromWindow", "hwnd", $hWnd, "dword", $iObjectID, "struct*", $tRIID, "ptr*", 0 )

Saludos

1 person likes this

Share this post


Link to post
Share on other sites

that works:sweating: I learned a lot by reading all stuff above

Func AccessibleObjectFromWindow( $hWnd, $iObjectID, $tRIID, ByRef $pObject )
;~      Local $aRet = DllCall( $hdllOleacc, "int", "AccessibleObjectFromWindow", "hwnd", $hWnd, "dword", $iObjectID, "struct*", $tRIID, "int*", 0 )
        Local $aRet = DllCall( $hdllOleacc, "int", "AccessibleObjectFromWindow", "hwnd", $hWnd, "dword", $iObjectID, "struct*", $tRIID, "ptr*", 0 )

 

Share this post


Link to post
Share on other sites

I forgot to tell you that in the first post. I did that change when I tried code lastnight then  I forgot that I did lol.

 

Saludos

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