WindowsXP-SP1/windows/oleacc/oleacc/default.cpp
2020-09-30 16:53:49 +02:00

887 lines
21 KiB
C++

// 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)
{
}