I am trying to create QA automation for Google Chrome to simulate clicks and receive tab click events.
I use the IAccessible interface and the AccessChildren API to get the full accessible tree of elements.
When using AccExplorer 2.0 to view a tree, it looks great (see image at the end).
But my program shows only a partial tree, and the names do not match those that I see in AccExplorer.
I run:
- Chrome 37 beta li>
- Win 7 64 bit
Any ideas why I can't view the full tree?
thanks
This is my source code for the program (C ++): (similar to the MSDN example)
int _tmain(int argc, _TCHAR* argv[]) { int i=0; HWND hWndChrome = NULL; hWndChrome = (HWND)0x000702c0; wcout << L"\n\nChrome_WidgetWin_1 = "<< hex << hWndChrome << "\n--------------------------"; CComPtr<IAccessible> pAccMain; ::AccessibleObjectFromWindow(hWndChrome, OBJID_CLIENT, IID_IAccessible, (void**)(&pAccMain)); WalkTreeWithAccessibleChildren(pAccMain, 0); _getch(); return 0; } HRESULT WalkTreeWithAccessibleChildren(__in CComPtr<IAccessible> pAcc, __in int depth) { long childCount = 0; long returnCount = 0; HRESULT hr = pAcc->get_accChildCount(&childCount); if (childCount == 0) return S_FALSE; CComVariant* pArray = new CComVariant[childCount]; hr = ::AccessibleChildren(pAcc, 0L, childCount, pArray, &returnCount); if (FAILED(hr)) return hr; // Iterate through children. for (int x = 0; x < returnCount; x++) { CComVariant vtChild = pArray[x]; // If it an accessible object, get the IAccessible, and recurse. if (vtChild.vt == VT_DISPATCH) { CComPtr<IDispatch> pDisp = vtChild.pdispVal; CComQIPtr<IAccessible> pAccChild = pDisp; if (!pAccChild) continue; // Print current accessible element wcout << endl; for (int y = 0; y < depth; y++) wcout << L" "; wcout << L"* " << GetName(pAccChild, CHILDID_SELF).data() << L" | " << GetRole(pAccChild, CHILDID_SELF).data() << L" (Object)"; WalkTreeWithAccessibleChildren(pAccChild, depth + 1); } // Else it a child element so we have to call accNavigate on the parent, // and we do not recurse because child elements can't have children. else { // Print current accessible element wcout << endl; for (int y = 0; y < depth; y++) wcout << L" "; wcout << L"* " << GetName(pAcc, vtChild.lVal).data() << L" | " << GetRole(pAcc, vtChild.lVal).data() << " (Child)"; } } delete[] pArray; return S_OK; } wstring GetName(__in CComPtr<IAccessible> pAcc, __in CComVariant varChild) { if (!pAcc) return L""; CComBSTR bstrName; HRESULT hr = pAcc->get_accName(varChild, &bstrName); if (FAILED(hr)) return L""; if (!bstrName.m_str) return L"<NULL>"; return bstrName.m_str; } wstring GetRole(__in CComPtr<IAccessible> pAcc, __in CComVariant varChild) { if (!pAcc) return L""; CComVariant varRoleID; HRESULT hr = pAcc->get_accRole(varChild, &varRoleID); if (FAILED(hr)) return L""; WCHAR sRoleBuff[1024] = {0}; hr = ::GetRoleText(varRoleID.lVal, sRoleBuff, 1024); if (FAILED(hr)) return L""; return sRoleBuff; }
And this is the console output:
Chrome_WidgetWin_1 = 000702C0 -------------------------- * Chrome Legacy Window | window (Object) * System | menu bar (Object) * <NULL> | title bar (Object) * IME | push button (Child) * Minimize | push button (Child) * Maximize | push button (Child) * Context help | push button (Child) * Close | push button (Child) * Application | menu bar (Object) * Chrome Legacy Window | client (Object) // -----> { there should be a big sub-tree here } <----- // * Vertical | scroll bar (Object) * Line up | push button (Child) * Page up | push button (Child) * Position | indicator (Child) * Page down | push button (Child) * Line down | push button (Child) * Horizontal | scroll bar (Object) * Column left | push button (Child) * Page left | push button (Child) * Position | indicator (Child) * Page right | push button (Child) * Column right | push button (Child) * <NULL> | grip (Object)
Here is a screenshot of AccExplorer showing the full tree: (some nodes collapsed) 
Edit:
When using OBJID_WINDOW instead of OBJID_WINDOW (as in the example in AccessibleObjectFromWindow) - I get a tree with a lot of nodes, but still I do not see tabs.