// Copyright (c) 1996-2000 Microsoft Corporation // -------------------------------------------------------------------------- // // DEFAULT.CPP // // This is the default implementation for CAccessible. All other objects // usually inherit from this one. // // Implements: // IUnknown // QueryInterface // AddRef // Release // IDispatch // GetTypeInfoCount // GetTypeInfo // GetIDsOfNames // Invoke // IAccessible // get_accParent // get_accChildCount // get_accChild // get_accName // get_accValue // get_accDescription // get_accRole // get_accState // get_accHelp // get_accHelpTopic // get_accKeyboardShortcut // get_accFocus // get_accSelection // get_accDefaultAction // accSelect // accLocation // accNavigate // accHitTest // accDoDefaultAction // put_accName // put_accValue // IEnumVARIANT // Next // Skip // Reset // Clone // IOleWindow // GetWindow // ContextSensitiveHelp // // Helper Functions // SetupChildren // ValidateChild // InitTypeInfo // TermTypeInfo // // -------------------------------------------------------------------------- #include "oleacc_p.h" #include "default.h" #include "PropMgr_Util.h" CAccessible::CAccessible( CLASS_ENUM eclass ) { // NOTE: we rely on the fact that operator new (see memchk.cpp) uses LocalAlloc // with a flag specifying zero-inited memory to initialize our variables. // (If we want ot used cached memoey slots, we should change this to explicitly // init; or make sure cache slots are cleared before use.) if( eclass == CLASS_NONE ) m_pClassInfo = NULL; else m_pClassInfo = & g_ClassInfo[ eclass ]; } CAccessible::~CAccessible() { // Nothing to do // (Dtor only exists so that the base class has a virtual dtor, so that // derived class dtors work properly when deleted through a base class ptr) } // -------------------------------------------------------------------------- // // CAccessible::GetWindow() // // This is from IOleWindow, to let us get the HWND from an IAccessible*. // // --------------------------------------------------------------------------- STDMETHODIMP CAccessible::GetWindow(HWND* phwnd) { *phwnd = m_hwnd; return(S_OK); } // -------------------------------------------------------------------------- // // CAccessible::ContextSensitiveHelp() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::ContextSensitiveHelp(BOOL fEnterMode) { UNUSED(fEnterMode); return(E_NOTIMPL); } // -------------------------------------------------------------------------- // // CAccessible::InitTypeInfo() // // This initializes our type info when we need it for IDispatch junk. // // -------------------------------------------------------------------------- HRESULT CAccessible::InitTypeInfo(void) { HRESULT hr; ITypeLib *piTypeLib; if (m_pTypeInfo) return(S_OK); // Try getting the typelib from the registry hr = LoadRegTypeLib(LIBID_Accessibility, 1, 0, 0, &piTypeLib); if (FAILED(hr)) { OLECHAR wszPath[MAX_PATH]; // Try loading directly. #ifdef UNICODE MyGetModuleFileName(NULL, wszPath, ARRAYSIZE(wszPath)); #else TCHAR szPath[MAX_PATH]; MyGetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)); MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, ARRAYSIZE(wszPath)); #endif hr = LoadTypeLib(wszPath, &piTypeLib); } if (SUCCEEDED(hr)) { hr = piTypeLib->GetTypeInfoOfGuid(IID_IAccessible, &m_pTypeInfo); piTypeLib->Release(); if (!SUCCEEDED(hr)) m_pTypeInfo = NULL; } return(hr); } // -------------------------------------------------------------------------- // // CAccessible::TermTypeInfo() // // This frees the type info if it is around // // -------------------------------------------------------------------------- void CAccessible::TermTypeInfo(void) { if (m_pTypeInfo) { m_pTypeInfo->Release(); m_pTypeInfo = NULL; } } // -------------------------------------------------------------------------- // // CAccessible::QueryInterface() // // This responds to // * IUnknown // * IDispatch // * IEnumVARIANT // * IAccessible // // The following comment is somewhat old and obsolte: // Some code will also respond to IText. That code must override our // QueryInterface() implementation. // No current plans to support IText anywhere; but derived classes that // want to implement other interfaces will have to override QI. // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::QueryInterface( REFIID riid, void** ppv ) { *ppv = NULL; if( riid == IID_IUnknown || riid == IID_IDispatch || riid == IID_IAccessible ) { *ppv = static_cast< IAccessible * >( this ); } else if( riid == IID_IEnumVARIANT ) { *ppv = static_cast< IEnumVARIANT * >( this ); } else if( riid == IID_IOleWindow ) { *ppv = static_cast< IOleWindow * >( this ); } else if( riid == IID_IServiceProvider ) { *ppv = static_cast< IServiceProvider * >( this ); } else if( riid == IID_IAccIdentity && m_pClassInfo && m_pClassInfo->fSupportsAnnotation ) { // Only allow to QI to this interface if this // proxy type supports it... *ppv = static_cast< IAccIdentity * >( this ); } else { return E_NOINTERFACE; } ((LPUNKNOWN) *ppv)->AddRef(); return NOERROR; } // -------------------------------------------------------------------------- // // CAccessible::AddRef() // // -------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CAccessible::AddRef() { return(++m_cRef); } // -------------------------------------------------------------------------- // // CAccessible::Release() // // -------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CAccessible::Release() { if ((--m_cRef) == 0) { TermTypeInfo(); delete this; return 0; } return(m_cRef); } // -------------------------------------------------------------------------- // // CAccessible::GetTypeInfoCount() // // This hands off to our typelib for IAccessible(). Note that // we only implement one type of object for now. BOGUS! What about IText? // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::GetTypeInfoCount(UINT * pctInfo) { HRESULT hr; InitPv(pctInfo); hr = InitTypeInfo(); if (SUCCEEDED(hr)) *pctInfo = 1; return(hr); } // -------------------------------------------------------------------------- // // CAccessible::GetTypeInfo() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::GetTypeInfo(UINT itInfo, LCID lcid, ITypeInfo ** ppITypeInfo) { HRESULT hr; UNUSED(lcid); // locale id is unused if (ppITypeInfo == NULL) return(E_POINTER); InitPv(ppITypeInfo); if (itInfo != 0) return(TYPE_E_ELEMENTNOTFOUND); hr = InitTypeInfo(); if (SUCCEEDED(hr)) { m_pTypeInfo->AddRef(); *ppITypeInfo = m_pTypeInfo; } return(hr); } // -------------------------------------------------------------------------- // // CAccessible::GetIDsOfNames() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgDispID) { HRESULT hr; UNUSED(lcid); // locale id is unused UNUSED(riid); // riid is unused hr = InitTypeInfo(); if (!SUCCEEDED(hr)) return(hr); return(m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispID)); } // -------------------------------------------------------------------------- // // CAccessible::Invoke() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::Invoke(DISPID dispID, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) { HRESULT hr; UNUSED(lcid); // locale id is unused UNUSED(riid); // riid is unused hr = InitTypeInfo(); if (!SUCCEEDED(hr)) return(hr); return(m_pTypeInfo->Invoke((IAccessible *)this, dispID, wFlags, pDispParams, pvarResult, pExcepInfo, puArgErr)); } // -------------------------------------------------------------------------- // // CAccessible::get_accParent() // // NOTE: Not only is this the default handler, it can also serve as // parameter checking for overriding implementations. // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accParent(IDispatch ** ppdispParent) { InitPv(ppdispParent); if (m_hwnd) return(AccessibleObjectFromWindow(m_hwnd, OBJID_WINDOW, IID_IDispatch, (void **)ppdispParent)); else return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::get_accChildCount() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accChildCount(long* pChildCount) { SetupChildren(); *pChildCount = m_cChildren; return(S_OK); } // -------------------------------------------------------------------------- // // CAccessible::get_accChild() // // No children. // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accChild(VARIANT varChild, IDispatch** ppdispChild) { InitPv(ppdispChild); if (! ValidateChild(&varChild) || !varChild.lVal) return(E_INVALIDARG); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::get_accValue() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accValue(VARIANT varChild, BSTR * pszValue) { InitPv(pszValue); if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::get_accDescription() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accDescription(VARIANT varChild, BSTR * pszDescription) { InitPv(pszDescription); if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::get_accHelp() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accHelp(VARIANT varChild, BSTR* pszHelp) { InitPv(pszHelp); if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::get_accHelpTopic() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild, long* pidTopic) { InitPv(pszHelpFile); InitPv(pidTopic); if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::get_accKeyboardShortcut() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accKeyboardShortcut(VARIANT varChild, BSTR* pszShortcut) { InitPv(pszShortcut); if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::get_accFocus() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accFocus(VARIANT *pvarFocus) { InitPvar(pvarFocus); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::get_accSelection() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accSelection(VARIANT* pvarSelection) { InitPvar(pvarSelection); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::get_accDefaultAction() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::get_accDefaultAction(VARIANT varChild, BSTR* pszDefaultAction) { InitPv(pszDefaultAction); if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::accSelect() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::accSelect(long flagsSel, VARIANT varChild) { if (! ValidateChild(&varChild)) return(E_INVALIDARG); if (! ValidateSelFlags(flagsSel)) return(E_INVALIDARG); return(S_FALSE); } #if 0 // -------------------------------------------------------------------------- // // CAccessible::accLocation() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild) { InitAccLocation(pxLeft, pyTop, pcxWidth, pcyHeight); if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(S_OK); } #endif // -------------------------------------------------------------------------- // // CAccessible::accNavigate() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::accNavigate(long navFlags, VARIANT varStart, VARIANT *pvarEnd) { InitPvar(pvarEnd); if (! ValidateChild(&varStart)) return(E_INVALIDARG); if (!ValidateNavDir(navFlags, varStart.lVal)) return(E_INVALIDARG); return(S_FALSE); } #if 0 // -------------------------------------------------------------------------- // // CAccessible::accHitTest() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::accHitTest(long xLeft, long yTop, VARIANT* pvarChild) { InitPvar(pvarChild); return(S_FALSE); } #endif // -------------------------------------------------------------------------- // // CAccessible::accDoDefaultAction() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::accDoDefaultAction(VARIANT varChild) { if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::put_accName() // // CALLER frees the string // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::put_accName(VARIANT varChild, BSTR szName) { UNUSED(szName); if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::put_accValue() // // CALLER frees the string // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::put_accValue(VARIANT varChild, BSTR szValue) { UNUSED(szValue); if (! ValidateChild(&varChild)) return(E_INVALIDARG); return(S_FALSE); } // -------------------------------------------------------------------------- // // CAccessible::Next // // Handles simple Next, where we return back indeces for child elements. // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::Next(ULONG celt, VARIANT* rgvar, ULONG* pceltFetched) { VARIANT* pvar; long cFetched; long iCur; SetupChildren(); // Can be NULL if (pceltFetched) *pceltFetched = 0; pvar = rgvar; cFetched = 0; iCur = m_idChildCur; // // Loop through our items // while ((cFetched < (long)celt) && (iCur < m_cChildren)) { cFetched++; iCur++; // // Note this gives us (index)+1 because we incremented iCur // pvar->vt = VT_I4; pvar->lVal = iCur; ++pvar; } // // Advance the current position // m_idChildCur = iCur; // // Fill in the number fetched // if (pceltFetched) *pceltFetched = cFetched; // // Return S_FALSE if we grabbed fewer items than requested // return((cFetched < (long)celt) ? S_FALSE : S_OK); } // -------------------------------------------------------------------------- // // CAccessible::Skip() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::Skip(ULONG celt) { SetupChildren(); m_idChildCur += celt; if (m_idChildCur > m_cChildren) m_idChildCur = m_cChildren; // // We return S_FALSE if at the end // return((m_idChildCur >= m_cChildren) ? S_FALSE : S_OK); } // -------------------------------------------------------------------------- // // CAccessible::Reset() // // -------------------------------------------------------------------------- STDMETHODIMP CAccessible::Reset(void) { m_idChildCur = 0; return(S_OK); } STDMETHODIMP CAccessible::QueryService( REFGUID guidService, REFIID riid, void **ppv ) { if( guidService == IIS_IsOleaccProxy ) { return QueryInterface( riid, ppv ); } else { // MSDN mentions SVC_E_UNKNOWNSERVICE as the return code, but that's not in any of the headers. // Returning E_INVALIDARG instead. (Don't want to use E_NOINTERFACE, since that clashes with // QI's return value, making it hard to distinguish between valid service+invalid interface vs // invalid service. return E_INVALIDARG; } } STDMETHODIMP CAccessible::GetIdentityString ( DWORD dwIDChild, BYTE ** ppIDString, DWORD * pdwIDStringLen ) { *ppIDString = NULL; *pdwIDStringLen = 0; if( ! m_pClassInfo || ! m_pClassInfo->fSupportsAnnotation ) { // Shouldn't get here - shouldn't QI to this interface if the above are false. Assert( FALSE ); return E_FAIL; } BYTE * pKeyData = (BYTE *) CoTaskMemAlloc( HWNDKEYSIZE ); if( ! pKeyData ) { return E_OUTOFMEMORY; } MakeHwndKey( pKeyData, m_hwnd, m_pClassInfo->dwObjId, dwIDChild ); *ppIDString = pKeyData; *pdwIDStringLen = HWNDKEYSIZE; return S_OK; } // -------------------------------------------------------------------------- // // CAccessible::ValidateChild() // // -------------------------------------------------------------------------- BOOL CAccessible::ValidateChild(VARIANT *pvar) { // // This validates a VARIANT parameter and translates missing/empty // params. // SetupChildren(); // Missing parameter, a la VBA TryAgain: switch (pvar->vt) { case VT_VARIANT | VT_BYREF: VariantCopy(pvar, pvar->pvarVal); goto TryAgain; case VT_ERROR: if (pvar->scode != DISP_E_PARAMNOTFOUND) return(FALSE); // FALL THRU case VT_EMPTY: pvar->vt = VT_I4; pvar->lVal = 0; break; // remove this! VT_I2 is not valid!! #ifdef VT_I2_IS_VALID // it isn't now... case VT_I2: pvar->vt = VT_I4; pvar->lVal = (long)pvar->iVal; // FALL THROUGH #endif case VT_I4: if ((pvar->lVal < 0) || (pvar->lVal > m_cChildren)) return(FALSE); break; default: return(FALSE); } return(TRUE); } // -------------------------------------------------------------------------- // // SetupChildren() // // Default implementation of SetupChildren, does nothing. // // -------------------------------------------------------------------------- void CAccessible::SetupChildren(void) { }