X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ed5317e538f5d3d7b2731b1e4248137f014139a6..793db75554d2d2bc5dc9b0fc42c0b7aa03a44183:/src/msw/ole/access.cpp diff --git a/src/msw/ole/access.cpp b/src/msw/ole/access.cpp index 3bc308ca47..0dfdd300ac 100644 --- a/src/msw/ole/access.cpp +++ b/src/msw/ole/access.cpp @@ -17,7 +17,7 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "access.h" #endif @@ -38,7 +38,7 @@ #include "wx/log.h" #include "wx/access.h" -#include +#include "wx/msw/wrapwin.h" // for some compilers, the entire ole2.h must be included, not only oleauto.h #if wxUSE_NORLANDER_HEADERS || defined(__WATCOMC__) @@ -47,6 +47,7 @@ #include #include +#include #include "wx/msw/ole/oleutils.h" @@ -78,7 +79,7 @@ class wxIEnumVARIANT : public IEnumVARIANT { public: wxIEnumVARIANT(const wxVariant& variant); - ~wxIEnumVARIANT() { } + virtual ~wxIEnumVARIANT() { } DECLARE_IUNKNOWN_METHODS; @@ -326,6 +327,16 @@ public: VARIANT *pVarResult, EXCEPINFO *pExcepInfo, unsigned int *puArgErr ); +// Helpers + + // Gets the standard IAccessible interface for the given child or object. + // Call Release if this is non-NULL. + IAccessible* GetChildStdAccessible(int id); + + // Gets the IAccessible interface for the given child or object. + // Call Release if this is non-NULL. + IAccessible* GetChildAccessible(int id); + private: wxAccessible *m_pAccessible; // pointer to C++ class we belong to @@ -359,6 +370,7 @@ wxIAccessible::wxIAccessible(wxAccessible *pAccessible) STDMETHODIMP wxIAccessible::accHitTest(long xLeft, long yLeft, VARIANT* pVarID) { + wxLogTrace(wxT("access"), wxT("accHitTest")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; @@ -377,7 +389,7 @@ STDMETHODIMP wxIAccessible::accHitTest(long xLeft, long yLeft, VARIANT* pVarID) // Use standard interface instead. IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); if (!stdInterface) - return E_FAIL; + return E_NOTIMPL; else return stdInterface->accHitTest(xLeft, yLeft, pVarID); } @@ -394,13 +406,12 @@ STDMETHODIMP wxIAccessible::accHitTest(long xLeft, long yLeft, VARIANT* pVarID) { wxIAccessible* childIA = childObject->GetIAccessible(); if (!childIA) - return E_FAIL; + return E_NOTIMPL; - if (childIA->QueryInterface(IID_IDispatch, (LPVOID*) pVarID->pdispVal) != S_OK) + if (childIA->QueryInterface(IID_IDispatch, (LPVOID*) & pVarID->pdispVal) != S_OK) return E_FAIL; pVarID->vt = VT_DISPATCH; - pVarID->pdispVal->AddRef(); return S_OK; } } @@ -416,7 +427,11 @@ STDMETHODIMP wxIAccessible::accHitTest(long xLeft, long yLeft, VARIANT* pVarID) return S_FALSE; } - return E_FAIL; + #if 0 + // all cases above already cause some return action so below line + // is unreachable and cause unnecessary warning + return E_NOTIMPL; + #endif } // Retrieves the specified object's current screen location. All visual objects must @@ -424,6 +439,7 @@ STDMETHODIMP wxIAccessible::accHitTest(long xLeft, long yLeft, VARIANT* pVarID) STDMETHODIMP wxIAccessible::accLocation ( long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varID) { + wxLogTrace(wxT("access"), wxT("accLocation")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; @@ -436,12 +452,22 @@ STDMETHODIMP wxIAccessible::accLocation ( long* pxLeft, long* pyTop, long* pcxWi if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varID); + // Try to use child object directly. + if (varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varID); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varID); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varID); } else { @@ -452,7 +478,7 @@ STDMETHODIMP wxIAccessible::accLocation ( long* pxLeft, long* pyTop, long* pcxWi return S_OK; } - return E_FAIL; + return E_NOTIMPL; } // Traverses to another user interface element within a container and retrieves the object. @@ -463,94 +489,152 @@ STDMETHODIMP wxIAccessible::accNavigate ( long navDir, VARIANT varStart, VARIANT wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; - - if (varStart.vt != VT_I4) + wxLogTrace(wxT("access"), wxString(wxT("accNavigate for ")) + m_pAccessible->GetWindow()->GetClassInfo()->GetClassName()); + + if ((varStart.vt != VT_I4 && varStart.vt != VT_EMPTY) + #if 0 + // according to MSDN and sources varStart.vt is unsigned + // so below line cause warning "Condition is always false" + || varStart.vt < 0 + #endif + ) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for accNavigate")); return E_INVALIDARG; + } wxAccessible* elementObject = NULL; int elementId = 0; VariantInit(pVarEnd); wxNavDir navDirWX = wxNAVDIR_FIRSTCHILD; + wxString navStr; + switch (navDir) { case NAVDIR_DOWN: navDirWX = wxNAVDIR_DOWN; + navStr = wxT("wxNAVDIR_DOWN"); break; case NAVDIR_FIRSTCHILD: navDirWX = wxNAVDIR_FIRSTCHILD; + navStr = wxT("wxNAVDIR_FIRSTCHILD"); break; case NAVDIR_LASTCHILD: navDirWX = wxNAVDIR_LASTCHILD; + navStr = wxT("wxNAVDIR_LASTCHILD"); break; case NAVDIR_LEFT: navDirWX = wxNAVDIR_LEFT; + navStr = wxT("wxNAVDIR_LEFT"); break; case NAVDIR_NEXT: navDirWX = wxNAVDIR_NEXT; + navStr = wxT("wxNAVDIR_NEXT"); break; case NAVDIR_PREVIOUS: navDirWX = wxNAVDIR_PREVIOUS; + navStr = wxT("wxNAVDIR_PREVIOUS"); break; case NAVDIR_RIGHT: navDirWX = wxNAVDIR_RIGHT; + navStr = wxT("wxNAVDIR_RIGHT"); break; case NAVDIR_UP: navDirWX = wxNAVDIR_UP; + navStr = wxT("wxNAVDIR_UP"); break; + default: + { + wxLogTrace(wxT("access"), wxT("Unknown NAVDIR symbol")); + break; + } } + wxLogTrace(wxT("access"), navStr); wxAccStatus status = m_pAccessible->Navigate(navDirWX, varStart.lVal, & elementId, & elementObject); if (status == wxACC_FAIL) + { + wxLogTrace(wxT("access"), wxT("wxAccessible::Navigate failed")); return E_FAIL; + } + + if (status == wxACC_FALSE) + { + wxLogTrace(wxT("access"), wxT("wxAccessible::Navigate found no object in this direction")); + return S_FALSE; + } if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->accNavigate ( navDir, varStart, pVarEnd); + wxLogTrace(wxT("access"), wxT("Navigate not implemented")); + + // Try to use child object directly. + if (varStart.vt == VT_I4 && varStart.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varStart.lVal); + if (childAccessible) + { + varStart.lVal = 0; + HRESULT hResult = childAccessible->accNavigate(navDir, varStart, pVarEnd); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->accNavigate(navDir, varStart, pVarEnd); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->accNavigate(navDir, varStart, pVarEnd); } else { if (elementObject) { + wxLogTrace(wxT("access"), wxT("Getting wxIAccessible and calling QueryInterface for Navigate")); wxIAccessible* objectIA = elementObject->GetIAccessible(); if (!objectIA) + { + wxLogTrace(wxT("access"), wxT("No wxIAccessible")); return E_FAIL; + } - if (objectIA->QueryInterface(IID_IDispatch, (LPVOID*) pVarEnd->pdispVal) != S_OK) + HRESULT hResult = objectIA->QueryInterface(IID_IDispatch, (LPVOID*) & pVarEnd->pdispVal); + if (hResult != S_OK) + { + wxLogTrace(wxT("access"), wxT("QueryInterface failed")); return E_FAIL; + } + wxLogTrace(wxT("access"), wxT("Called QueryInterface for Navigate")); pVarEnd->vt = VT_DISPATCH; - pVarEnd->pdispVal->AddRef(); return S_OK; } else if (elementId > 0) { + wxLogTrace(wxT("access"), wxT("Returning element id from Navigate")); pVarEnd->vt = VT_I4; pVarEnd->lVal = elementId; return S_OK; } else { + wxLogTrace(wxT("access"), wxT("No object in accNavigate")); pVarEnd->vt = VT_EMPTY; return S_FALSE; } } - return E_FAIL; + wxLogTrace(wxT("access"), wxT("Failing Navigate")); + return E_NOTIMPL; } // Retrieves the address of an IDispatch interface for the specified child. @@ -558,12 +642,16 @@ STDMETHODIMP wxIAccessible::accNavigate ( long navDir, VARIANT varStart, VARIANT STDMETHODIMP wxIAccessible::get_accChild ( VARIANT varChildID, IDispatch** ppDispChild) { + wxLogTrace(wxT("access"), wxT("get_accChild")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; if (varChildID.vt != VT_I4) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for get_accChild")); return E_INVALIDARG; + } if (varChildID.lVal == CHILDID_SELF) { @@ -576,16 +664,22 @@ STDMETHODIMP wxIAccessible::get_accChild ( VARIANT varChildID, IDispatch** ppDis wxAccStatus status = m_pAccessible->GetChild(varChildID.lVal, & child); if (status == wxACC_FAIL) + { + wxLogTrace(wxT("access"), wxT("GetChild failed")); return E_FAIL; + } if (status == wxACC_NOT_IMPLEMENTED) { // Use standard interface instead. IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); if (!stdInterface) - return E_FAIL; + return E_NOTIMPL; else + { + wxLogTrace(wxT("access"), wxT("Using standard interface for get_accChild")); return stdInterface->get_accChild (varChildID, ppDispChild); + } } else { @@ -593,16 +687,28 @@ STDMETHODIMP wxIAccessible::get_accChild ( VARIANT varChildID, IDispatch** ppDis { wxIAccessible* objectIA = child->GetIAccessible(); if (!objectIA) - return E_FAIL; - *ppDispChild = objectIA; - objectIA->AddRef(); + return E_NOTIMPL; + + if (objectIA->QueryInterface(IID_IDispatch, (LPVOID*) ppDispChild) != S_OK) + { + wxLogTrace(wxT("access"), wxT("QueryInterface failed in get_accChild")); + return E_FAIL; + } + return S_OK; } else + { + wxLogTrace(wxT("access"), wxT("Not an accessible object")); return S_FALSE; // Indicates it's not an accessible object + } } - return E_FAIL; + #if 0 + // all cases above already cause some return action so below line + // is unreachable and cause unnecessary warning + return E_NOTIMPL; + #endif } // Retrieves the number of children that belong to this object. @@ -610,6 +716,7 @@ STDMETHODIMP wxIAccessible::get_accChild ( VARIANT varChildID, IDispatch** ppDis STDMETHODIMP wxIAccessible::get_accChildCount ( long* pCountChildren) { + wxLogTrace(wxT("access"), wxT("get_accChildCount")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; @@ -624,9 +731,16 @@ STDMETHODIMP wxIAccessible::get_accChildCount ( long* pCountChildren) // Use standard interface instead. IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); if (!stdInterface) - return E_FAIL; + return E_NOTIMPL; else - return stdInterface->get_accChildCount (pCountChildren); + { + wxLogTrace(wxT("access"), wxT("Using standard interface for get_accChildCount")); + HRESULT res = stdInterface->get_accChildCount (pCountChildren); + wxString str; + str.Printf(wxT("Number of children was %d"), (int) (*pCountChildren)); + wxLogTrace(wxT("access"), str); + return res; + } } else { @@ -634,7 +748,11 @@ STDMETHODIMP wxIAccessible::get_accChildCount ( long* pCountChildren) return S_OK; } - return E_FAIL; + #if 0 + // all cases above already cause some return action so below line + // is unreachable and cause unnecessary warning + return E_NOTIMPL; + #endif } // Retrieves the IDispatch interface of the object's parent. @@ -642,21 +760,27 @@ STDMETHODIMP wxIAccessible::get_accChildCount ( long* pCountChildren) STDMETHODIMP wxIAccessible::get_accParent ( IDispatch** ppDispParent) { + wxLogTrace(wxT("access"), wxT("get_accParent")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; wxAccessible* parent = NULL; wxAccStatus status = m_pAccessible->GetParent(& parent); + if (status == wxACC_FAIL) return E_FAIL; - - if (status == wxACC_NOT_IMPLEMENTED) + + // It doesn't seem acceptable to return S_FALSE with a NULL + // ppDispParent, so if we have no wxWindows parent, we leave + // it to the standard interface. + if (status == wxACC_NOT_IMPLEMENTED || !parent) { + wxLogTrace(wxT("access"), wxT("Using standard interface to get the parent.")); // Use standard interface instead. IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); if (!stdInterface) - return E_FAIL; + return E_NOTIMPL; else return stdInterface->get_accParent (ppDispParent); } @@ -668,28 +792,31 @@ STDMETHODIMP wxIAccessible::get_accParent ( IDispatch** ppDispParent) if (!objectIA) return E_FAIL; + wxLogTrace(wxT("access"), wxT("About to call QueryInterface")); if (objectIA->QueryInterface(IID_IDispatch, (LPVOID*) ppDispParent) != S_OK) + { + wxLogTrace(wxT("access"), wxT("Failed QueryInterface")); return E_FAIL; + } - (*ppDispParent)->AddRef(); + wxLogTrace(wxT("access"), wxT("Returning S_OK for get_accParent")); return S_OK; -/* - wxIAccessible* objectIA = parent->GetIAccessible(); - if (!objectIA) - return E_FAIL; - objectIA->AddRef(); - *ppDispParent = objectIA; - return S_OK; -*/ } else { + // This doesn't seem to be allowed, despite the documentation, + // so we handle it higher up by using the standard interface. + wxLogTrace(wxT("access"), wxT("Returning NULL parent because there was none")); *ppDispParent = NULL; - return S_OK; + return S_FALSE; } } - return E_FAIL; + #if 0 + // all cases above already cause some return action so below line + // is unreachable and cause unnecessary warning + return E_NOTIMPL; + #endif } // Performs the object's default action. Not all objects have a default @@ -697,12 +824,16 @@ STDMETHODIMP wxIAccessible::get_accParent ( IDispatch** ppDispParent) STDMETHODIMP wxIAccessible::accDoDefaultAction(VARIANT varID) { + wxLogTrace(wxT("access"), wxT("accDoDefaultAction")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; if (varID.vt != VT_I4) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for accDoDefaultAction")); return E_INVALIDARG; + } wxAccStatus status = m_pAccessible->DoDefaultAction(varID.lVal); if (status == wxACC_FAIL) @@ -713,12 +844,22 @@ STDMETHODIMP wxIAccessible::accDoDefaultAction(VARIANT varID) if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->accDoDefaultAction(varID); + // Try to use child object directly. + if (varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->accDoDefaultAction(varID); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->accDoDefaultAction(varID); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->accDoDefaultAction(varID); } return E_FAIL; } @@ -728,12 +869,16 @@ STDMETHODIMP wxIAccessible::accDoDefaultAction(VARIANT varID) STDMETHODIMP wxIAccessible::get_accDefaultAction ( VARIANT varID, BSTR* pszDefaultAction) { + wxLogTrace(wxT("access"), wxT("get_accDefaultAction")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; if (varID.vt != VT_I4) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for get_accDefaultAction")); return E_INVALIDARG; + } wxString defaultAction; wxAccStatus status = m_pAccessible->GetDefaultAction(varID.lVal, & defaultAction); @@ -745,12 +890,22 @@ STDMETHODIMP wxIAccessible::get_accDefaultAction ( VARIANT varID, BSTR* pszDefau if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->get_accDefaultAction (varID, pszDefaultAction); + // Try to use child object directly. + if (varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->get_accDefaultAction(varID, pszDefaultAction); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accDefaultAction(varID, pszDefaultAction); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accDefaultAction(varID, pszDefaultAction); } else { @@ -774,12 +929,16 @@ STDMETHODIMP wxIAccessible::get_accDefaultAction ( VARIANT varID, BSTR* pszDefau STDMETHODIMP wxIAccessible::get_accDescription ( VARIANT varID, BSTR* pszDescription) { + wxLogTrace(wxT("access"), wxT("get_accDescription")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; if (varID.vt != VT_I4) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for get_accDescription")); return E_INVALIDARG; + } wxString description; wxAccStatus status = m_pAccessible->GetDescription(varID.lVal, & description); @@ -788,12 +947,22 @@ STDMETHODIMP wxIAccessible::get_accDescription ( VARIANT varID, BSTR* pszDescrip if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->get_accDescription (varID, pszDescription); + // Try to use child object directly. + if (varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->get_accDescription(varID, pszDescription); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accDescription(varID, pszDescription); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accDescription(varID, pszDescription); } else { @@ -809,7 +978,7 @@ STDMETHODIMP wxIAccessible::get_accDescription ( VARIANT varID, BSTR* pszDescrip return S_OK; } } - return E_FAIL; + return E_NOTIMPL; } // Retrieves an object's Help property string. @@ -817,12 +986,16 @@ STDMETHODIMP wxIAccessible::get_accDescription ( VARIANT varID, BSTR* pszDescrip STDMETHODIMP wxIAccessible::get_accHelp ( VARIANT varID, BSTR* pszHelp) { + wxLogTrace(wxT("access"), wxT("get_accHelp")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; if (varID.vt != VT_I4) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for get_accHelp")); return E_INVALIDARG; + } wxString helpString; wxAccStatus status = m_pAccessible->GetHelpText(varID.lVal, & helpString); @@ -831,12 +1004,22 @@ STDMETHODIMP wxIAccessible::get_accHelp ( VARIANT varID, BSTR* pszHelp) if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->get_accHelp (varID, pszHelp); + // Try to use child object directly. + if (varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->get_accHelp(varID, pszHelp); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accHelp(varID, pszHelp); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accHelp (varID, pszHelp); } else { @@ -852,7 +1035,7 @@ STDMETHODIMP wxIAccessible::get_accHelp ( VARIANT varID, BSTR* pszHelp) return S_OK; } } - return E_FAIL; + return E_NOTIMPL; } // Retrieves the full path of the WinHelp file associated with the specified @@ -863,12 +1046,16 @@ STDMETHODIMP wxIAccessible::get_accHelp ( VARIANT varID, BSTR* pszHelp) STDMETHODIMP wxIAccessible::get_accHelpTopic ( BSTR* pszHelpFile, VARIANT varChild, long* pidTopic) { + wxLogTrace(wxT("access"), wxT("get_accHelpTopic")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; if (varChild.vt != VT_I4) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for get_accHelpTopic")); return E_INVALIDARG; + } wxAccStatus status = wxACC_NOT_IMPLEMENTED; if (status == wxACC_FAIL) @@ -876,14 +1063,24 @@ STDMETHODIMP wxIAccessible::get_accHelpTopic ( BSTR* pszHelpFile, VARIANT varChi if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->get_accHelpTopic (pszHelpFile, varChild, pidTopic); + // Try to use child object directly. + if (varChild.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varChild.lVal); + if (childAccessible) + { + varChild.lVal = 0; + HRESULT hResult = childAccessible->get_accHelpTopic(pszHelpFile, varChild, pidTopic); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accHelpTopic(pszHelpFile, varChild, pidTopic); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accHelpTopic (pszHelpFile, varChild, pidTopic); } - return E_FAIL; + return E_NOTIMPL; } // Retrieves the specified object's shortcut key or access key, also known as @@ -892,6 +1089,7 @@ STDMETHODIMP wxIAccessible::get_accHelpTopic ( BSTR* pszHelpFile, VARIANT varChi STDMETHODIMP wxIAccessible::get_accKeyboardShortcut ( VARIANT varID, BSTR* pszKeyboardShortcut) { + wxLogTrace(wxT("access"), wxT("get_accKeyboardShortcut")); *pszKeyboardShortcut = NULL; wxASSERT (m_pAccessible != NULL); @@ -899,21 +1097,34 @@ STDMETHODIMP wxIAccessible::get_accKeyboardShortcut ( VARIANT varID, BSTR* pszKe return E_FAIL; if (varID.vt != VT_I4) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for get_accKeyboardShortcut")); return E_INVALIDARG; + } wxString keyboardShortcut; - wxAccStatus status = m_pAccessible->GetHelpText(varID.lVal, & keyboardShortcut); + wxAccStatus status = m_pAccessible->GetKeyboardShortcut(varID.lVal, & keyboardShortcut); if (status == wxACC_FAIL) return E_FAIL; if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->get_accKeyboardShortcut(varID, pszKeyboardShortcut); + // Try to use child object directly. + if (varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->get_accKeyboardShortcut(varID, pszKeyboardShortcut); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accKeyboardShortcut(varID, pszKeyboardShortcut); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accKeyboardShortcut (varID, pszKeyboardShortcut); } else { @@ -929,7 +1140,7 @@ STDMETHODIMP wxIAccessible::get_accKeyboardShortcut ( VARIANT varID, BSTR* pszKe return S_OK; } } - return E_FAIL; + return E_NOTIMPL; } // Retrieves the name of the specified object. @@ -937,6 +1148,7 @@ STDMETHODIMP wxIAccessible::get_accKeyboardShortcut ( VARIANT varID, BSTR* pszKe STDMETHODIMP wxIAccessible::get_accName ( VARIANT varID, BSTR* pszName) { + wxLogTrace(wxT("access"), wxT("get_accName")); *pszName = NULL; wxASSERT (m_pAccessible != NULL); @@ -944,7 +1156,10 @@ STDMETHODIMP wxIAccessible::get_accName ( VARIANT varID, BSTR* pszName) return E_FAIL; if (varID.vt != VT_I4) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for get_accName")); return E_INVALIDARG; + } wxString name; @@ -955,12 +1170,22 @@ STDMETHODIMP wxIAccessible::get_accName ( VARIANT varID, BSTR* pszName) if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->get_accName (varID, pszName); + // Try to use child object directly. + if (varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->get_accName(varID, pszName); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accName(varID, pszName); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accName (varID, pszName); } else { @@ -968,7 +1193,7 @@ STDMETHODIMP wxIAccessible::get_accName ( VARIANT varID, BSTR* pszName) *pszName = basicString.Get(); return S_OK; } - return E_FAIL; + return E_NOTIMPL; } // Retrieves information that describes the role of the specified object. @@ -976,12 +1201,16 @@ STDMETHODIMP wxIAccessible::get_accName ( VARIANT varID, BSTR* pszName) STDMETHODIMP wxIAccessible::get_accRole ( VARIANT varID, VARIANT* pVarRole) { + wxLogTrace(wxT("access"), wxT("get_accRole")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; if (varID.vt != VT_I4) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for get_accRole")); return E_INVALIDARG; + } VariantInit(pVarRole); @@ -994,12 +1223,22 @@ STDMETHODIMP wxIAccessible::get_accRole ( VARIANT varID, VARIANT* pVarRole) if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->get_accRole (varID, pVarRole); + // Try to use child object directly. + if (varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->get_accRole(varID, pVarRole); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accRole(varID, pVarRole); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accRole (varID, pVarRole); } else { @@ -1014,7 +1253,7 @@ STDMETHODIMP wxIAccessible::get_accRole ( VARIANT varID, VARIANT* pVarRole) return S_OK; } - return E_FAIL; + return E_NOTIMPL; } // Retrieves the current state of the specified object. @@ -1022,12 +1261,16 @@ STDMETHODIMP wxIAccessible::get_accRole ( VARIANT varID, VARIANT* pVarRole) STDMETHODIMP wxIAccessible::get_accState ( VARIANT varID, VARIANT* pVarState) { + wxLogTrace(wxT("access"), wxT("get_accState")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; - if (varID.vt != VT_I4) + if (varID.vt != VT_I4 && varID.vt != VT_EMPTY) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for get_accState")); return E_INVALIDARG; + } long wxstate = 0; @@ -1037,12 +1280,22 @@ STDMETHODIMP wxIAccessible::get_accState ( VARIANT varID, VARIANT* pVarState) if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->get_accState (varID, pVarState); + // Try to use child object directly. + if (varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->get_accState(varID, pVarState); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accState(varID, pVarState); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accState (varID, pVarState); } else { @@ -1051,7 +1304,7 @@ STDMETHODIMP wxIAccessible::get_accState ( VARIANT varID, VARIANT* pVarState) pVarState->vt = VT_I4; return S_OK; } - return E_FAIL; + return E_NOTIMPL; } // Retrieves the value of the specified object. @@ -1059,12 +1312,16 @@ STDMETHODIMP wxIAccessible::get_accState ( VARIANT varID, VARIANT* pVarState) STDMETHODIMP wxIAccessible::get_accValue ( VARIANT varID, BSTR* pszValue) { + wxLogTrace(wxT("access"), wxT("get_accValue")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; if (varID.vt != VT_I4) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for get_accValue")); return E_INVALIDARG; + } wxString strValue; @@ -1075,12 +1332,22 @@ STDMETHODIMP wxIAccessible::get_accValue ( VARIANT varID, BSTR* pszValue) if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->get_accValue (varID, pszValue); + // Try to use child object directly. + if (varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->get_accValue(varID, pszValue); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accValue(varID, pszValue); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->get_accValue (varID, pszValue); } else { @@ -1088,7 +1355,7 @@ STDMETHODIMP wxIAccessible::get_accValue ( VARIANT varID, BSTR* pszValue) * pszValue = basicString.Get(); return S_OK; } - return E_FAIL; + return E_NOTIMPL; } // Modifies the selection or moves the keyboard focus of the @@ -1097,12 +1364,16 @@ STDMETHODIMP wxIAccessible::get_accValue ( VARIANT varID, BSTR* pszValue) STDMETHODIMP wxIAccessible::accSelect ( long flagsSelect, VARIANT varID ) { + wxLogTrace(wxT("access"), wxT("get_accSelect")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; - if (varID.vt != VT_I4) + if (varID.vt != VT_I4 && varID.vt != VT_EMPTY) + { + wxLogTrace(wxT("access"), wxT("Invalid arg for accSelect")); return E_INVALIDARG; + } wxAccSelectionFlags wxsel = wxConvertFromWindowsSelFlag(flagsSelect); @@ -1112,17 +1383,27 @@ STDMETHODIMP wxIAccessible::accSelect ( long flagsSelect, VARIANT varID ) if (status == wxACC_NOT_IMPLEMENTED) { - // Use standard interface instead. - IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); - if (!stdInterface) - return E_FAIL; - else - return stdInterface->accSelect ( flagsSelect, varID ); + // Try to use child object directly. + if (varID.lVal > 0 && varID.lVal > 0) + { + IAccessible* childAccessible = GetChildAccessible(varID.lVal); + if (childAccessible) + { + varID.lVal = 0; + HRESULT hResult = childAccessible->accSelect(flagsSelect, varID); + childAccessible->Release(); + return hResult; + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->accSelect(flagsSelect, varID); + } + else if (m_pAccessible->GetIAccessibleStd()) + return ((IAccessible*) m_pAccessible->GetIAccessibleStd())->accSelect(flagsSelect, varID); } else return S_OK; - return E_FAIL; + return E_NOTIMPL; } // Retrieves the object that has the keyboard focus. All objects @@ -1130,6 +1411,7 @@ STDMETHODIMP wxIAccessible::accSelect ( long flagsSelect, VARIANT varID ) STDMETHODIMP wxIAccessible::get_accFocus ( VARIANT* pVarID) { + wxLogTrace(wxT("access"), wxT("get_accFocus")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; @@ -1147,7 +1429,7 @@ STDMETHODIMP wxIAccessible::get_accFocus ( VARIANT* pVarID) // Use standard interface instead. IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); if (!stdInterface) - return E_FAIL; + return E_NOTIMPL; else return stdInterface->get_accFocus (pVarID); } @@ -1157,19 +1439,17 @@ STDMETHODIMP wxIAccessible::get_accFocus ( VARIANT* pVarID) { pVarID->vt = VT_I4; pVarID->lVal = CHILDID_SELF; - return S_OK; - } + return S_OK; } else { wxIAccessible* childIA = childObject->GetIAccessible(); if (!childIA) - return E_FAIL; + return E_NOTIMPL; - if (childIA->QueryInterface(IID_IDispatch, (LPVOID*) pVarID->pdispVal) != S_OK) + if (childIA->QueryInterface(IID_IDispatch, (LPVOID*) & pVarID->pdispVal) != S_OK) return E_FAIL; pVarID->vt = VT_DISPATCH; - pVarID->pdispVal->AddRef(); return S_OK; } } @@ -1185,7 +1465,11 @@ STDMETHODIMP wxIAccessible::get_accFocus ( VARIANT* pVarID) return S_FALSE; } - return E_FAIL; + #if 0 + // all cases above already cause some return action so below line + // is unreachable and cause unnecessary warning + return E_NOTIMPL; + #endif } // Retrieves the selected children of this object. All objects @@ -1193,6 +1477,7 @@ STDMETHODIMP wxIAccessible::get_accFocus ( VARIANT* pVarID) STDMETHODIMP wxIAccessible::get_accSelection ( VARIANT * pVarChildren) { + wxLogTrace(wxT("access"), wxT("get_accSelection")); wxASSERT (m_pAccessible != NULL); if (!m_pAccessible) return E_FAIL; @@ -1209,7 +1494,7 @@ STDMETHODIMP wxIAccessible::get_accSelection ( VARIANT * pVarChildren) // Use standard interface instead. IAccessible* stdInterface = (IAccessible*)m_pAccessible->GetIAccessibleStd(); if (!stdInterface) - return E_FAIL; + return E_NOTIMPL; else return stdInterface->get_accSelection (pVarChildren); } @@ -1227,13 +1512,12 @@ STDMETHODIMP wxIAccessible::get_accSelection ( VARIANT * pVarChildren) wxAccessible* childObject = (wxAccessible*) selections.GetVoidPtr(); wxIAccessible* childIA = childObject->GetIAccessible(); if (!childIA) - return E_FAIL; + return E_NOTIMPL; - if (childIA->QueryInterface(IID_IDispatch, (LPVOID*) pVarChildren->pdispVal) != S_OK) + if (childIA->QueryInterface(IID_IDispatch, (LPVOID*) & pVarChildren->pdispVal) != S_OK) return E_FAIL; pVarChildren->vt = VT_DISPATCH; - pVarChildren->pdispVal->AddRef(); return S_OK; } @@ -1251,12 +1535,12 @@ STDMETHODIMP wxIAccessible::get_accSelection ( VARIANT * pVarChildren) } } - return E_FAIL; + return E_NOTIMPL; } // Get type info -STDMETHODIMP wxIAccessible::GetTypeInfo(unsigned int typeInfo, LCID lcid, ITypeInfo** ppTypeInfo) +STDMETHODIMP wxIAccessible::GetTypeInfo(unsigned int WXUNUSED(typeInfo), LCID WXUNUSED(lcid), ITypeInfo** ppTypeInfo) { *ppTypeInfo = NULL; return E_NOTIMPL; @@ -1272,22 +1556,135 @@ STDMETHODIMP wxIAccessible::GetTypeInfoCount(unsigned int* typeInfoCount) // Get ids of names -STDMETHODIMP wxIAccessible::GetIDsOfNames(REFIID riid, OLECHAR** names, unsigned int cNames, - LCID lcid, DISPID* dispId) +STDMETHODIMP wxIAccessible::GetIDsOfNames(REFIID WXUNUSED(riid), OLECHAR** WXUNUSED(names), unsigned int WXUNUSED(cNames), + LCID WXUNUSED(lcid), DISPID* WXUNUSED(dispId)) { return E_NOTIMPL; } // Invoke -STDMETHODIMP wxIAccessible::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, - WORD wFlags, DISPPARAMS *pDispParams, - VARIANT *pVarResult, EXCEPINFO *pExcepInfo, - unsigned int *puArgErr ) +STDMETHODIMP wxIAccessible::Invoke(DISPID WXUNUSED(dispIdMember), REFIID WXUNUSED(riid), LCID WXUNUSED(lcid), + WORD WXUNUSED(wFlags), DISPPARAMS *WXUNUSED(pDispParams), + VARIANT *WXUNUSED(pVarResult), EXCEPINFO *WXUNUSED(pExcepInfo), + unsigned int *WXUNUSED(puArgErr) ) { return E_NOTIMPL; } +// Gets the standard IAccessible interface for the given child or object. +// Call Release if this is non-NULL. +IAccessible* wxIAccessible::GetChildStdAccessible(int id) +{ + if (id == 0) + { + IAccessible* obj = (IAccessible*)m_pAccessible->GetIAccessibleStd(); + + obj->AddRef(); + return obj; + } + else + { + VARIANT var; + VariantInit(& var); + var.vt = VT_I4; + var.lVal = id; + IDispatch* pDispatch = NULL; + if (S_OK == get_accChild ( var, & pDispatch)) + { + IAccessible* childAccessible = NULL; + if (pDispatch->QueryInterface(IID_IAccessible, (LPVOID*) & childAccessible) == S_OK) + { + pDispatch->Release(); + wxIAccessible* c = (wxIAccessible*) childAccessible; + IAccessible* stdChildAccessible = (IAccessible*) c->m_pAccessible->GetIAccessibleStd(); + stdChildAccessible->AddRef(); + childAccessible->Release(); + return stdChildAccessible; + } + else + { + pDispatch->Release(); + } + } + } + +#if 0 + { + // Loop until we find the right id + long nChildren = 0; + this->get_accChildCount(& nChildren); + + int i; + for (i = 0; i < nChildren; i++) + { + long obtained = 0; + VARIANT var; + VariantInit(& var); + var.vt = VT_I4; + if (S_OK == AccessibleChildren(this, i, 1, & var, &obtained)) + { + if (var.lVal == id) + { + VariantInit(& var); + var.vt = VT_DISPATCH; + if (S_OK == AccessibleChildren(this, i, 1, & var, &obtained)) + { + IAccessible* childAccessible = NULL; + if (var.pdispVal->QueryInterface(IID_IAccessible, (LPVOID*) & childAccessible) == S_OK) + { + var.pdispVal->Release(); + return childAccessible; + } + else + { + var.pdispVal->Release(); + } + } + } + break; + } + } + } +#endif + return NULL; +} + +// Gets the IAccessible interface for the given child or object. +// Call Release if this is non-NULL. +IAccessible* wxIAccessible::GetChildAccessible(int id) +{ + if (id == 0) + { + IAccessible* obj = this; + + obj->AddRef(); + return obj; + } + else + { + VARIANT var; + VariantInit(& var); + var.vt = VT_I4; + var.lVal = id; + IDispatch* pDispatch = NULL; + if (S_OK == get_accChild ( var, & pDispatch)) + { + IAccessible* childAccessible = NULL; + if (pDispatch->QueryInterface(IID_IAccessible, (LPVOID*) & childAccessible) == S_OK) + { + pDispatch->Release(); + return childAccessible; + } + else + { + pDispatch->Release(); + } + } + } + return NULL; +} + // ---------------------------------------------------------------------------- // wxAccessible implementation // ---------------------------------------------------------------------------- @@ -1323,13 +1720,8 @@ void* wxAccessible::GetIAccessibleStd() if (GetWindow()) { -#if 0 - HRESULT retCode = ::CreateStdAccessibleProxy((HWND) GetWindow()->GetHWND(), - wxT("wxWindowClass"), OBJID_CLIENT, IID_IAccessible, (void**) & m_pIAccessibleStd); -#else HRESULT retCode = ::CreateStdAccessibleObject((HWND) GetWindow()->GetHWND(), OBJID_CLIENT, IID_IAccessible, (void**) & m_pIAccessibleStd); -#endif if (retCode == S_OK) return m_pIAccessibleStd; else @@ -1341,6 +1733,14 @@ void* wxAccessible::GetIAccessibleStd() return NULL; } +// Sends an event when something changes in an accessible object. +void wxAccessible::NotifyEvent(int eventType, wxWindow* window, wxAccObject objectType, + int objectId) +{ + ::NotifyWinEvent((DWORD) eventType, (HWND) window->GetHWND(), + (LONG) objectType, (LONG) objectId); +} + // Utilities // Convert to Windows role @@ -1564,15 +1964,15 @@ int wxConvertToWindowsSelFlag(wxAccSelectionFlags wxsel) { int sel = 0; - if (sel & wxACC_SEL_TAKEFOCUS) + if (wxsel & wxACC_SEL_TAKEFOCUS) sel |= SELFLAG_TAKEFOCUS; - if (sel & wxACC_SEL_TAKESELECTION) + if (wxsel & wxACC_SEL_TAKESELECTION) sel |= SELFLAG_TAKESELECTION; - if (sel & wxACC_SEL_EXTENDSELECTION) + if (wxsel & wxACC_SEL_EXTENDSELECTION) sel |= SELFLAG_EXTENDSELECTION; - if (sel & wxACC_SEL_ADDSELECTION) + if (wxsel & wxACC_SEL_ADDSELECTION) sel |= SELFLAG_ADDSELECTION; - if (sel & wxACC_SEL_REMOVESELECTION) + if (wxsel & wxACC_SEL_REMOVESELECTION) sel |= SELFLAG_REMOVESELECTION; return sel; }