VOID CALLBACK WinEventProc(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) { IAccessible* pAcc = NULL; VARIANT varChild; HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &pAcc, &varChild); if ((hr == S_OK) && (pAcc != NULL)) { BSTR bstrName, bstrValue; pAcc->get_accValue(varChild, &bstrValue); pAcc->get_accName(varChild, &bstrName); char className[50]; GetClassNameA(hwnd, className, 50); if ((strcmp(className, "Chrome_WidgetWin_1") == 0) && (wcscmp(bstrName, L"Address and search bar") == 0)) { SendMessage(ghWnd, WM_UPDATECAREPOS, NULL, (WPARAM)(bstrValue));//LPCWSTR printf("URL change: %ls\n", bstrValue); } pAcc->Release(); } return; }
void CALLBACK WebKitVBufBackend_t::renderThread_winEventProcHook(HWINEVENTHOOK hookID, DWORD eventID, HWND hwnd, long objectID, long childID, DWORD threadID, DWORD time) { switch (eventID) { case EVENT_OBJECT_VALUECHANGE: case EVENT_OBJECT_STATECHANGE: break; default: return; } WebKitVBufBackend_t* backend = NULL; for (VBufBackendSet_t::iterator it = runningBackends.begin(); it != runningBackends.end(); ++it) { HWND rootWindow = (HWND)(*it)->rootDocHandle; if (hwnd == rootWindow || IsChild(rootWindow, hwnd)) { backend = static_cast<WebKitVBufBackend_t*>(*it); break; } } if (!backend) return; IAccessible* acc = IAccessibleFromIdentifier((int)hwnd, childID); if (!acc) return; acc->Release(); map<IAccessible*, WebKitVBufStorage_controlFieldNode_t*>::const_iterator it; if ((it = backend->accessiblesToNodes.find(acc)) == backend->accessiblesToNodes.end()) return; backend->invalidateSubtree(it->second); }
void CALLBACK WinEventFunc(HWINEVENTHOOK hook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) { IAccessible* acc = nullptr; VARIANT var_child; HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &acc, &var_child); if (hr == S_OK && acc != nullptr) { BSTR name; acc->get_accName(var_child, &name); switch (dwEvent) { case EVENT_SYSTEM_FOREGROUND: case EVENT_SYSTEM_ALERT: case EVENT_OBJECT_FOCUS: case EVENT_OBJECT_SELECTION: case EVENT_OBJECT_VALUECHANGE: break; } SysFreeString(name); acc->Release(); } }
LRESULT CALLBACK callWndProcHook(int code, WPARAM wParam,LPARAM lParam) { CWPSTRUCT* pcwp = (CWPSTRUCT*)lParam; if (pcwp->message == WM_LRESULT_FROM_IACCESSIBLE) { *(LRESULT*)pcwp->lParam = LresultFromObject(IID_IAccessible, 0, (IUnknown*)pcwp->wParam); } else if (pcwp->message == WM_IACCESSIBLE_FROM_CHILDID) { IAccessible* acc = IAccessibleFromIdentifier((int)pcwp->hwnd, (int)pcwp->wParam); if (acc) { acc->Release(); } *(IAccessible**) pcwp->lParam = acc; } return 0; }
HRESULT AccessibleObject::BuildChildren(std::vector<AccessibleChild>& children, IAccessible* acc, LPARAM param) { if (acc == nullptr) acc = acc_; if (acc == nullptr) return E_INVALIDARG; long child_count = 0; HRESULT hr = acc->get_accChildCount(&child_count); if (FAILED(hr)) return hr; if (child_count == 0) return S_FALSE; long obtained_count = 0; std::vector<VARIANT> var_array(child_count); hr = AccessibleChildren(acc, 0L, child_count, var_array.data(), &obtained_count); if (FAILED(hr)) return hr; children.resize(obtained_count); for (int i = 0; i < obtained_count; i++) { VARIANT var_child = var_array[i]; if (var_child.vt == VT_DISPATCH) { IDispatch* dispatch = var_child.pdispVal; IAccessible* child = nullptr; hr = dispatch->QueryInterface(IID_IAccessible, (void**)&child); if (hr == S_OK) { GetName(children.at(i).name, CHILDID_SELF, child); GetRole(children.at(i).role, CHILDID_SELF, child); GetValue(children.at(i).value, CHILDID_SELF, child); if (AllowChildTraverse(children.at(i), param)) BuildChildren(children.at(i).children, child, param); child->Release(); } dispatch->Release(); } else { GetName(children.at(i).name, var_child.lVal, acc); GetRole(children.at(i).role, var_child.lVal, acc); GetValue(children.at(i).value, var_child.lVal, acc); } } return S_OK; }
bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult) { if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) { /* For UI Automation */ } else if ((DWORD)lParam == OBJID_CLIENT) { #if 1 // Ignoring all requests while starting up // ### Maybe QPA takes care of this??? if (QApplication::startingUp() || QApplication::closingDown()) return false; #endif typedef LRESULT (WINAPI *PtrLresultFromObject)(REFIID, WPARAM, LPUNKNOWN); static PtrLresultFromObject ptrLresultFromObject = 0; static bool oleaccChecked = false; if (!oleaccChecked) { oleaccChecked = true; #if !defined(Q_OS_WINCE) ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject"); #endif } if (ptrLresultFromObject) { QWindow *window = QWindowsContext::instance()->findWindow(hwnd); if (window) { QAccessibleInterface *acc = window->accessibleRoot(); if (acc) { QWindowsAccessible *winacc = new QWindowsAccessible(acc); IAccessible *iface; HRESULT hr = winacc->QueryInterface(IID_IAccessible, (void**)&iface); if (SUCCEEDED(hr)) { *lResult = ptrLresultFromObject(IID_IAccessible, wParam, iface); // ref == 2 if (*lResult) { iface->Release(); // the client will release the object again, and then it will destroy itself } return true; } } } } } return false; }
void walk_tree(IAccessible *pAccessible, char **pColumnHeaderNames, long *pColumnHeadersCount) { HRESULT hr ; long childCount ; hr = pAccessible->get_accChildCount(&childCount) ; if (FAILED(hr) || childCount == 0) return ; VARIANT *pChildVariants = new VARIANT[childCount] ; long childrenFound ; hr = AccessibleChildren(pAccessible, 0, childCount, pChildVariants, &childrenFound) ; if (FAILED(hr)) return ; for (int i=1; i < childrenFound + 1; i++) { VARIANT vChild = pChildVariants[i] ; if (vChild.vt == VT_DISPATCH) { IDispatch *pDispatch = vChild.pdispVal ; IAccessible *pChildAccessible = NULL ; hr = pDispatch->QueryInterface(IID_IAccessible, (void**) &pChildAccessible) ; if (hr == S_OK) { walk_tree(pChildAccessible, pColumnHeaderNames, pColumnHeadersCount) ; pChildAccessible->Release() ; } pDispatch->Release() ; } else { long role ; get_role(i, pAccessible, &role) ; if (role == 0x19) { if (pColumnHeaderNames == NULL) { *pColumnHeadersCount = *pColumnHeadersCount + 1 ; } else { char *headerName = (char *)malloc(sizeof(char) * BUFFER_SIZE) ; get_name(i, pAccessible, headerName) ; pColumnHeaderNames[i - 1] = headerName ; } } } } }
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Note, this window's message handling should not invoke any call that // may result in a cross-process ipc call. Doing so may violate RPC // message semantics. switch (msg) { case WM_GETOBJECT: { // Do explicit casting to make it working on 64bit systems (see bug 649236 // for details). int32_t objId = static_cast<DWORD>(lParam); if (objId == OBJID_CLIENT) { DocAccessible* document = nsWinUtils::sHWNDCache->GetWeak(static_cast<void*>(hWnd)); if (document) { IAccessible* msaaAccessible = nullptr; document->GetNativeInterface((void**)&msaaAccessible); // does an addref if (msaaAccessible) { LRESULT result = ::LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref msaaAccessible->Release(); // release extra addref return result; } } } return 0; } case WM_NCHITTEST: { LRESULT lRet = ::DefWindowProc(hWnd, msg, wParam, lParam); if (HTCLIENT == lRet) lRet = HTTRANSPARENT; return lRet; } } return ::DefWindowProcW(hWnd, msg, wParam, lParam); }
LRESULT CALLBACK nsAccessNodeWrap::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Note, this window's message handling should not invoke any call that // may result in a cross-process ipc call. Doing so may violate RPC // message semantics. switch (msg) { case WM_GETOBJECT: { if (lParam == OBJID_CLIENT) { DocAccessible* document = sHWNDCache.GetWeak(static_cast<void*>(hWnd)); if (document) { IAccessible* msaaAccessible = NULL; document->GetNativeInterface((void**)&msaaAccessible); // does an addref if (msaaAccessible) { LRESULT result = ::LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref msaaAccessible->Release(); // release extra addref return result; } } } return 0; } case WM_NCHITTEST: { LRESULT lRet = ::DefWindowProc(hWnd, msg, wParam, lParam); if (HTCLIENT == lRet) lRet = HTTRANSPARENT; return lRet; } } return ::DefWindowProcW(hWnd, msg, wParam, lParam); }
IAccessible* IAccessibleFromIdentifier(int docHandle, int ID) { // We want to bypass oleacc proxying, // so retrieve the IAccessible directly rather than using AccessibleObjectFromEvent. LRESULT lres; if (!(lres = SendMessage((HWND)docHandle, WM_GETOBJECT, 0, OBJID_CLIENT))) return NULL; IAccessible* root = NULL; if (ObjectFromLresult(lres, IID_IAccessible, 0, (void**)&root) != S_OK) return NULL; VARIANT varChild; varChild.vt = VT_I4; varChild.lVal = ID; IDispatch* childDisp; HRESULT hres = root->get_accChild(varChild, &childDisp); root->Release(); if (hres != S_OK) return NULL; IAccessible* childAcc; hres = childDisp->QueryInterface(IID_IAccessible, (void**)&childAcc); childDisp->Release(); if (hres != S_OK) return NULL; return childAcc; }
void AdobeFlashVBufBackend_t::render(VBufStorage_buffer_t* buffer, int docHandle, int ID, VBufStorage_controlFieldNode_t* oldNode) { if (!oldNode) { // This is the initial render. WCHAR* wclass = (WCHAR*)malloc(sizeof(WCHAR) * 256); if (!wclass) return; if (GetClassName((HWND)UlongToHandle(docHandle), wclass, 256) == 0) { free(wclass); return; } this->isWindowless = wcscmp(wclass, L"Internet Explorer_Server") == 0; free(wclass); } DWORD_PTR res=0; //Get an IAccessible by sending WM_GETOBJECT directly to bypass any proxying, to speed things up. if (SendMessageTimeout((HWND)UlongToHandle(docHandle), WM_GETOBJECT, 0, isWindowless ? ID : OBJID_CLIENT, SMTO_ABORTIFHUNG, 2000, &res) == 0 || res == 0) { //Failed to send message or window does not support IAccessible return; } IAccessible* pacc=NULL; if(ObjectFromLresult(res,IID_IAccessible,0,(void**)&pacc)!=S_OK) { //Could not get the IAccessible pointer from the WM_GETOBJECT result return; } nhAssert(pacc); //must get a valid IAccessible object HRESULT hres; VARIANT varChild; varChild.vt=VT_I4; IAccessible* childAcc; if (ID != CHILDID_SELF && !this->isWindowless) { // We have the root accessible, but a specific child has been requested. varChild.lVal = ID; IDispatch* childDisp = NULL; hres = pacc->get_accChild(varChild, &childDisp); pacc->Release(); if (hres != S_OK || !childDisp) return; childAcc = NULL; hres = childDisp->QueryInterface(IID_IAccessible, (void**)&childAcc); childDisp->Release(); if (hres != S_OK || !childAcc) return; pacc = childAcc; } if (!oldNode || ID == this->rootID) { // This is the root node. VBufStorage_controlFieldNode_t* parentNode=buffer->addControlFieldNode(NULL,NULL,docHandle,ID,TRUE); parentNode->addAttribute(L"IAccessible::role",L"10"); VBufStorage_fieldNode_t* previousNode=NULL; long childCount=0; pacc->get_accChildCount(&childCount); if (this->getAccId(pacc) != -1) { // We can get IDs from accessibles. VARIANT* varChildren; if (!(varChildren = (VARIANT*)malloc(sizeof(VARIANT) * childCount))) return; if (FAILED(AccessibleChildren(pacc, 0, childCount, varChildren, &childCount))) childCount = 0; for (long i = 0; i < childCount; ++i) { if (varChildren[i].vt != VT_DISPATCH || !varChildren[i].pdispVal) { VariantClear(&(varChildren[i])); continue; } childAcc = NULL; hres = varChildren[i].pdispVal->QueryInterface(IID_IAccessible, (void**)&childAcc); VariantClear(&(varChildren[i])); if (hres != S_OK) continue; int childId = getAccId(childAcc); previousNode = this->renderControlContent(buffer, parentNode, previousNode, docHandle, childId, childAcc); childAcc->Release(); } free(varChildren); } else { // We can't get IDs from accessibles. // The only way to get IDs is to just try them sequentially. // accessiblesByLocation maps ((x, y), id) to (accessible, id). // This allows us to order by location and, where that is the same, ID. // We need this because added children always have larger IDs, // even if they were inserted between two other children. map<pair<pair<long, long>, long>, pair<IAccessible*, long>> accessiblesByLocation; // Keep going until we have childCount children. for(int i=1;i<1000&&static_cast<long>(accessiblesByLocation.size())<childCount;++i) { IDispatch* childDisp=NULL; varChild.lVal=i; if (pacc->get_accChild(varChild, &childDisp) != S_OK || !childDisp) continue; childAcc = NULL; hres = childDisp->QueryInterface(IID_IAccessible, (void**)&childAcc); childDisp->Release(); if (hres != S_OK || !childAcc) continue; long left=0, top=0, width=0, height=0; varChild.lVal = CHILDID_SELF; if (childAcc->accLocation(&left, &top, &width, &height, varChild) != S_OK) left=top=width=height=0; accessiblesByLocation[make_pair(make_pair(top + height / 2, left + width / 2), i)] = make_pair(childAcc, i); } for (map<pair<pair<long, long>, long>, pair<IAccessible*, long>>::iterator i = accessiblesByLocation.begin(); i != accessiblesByLocation.end(); ++i) { previousNode = this->renderControlContent(buffer, parentNode, previousNode, docHandle, i->second.second, i->second.first); i->second.first->Release(); } } } else { // This is a child that is being re-rendered. this->renderControlContent(buffer, NULL, NULL, docHandle, ID, pacc); } pacc->Release(); }
// Recursively give information about an object void MyFrame::LogObject(int indent, IAccessible* obj) { wxString name, role; if (indent == 0) { GetInfo(obj, 0, name, role); wxString str; str.Printf(wxT("Name = %s; Role = %s"), name.c_str(), role.c_str()); str.Pad(indent, wxT(' '), false); Log(str); } long childCount = 0; if (S_OK == obj->get_accChildCount(& childCount)) { wxString str; str.Printf(wxT("There are %d children."), (int) childCount); str.Pad(indent, wxT(' '), false); Log(str); Log(wxT("")); } int i; for (i = 1; i <= childCount; i++) { GetInfo(obj, i, name, role); wxString str; str.Printf(wxT("%d) Name = %s; Role = %s"), i, name.c_str(), role.c_str()); str.Pad(indent, wxT(' '), false); Log(str); VARIANT var; VariantInit(& var); var.vt = VT_I4; var.lVal = i; IDispatch* pDisp = NULL; IAccessible* childObject = NULL; if (S_OK == obj->get_accChild(var, & pDisp) && pDisp) { wxString str; str.Printf(wxT("This is a real object.")); str.Pad(indent+4, wxT(' '), false); Log(str); if (pDisp->QueryInterface(IID_IAccessible, (LPVOID*) & childObject) == S_OK) { LogObject(indent + 4, childObject); childObject->Release(); } pDisp->Release(); } else { wxString str; str.Printf(wxT("This is an element.")); str.Pad(indent+4, wxT(' '), false); Log(str); } // Log(wxT("")); } }
void MyFrame::OnQuery(wxCommandEvent& WXUNUSED(event)) { m_textCtrl->Clear(); IAccessible* accessibleFrame = NULL; if (S_OK != AccessibleObjectFromWindow((HWND) GetHWND(), OBJID_CLIENT, IID_IAccessible, (void**) & accessibleFrame)) { Log(wxT("Could not get object.")); return; } if (accessibleFrame) { //Log(wxT("Got an IAccessible for the frame.")); LogObject(0, accessibleFrame); Log(wxT("Checking children using AccessibleChildren()...")); // Now check the AccessibleChildren function works OK long childCount = 0; if (S_OK != accessibleFrame->get_accChildCount(& childCount)) { Log(wxT("Could not get number of children.")); accessibleFrame->Release(); return; } else if (childCount == 0) { Log(wxT("No children.")); accessibleFrame->Release(); return; } long obtained = 0; VARIANT *var = new VARIANT[childCount]; int i; for (i = 0; i < childCount; i++) { VariantInit(& (var[i])); var[i].vt = VT_DISPATCH; } if (S_OK == AccessibleChildren(accessibleFrame, 0, childCount, var, &obtained)) { for (i = 0; i < childCount; i++) { IAccessible* childAccessible = NULL; if (var[i].pdispVal) { if (var[i].pdispVal->QueryInterface(IID_IAccessible, (LPVOID*) & childAccessible) == S_OK) { var[i].pdispVal->Release(); wxString name, role; GetInfo(childAccessible, 0, name, role); wxString str; str.Printf(wxT("Found child %s/%s"), name.c_str(), role.c_str()); Log(str); childAccessible->Release(); } else { var[i].pdispVal->Release(); } } } } else { Log(wxT("AccessibleChildren failed.")); } delete[] var; accessibleFrame->Release(); } }