//=======================================================================
//		File:	ACCESS.CPP
//		Date:	4-1-97
//		Name:
//
//		Desc:	This file contains the implementation of the CAccClient
//				class.  This class is used by the server application
//				defined in SERVER.CPP to provide Accessible support
//				for the client area (and all its children) of the main
//				window.
//
//		Copyright (C) 1997 by Microsoft Corporation.  All rights reserved.
//		See bottom of file for disclaimer.
//=======================================================================

//=======================================================================
//		Include Files
//=======================================================================

#include <windows.h>
#include <winable.h>
#include <ole2.h>
#include <oleacc.h>
#include <math.h>
#include "resource.h"
#include "access.h"
#include "server.h"
#include "status.h"
#include "enumvar.h"



//=======================================================================
//		Private Defines
//=======================================================================

	//-----------------------------------------------------
	//	The child IDs as exposed by CAccClient.
	//-----------------------------------------------------
#define CHILDID_RING_ICON		2
#define CHILDID_MONEY_ICON		4
#define CHILDID_ART_ICON		8
#define CHILDID_MANSION_ICON	16
#define CHILDID_PERSON_ICON		32
#define CHILDID_PLANE_ICON		64
#define CHILDID_CLOTHING_ICON	128
#define	CHILDID_BUTTON			256
#define CHILDID_STATBAR			512


	//-----------------------------------------------------
	//	The number of children for which CAccClient
	//	  provides Accessible support (the number of
	//	  icons plus the push button and the status bar).
	//-----------------------------------------------------
#define	NUM_CHILDREN			(NUM_ICONS + 2)




//=======================================================================
//		Public Class Methods - CAccClient
//=======================================================================

//-----------------------------------------------------------------------
//	CAccClient::CAccClient()
//
//	DESCRIPTION:
//
//		CAccClient class constructor.
//
//	PARAMETERS:
//
//		None.
//
//	RETURNS:
//
//		None.
//
// ----------------------------------------------------------------------

CAccClient::CAccClient( void )
{
	//-----------------------------------------------------
	//	Simply set our pointer data members to NULL.
	//	  The real "construction" is implemented in
	//	  Initialize().
	//-----------------------------------------------------

    m_hWnd = NULL;
	m_hInst = NULL;
    m_pTypeInfo = NULL;
    m_pDefAccClient = NULL;
}




//-----------------------------------------------------------------------
//	CAccClient::~CAccClient()
//
//	DESCRIPTION:
//
//		CAccClient class destructor.  Releases the type information
//		interface and the standard Accessible window client area object.
//
//	PARAMETERS:
//
//		None.
//
//	RETURNS:
//
//		None.
//
// ----------------------------------------------------------------------

CAccClient::~CAccClient( void )
{
    if ( m_pTypeInfo )
    {
        m_pTypeInfo->Release();
        m_pTypeInfo = NULL;
    }

    if ( m_pDefAccClient )
    {
        m_pDefAccClient->Release();
        m_pDefAccClient = NULL;
    }
}




//-----------------------------------------------------------------------
//	CAccClient::Initialize()
//
//	DESCRIPTION:
//
//		Initializes the state of the CAccClient object, performing
//		tasks that might normally be done in a class constructor but
//		are done here to trap any errors.
//
//	PARAMETERS:
//
//		hWnd			Handle to the HWND object with which this
//						  Accessible object is associated.  This
//						  is the handle to our main window.
//
//		hInst			Instance handle for this instance of the
//						  application.
//
//	RETURNS:
//
//		HRESULT			NOERROR if the CAccClient object is
//						  initialized successfully, a COM error
//						  code otherwise.
//
//	NOTES:
//
//		It is assumed that this method will be called for the object
//		immediately after and only after the object is constructed.
//
// ----------------------------------------------------------------------

HRESULT CAccClient::Initialize( HWND hWnd, HINSTANCE hInst )
{
	HRESULT		hr;
	ITypeLib *	piTypeLib;


    
	//-----------------------------------------------------
	//	Set our window handle data member equal to the
	//	  hWnd parameter.
	//-----------------------------------------------------

	m_hWnd = hWnd;


	//-----------------------------------------------------
	//	Set our instance handle data member equal to the
	//	  hInst parameter.
	//-----------------------------------------------------

	m_hInst = hInst;


	//-----------------------------------------------------
	//	For our client window, create a system provided
	//	  Accessible object which implements the default
	//	  client window Accessibility behavior.
	//
	//	Our implementation of CAccClient will use the
	//	  default object's implementation as needed.  In
	//	  essence, CAccClient "inherits" its functionality
	//	  from the standard object, "customizing" or
	//	  "overriding" various methods for which the
	//	  standard implementation is insufficent for the
	//	  specifics of the window for which CAccClient
	//	  provides Accessibility.
	//-----------------------------------------------------

	hr = CreateStdAccessibleObject( m_hWnd,
	                                OBJID_CLIENT,
									IID_IAccessible,
	                                (void **) &m_pDefAccClient );

	if ( FAILED( hr ) )
		return hr;


	//-----------------------------------------------------
    //	Obtain an ITypeInfo pointer to our type library.
	//	  The ITypeInfo pointer is used to implement the
	//	  IDispatch interface.
	//-----------------------------------------------------

	//-----------------------------------------------------
	//	First, attempt to load the Accessibility type
	//	  library version 1.0 using the registry.
	//-----------------------------------------------------

    hr = LoadRegTypeLib( LIBID_Accessibility, 1, 0, 0, &piTypeLib );


	//-----------------------------------------------------
	//	If we fail to load the type library from the
	//	  registry information, explicitly try to load
	//	  it from the MSAA system DLL.
	//-----------------------------------------------------

    if ( FAILED( hr ) )
    {
        static OLECHAR szOleAcc[] = L"OLEACC.DLL";

        hr = LoadTypeLib( szOleAcc, &piTypeLib );
    }


	//-----------------------------------------------------
	//	If we successfully load the type library, attempt
	//	  to get the IAccessible type description
	//	  (ITypeInfo pointer) from the type library.
	//-----------------------------------------------------

    if ( SUCCEEDED( hr ) )
    {
        hr = piTypeLib->GetTypeInfoOfGuid( IID_IAccessible, &m_pTypeInfo );
        piTypeLib->Release();
    }


	return hr;
}




//-----------------------------------------------------------------------
//	CAccClient::QueryInterface()
//
//	DESCRIPTION:
//
//		Implements the IUnknown interface method QueryInterface().
//
//	PARAMETERS:
//
//		riid			[in]  The requested interface's IID.
//		ppv				[out] If the requested interface is supported,
//						      ppv points to the location of a pointer
//						      to the requested interface.  If the
//						      requested interface is not supported,
//						      ppv is set to NULL.
//
//	RETURNS:
//
//		HRESULT			S_OK if the interface is supported,
//						  E_NOINTERFACE if the interface is not
//						  supported, or some other COM error
//						  if the IEnumVARIANT interface is requested
//						  but cannot be delivered.
//
//	NOTES:
//
//		CAccClient correctly supports the IUnknown, IDispatch and
//		IAccessible interfaces.  CAccClient also incorrectly supports
//		the IEnumVARIANT interface (to return a VARIANT enumerator
//		containing all its children).  When the IEnumVARIANT
//		interface is requested, an enumerator is created and a
//		pointer to its IEnumVARIANT interface is returned.
//
//		The support for IEnumVARIANT is incorrect because the
//		interface pointer returned is not symmetric with respect
//		to the interface from which it was obtained.  For example,
//		assume that pIA is a pointer to an IAccessible interface.
//		Then, even though pIA->QueryInterface(IID_IEnumVARIANT)
//		succeeds and returns pIEV,
//		pIEV->QueryInterface(IID_Accessibility) will fail because
//		the enumerator has no knowledge of any interface except
//		itself (and IUnknown).
//
//		The original design of MSAA called for IAccessible
//		objects to also be enumerators of their children.  But
//		this design doesn't allow for different clients of the
//		Accessible object to have different enumerations of its
//		children and that is a potentially hazardous situation.
//		(Assume there is an Accessible object that is also a
//		VARIANT enumerator, A, and two clients, C1 and C2.
//		Since C1 and C2 each may be pre-empted will using A,
//		the following is a one of many examples that would pose
//		a problem for at least one client:
//
//			C1:  A->Reset()
//			C1:  A->Skip( 5 )
//			C2:  A->Reset()
//			C1:  A->Next()  ! C1 does not get the child it expects
//
//		So, although it breaks the rules of COM, QueryInterface()
//		as implemented below obtains a distinct VARIANT enumerator
//		for each request.  A better solution to this issue would
//		be if the IAccessible interface provided a method to get
//		the child enumeration or if MSAA provided an exported API
//		to perform this task.
//
// ----------------------------------------------------------------------

STDMETHODIMP CAccClient::QueryInterface( REFIID riid, void** ppv )
{
    *ppv = NULL;

	
	//-----------------------------------------------------
	//	If the IUnknown, IDispatch, or IAccessible
	//	  interface is desired, simply cast the this
	//	  pointer appropriately.
	//-----------------------------------------------------

	if ( riid == IID_IUnknown )
        *ppv = (LPUNKNOWN) this;

	else if ( riid == IID_IDispatch )
        *ppv = (IDispatch *) this;

	else if ( riid == IID_IAccessible )
        *ppv = (IAccessible *)this;


	//-----------------------------------------------------
	//	If the IEnumVARIANT interface is desired, create
	//	  a new VARIANT enumerator which contains all
	//	  the Accessible object's children.
	//-----------------------------------------------------

	else if (riid == IID_IEnumVARIANT)
	{
		CEnumVariant*	pcenum;
		HRESULT			hr;

		hr = CreateVarEnumOfAllChildren( &pcenum );

		if ( FAILED( hr ) )
			return hr;

		*ppv = (IEnumVARIANT *) pcenum;
	}


	//-----------------------------------------------------
	//	If the desired interface isn't one we know about,
	//	  return E_NOINTERFACE.
	//-----------------------------------------------------

    else
        return E_NOINTERFACE;


	//-----------------------------------------------------
	//	Increase the reference count of any interface
	//	  returned.
	//-----------------------------------------------------

    ((LPUNKNOWN) *ppv)->AddRef();



    return S_OK;
}




//-----------------------------------------------------------------------
//	CAccClient::AddRef()
//
//	DESCRIPTION:
//
//		Implements the IUnknown interface method AddRef().
//
//	PARAMETERS:
//
//		None.
//
//	RETURNS:
//
//		ULONG			Current reference count.
//
//	NOTES:
//
//		The lifetime of the Accessible object is governed by the
//		lifetime of the HWND object for which it provides
//		Accessibility.  The object is created in response to the
//		first WM_GETOBJECT message that the server application
//		is ready to process and is destroyed when the server's
//		main window is destroyed.  Since the object's lifetime
//		is not dependent on a reference count, the object has no
//		internal mechanism for tracking reference counting and
//		AddRef() and Release() always return one.
//
//-----------------------------------------------------------------------

STDMETHODIMP_(ULONG) CAccClient::AddRef( void )
{
	return 1L;
}




//-----------------------------------------------------------------------
//	CAccClient::Release()
//
//	DESCRIPTION:
//
//		Implements the IUnknown interface method Release().
//
//	PARAMETERS:
//
//		None.
//
//	RETURNS:
//
//		ULONG			Current reference count.
//
//	NOTES:
//
//		The lifetime of the Accessible object is governed by the
//		lifetime of the HWND object for which it provides
//		Accessibility.  The object is created in response to the
//		first WM_GETOBJECT message that the server application
//		is ready to process and is destroyed when the server's
//		main window is destroyed.  Since the object's lifetime
//		is not dependent on a reference count, the object has no
//		internal mechanism for tracking reference counting and
//		AddRef() and Release() always return one.
//
//-----------------------------------------------------------------------

STDMETHODIMP_(ULONG) CAccClient::Release( void )
{
	return 1L;
}




//-----------------------------------------------------------------------
//	CAccClient::GetTypeInfoCount()
//
//	DESCRIPTION:
//
//		Implements the IDispatch interface method GetTypeInfoCount().
//
//		Retrieves the number of type information interfaces that an
//		object provides (either 0 or 1).
//
//	PARAMETERS:
//
//		pctInfo		[out] Points to location that receives the
//							number of type information interfaces
//							that the object provides. If the object
//							provides type information, this number
//							is set to 1; otherwise it's set to 0.
//
//	RETURNS:
//
//		HRESULT			  S_OK if the function succeeds or 
//							E_INVALIDARG if pctInfo is invalid.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::GetTypeInfoCount( UINT *pctInfo )
{
    if ( !pctInfo )
        return E_INVALIDARG;

    *pctInfo = ( m_pTypeInfo == NULL ? 1 : 0 );

    return S_OK;
}




//-----------------------------------------------------------------------
//	CAccClient::GetTypeInfo()
//
//	DESCRIPTION:
//
//		Implements the IDispatch interface method GetTypeInfo().
//
//		Retrieves a type information object, which can be used to
//		get the type information for an interface.
//
//	PARAMETERS:
//
//		itinfo		[in]  The type information to return. If this value
//							is 0, the type information for the IDispatch
//							implementation is to be retrieved.
//
//		lcid		[in]  The locale ID for the type information.
//
//		ppITypeInfo	[out] Receives a pointer to the type information
//							object requested.
//
//	RETURNS:
//
//		HRESULT			  S_OK if the function succeeded (the TypeInfo
//							element exists), TYPE_E_ELEMENTNOTFOUND if
//							itinfo is not equal to zero, or 
//							E_INVALIDARG if ppITypeInfo is invalid.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::GetTypeInfo( UINT itinfo, LCID lcid, ITypeInfo** ppITypeInfo )
{
    if ( !ppITypeInfo )
        return E_INVALIDARG;

    *ppITypeInfo = NULL;

    if ( itinfo != 0 )
        return TYPE_E_ELEMENTNOTFOUND;
    else if ( m_pTypeInfo == NULL )
        return E_NOTIMPL;

    *ppITypeInfo = m_pTypeInfo;
    m_pTypeInfo->AddRef();

    return S_OK;
}




//-----------------------------------------------------------------------
//	CAccClient::GetIDsOfNames()
//
//	DESCRIPTION:
//
//		Implements the IDispatch interface method GetIDsOfNames().
//
//		Maps a single member and an optional set of argument names
//		to a corresponding set of integer DISPIDs, which may be used
//		on subsequent calls to IDispatch::Invoke.
//
//	PARAMETERS:
//
//		riid		[in]  Reserved for future use. Must be NULL.
//
//		rgszNames	[in]  Passed-in array of names to be mapped.
//
//		cNames		[in]  Count of the names to be mapped.
//
//		lcid		[in]  The locale context in which to interpret
//							the names.
//
//		rgdispid	[out] Caller-allocated array, each element of
//							which contains an ID corresponding to
//							one of the names passed in the rgszNames
//							array.  The first element represents the
//							member name; the subsequent elements
//							represent each of the member's parameters.
//
//	RETURNS:
//
//		HRESULT			  S_OK if the function succeeded,
//							E_OUTOFMEMORY if there is not enough
//							memory to complete the call,
//							DISP_E_UNKNOWNNAME if one or more of
//							the names were not known, or
//							DISP_E_UNKNOWNLCID if the LCID was
//							not recognized.
//
//	NOTES:
//
//		This method simply delegates the call to
//		ITypeInfo::GetIDsOfNames().
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::GetIDsOfNames( REFIID riid, OLECHAR ** rgszNames, UINT cNames,
                                        LCID lcid, DISPID * rgdispid )
{
    if ( m_pTypeInfo == NULL )
        return E_NOTIMPL;

    return( m_pTypeInfo->GetIDsOfNames( rgszNames, cNames, rgdispid ) );
}




//-----------------------------------------------------------------------
//	CAccClient::Invoke()
//
//	DESCRIPTION:
//
//		Implements the IDispatch interface method Invoke().
//
//		Provides access to properties and methods exposed by the
//		Accessible object.
//
//	PARAMETERS:
//
//		dispidMember	[in]  Identifies the dispatch member.
//
//		riid			[in]  Reserved for future use. Must be NULL.
//
//		lcid			[in]  The locale context in which to interpret
//								the names.
//
//		wFlags			[in]  Flags describing the context of the
//									Invoke call.
//
//		pdispparams		[in,] Pointer to a structure containing an
//						[out]	array of arguments, array of argument
//								dispatch IDs for named arguments, and
//								counts for number of elements in the
//								arrays.
//
//		pvarResult		[in,] Pointer to where the result is to be
//						[out]	stored, or NULL if the caller expects
//								no result.  This argument is ignored
//								if DISPATCH_PROPERTYPUT or
//								DISPATCH_PROPERTYPUTREF is specified.
//
//		pexcepinfo		[out] Pointer to a structure containing
//								exception information.  This structure
//								should be filled in if DISP_E_EXCEPTION
//								is returned.
//
//		puArgErr		[out] The index within rgvarg of the first
//								argument that has an error.  Arguments
//								are stored in pdispparams->rgvarg in
//								reverse order, so the first argument
//								is the one with the highest index in
//								the array.
//
//	RETURNS:
//
//		HRESULT			  S_OK on success, dispatch error (DISP_E_*)
//							or E_NOTIMPL otherwise.
//
//	NOTES:
//
//		This method simply delegates the call to ITypeInfo::Invoke().
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::Invoke( DISPID dispid,
                                 REFIID riid,
                                 LCID lcid,
                                 WORD wFlags,
                                 DISPPARAMS * pdispparams,
                                 VARIANT *pvarResult,
                                 EXCEPINFO *pexcepinfo,
                                 UINT *puArgErr )
{
    if ( m_pTypeInfo == NULL )
        return E_NOTIMPL;

    return m_pTypeInfo->Invoke( (IAccessible *)this,
                                dispid,
                                wFlags,
                                pdispparams,
                                pvarResult,
                                pexcepinfo,
                                puArgErr );
}




//-----------------------------------------------------------------------
//	CAccClient::get_accParent()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accParent().
//
//		Retrieves the IDispatch interface of the current object's
//		parent.
//
//	PARAMETERS:
//
//		ppdispParent	[out] Pointer to the variable that will
//								contain a pointer to the IDispatch
//								interface of CAccClient's parent.
//
//	RETURNS:
//
//		HRESULT			The value returned by the standard object's
//						  implementation of get_accParent().
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accParent( IDispatch ** ppdispParent )
{
	//
	// Use the default client window implementation to obtain the parent
	// of our Accessible object.
	//
	return m_pDefAccClient->get_accParent( ppdispParent );
}




//-----------------------------------------------------------------------
//	CAccClient::get_accChildCount()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accChildCount().
//
//		Retrieves the number of children belonging to CAccClient.
//
//	PARAMETERS:
//
//		pChildCount		[out] Pointer to the variable that will
//								be filled with the number of children
//								belonging to the CAccClient object.
//
//	RETURNS:
//
//		HRESULT			S_OK on success, E_INVALIDARG if pChildCount
//						  is invalid.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accChildCount( long* pChildCount )
{
    if ( !pChildCount )
        return E_INVALIDARG;

    *pChildCount = NUM_CHILDREN;

    return S_OK;
}




//-----------------------------------------------------------------------
//	CAccClient::get_accChild()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accChild().
//
//		Retrieve an IDispatch interface pointer to the child object
//		that has the given child ID or name.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child to be retrieved.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//		ppdispChild		[out] Pointer to the variable that will
//								contain a pointer to the IDispatch
//								interface of specified child object
//								of CAccClient.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if ppdispChild is invalid, S_FALSE
//						  otherwise because none of CAccClient's
//						  children are objects.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accChild( VARIANT varChild, IDispatch ** ppdispChild )
{
	//-----------------------------------------------------
	//	Validate the out parameter.
	//-----------------------------------------------------

    if ( !ppdispChild )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	None of the children of CAccClient are objects,
	//	  so none have IDispatch pointers.  Thus, in all
	//	  cases, set the IDispatch pointer to NULL and
	//	  return S_FALSE.
	//-----------------------------------------------------

	*ppdispChild = NULL;


    return S_FALSE;
}




//-----------------------------------------------------------------------
//	CAccClient::get_accName()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accName().
//
//		Retrieve the name property for the specified child.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child to be retrieved.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//		pszName			[out] Pointer to the BSTR that will contain
//								the child's name property string.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if either parameter is invalid
//						  or the return value from the private method
//						  HrLoadString().
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accName( VARIANT varChild, BSTR* pszName )
{
	//-----------------------------------------------------
	//	Validate the parameters.
	//-----------------------------------------------------

    if ( !pszName || !IsValidChildVariant( &varChild ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	Initialize the out parameter.
	//-----------------------------------------------------

	*pszName = NULL;


	//-----------------------------------------------------
	//	Since varChild is valid, either it identifies the
	//	  Accessible object itself or one of its children.
	//-----------------------------------------------------

	//-----------------------------------------------------
	//	If the child ID is CHILDID_SELF, the name property
	//	  of the Accessible object itself is being
	//	  requested.  Call HrLoadString() to read in the
	//	  name property of the client window from the
	//	  string table resource.
	//-----------------------------------------------------

	if ( varChild.lVal == CHILDID_SELF )
		return HrLoadString( IDS_NAMEPROP_CLIENT, pszName );

	
	//-----------------------------------------------------
	//	The name property of one of the children is
	//	  sought, so call HrLoadString() to read it in
	//	  from the string table resource.
	//-----------------------------------------------------

	return HrLoadString( IDS_NAMEPROP_RINGICON + GetOffsetFromChildID( varChild.lVal ),
	                     pszName );
}




//-----------------------------------------------------------------------
//	CAccClient::get_accValue()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accValue().
//
//		Retrieves the value property for the specified child.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child to be retrieved.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//		pszValue		[out] Pointer to the BSTR that will contain
//								the child's value property string.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if either parameter is invalid,
//						  DISP_E_MEMBERNOTFOUND if VarChild refers
//						  to any child other than the status bar,
//						  or S_OK.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accValue( VARIANT varChild, BSTR* pszValue )
{
	//-----------------------------------------------------
	//	Validate the parameters.
	//-----------------------------------------------------

    if ( !pszValue || !IsValidChildVariant( &varChild ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	Initialize the out parameter.
	//-----------------------------------------------------

    *pszValue = NULL;


	//-----------------------------------------------------
	//	We only support the value property for the
	//	  status bar, so return DISP_E_MEMBERNOTFOUND
	//	  if varChild refers to any other valid object.
	//-----------------------------------------------------

	if ( varChild.lVal != CHILDID_STATBAR )
	    return DISP_E_MEMBERNOTFOUND;
	else
	{
	    OLECHAR	wszString[256];

    
		MultiByteToWideChar( CP_ACP,
		                     0,
							 (LPCSTR) StatusBar_GetText(),
							 -1,
							 wszString,
							 256 );

		*pszValue = SysAllocString( wszString );

		return S_OK;
	}
}




//-----------------------------------------------------------------------
//	CAccClient::get_accDescription()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accDescription().
//
//		Retrieves the description property for the specified child.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child to be retrieved.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//		pszDesc			[out] Pointer to the BSTR that will contain
//								the child's description property string.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if either parameter is invalid
//						  or the return value from either the
//						  standard client window implementation of
//						  get_accDescription() or the private method
//						  HrLoadString().
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accDescription( VARIANT varChild, BSTR* pszDesc )
{
	//-----------------------------------------------------
	//	Validate the parameters.
	//-----------------------------------------------------

    if ( !pszDesc || !IsValidChildVariant( &varChild ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	Initialize the out parameter.
	//-----------------------------------------------------

	*pszDesc = NULL;


	//-----------------------------------------------------
	//	If the child identifier is CHILDID_SELF, the
	//	  description property of the Accessible object
	//	  itself is being requested.  Thus, delegate
	//	  this request to the standard implementation.
	//-----------------------------------------------------

	if ( varChild.lVal == CHILDID_SELF )
        return m_pDefAccClient->get_accDescription( varChild, pszDesc );

	
	//-----------------------------------------------------
	//	The description property of one of the children
	//	  is sought, so call HrLoadString() to read it
	//	  in from the string table resource.
	//-----------------------------------------------------

	return HrLoadString( IDS_DESCPROP_RINGICON + GetOffsetFromChildID( varChild.lVal ),
	                     pszDesc );
}




//-----------------------------------------------------------------------
//	CAccClient::get_accRole()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accRole().
//
//		Retrieves the role property for the specified child.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child to be retrieved.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//		pVarRole		[out] Pointer to the VARIANT structure that
//								will contain the specified child's
//								role property.  This property may
//								either be in the form of a standard
//								role constant or a custom description
//								string.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if either parameter is invalid,
//						  S_OK if the specified child is the button
//						  or status bar, or the return value from
//						  either the standard client window implementation
//						  of get_accRole() or the private method
//						  HrLoadString().
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accRole( VARIANT varChild, VARIANT * pVarRole )
{
	//-----------------------------------------------------
	//	Validate the parameters.
	//-----------------------------------------------------

    if ( !pVarRole || !IsValidChildVariant( &varChild ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	If the child ID refers to the Accessible object
	//	  itself, delegate the request to the default
	//	  implementation.
	//-----------------------------------------------------

    if ( varChild.lVal == CHILDID_SELF )
        return m_pDefAccClient->get_accRole( varChild, pVarRole );


	//-----------------------------------------------------
	//	If the child ID refers to the push button, return
	//	  the system defined role for a push button.
	//-----------------------------------------------------

    else if ( varChild.lVal == CHILDID_BUTTON )
    {
        pVarRole->vt = VT_I4;
        pVarRole->lVal = ROLE_SYSTEM_PUSHBUTTON;
        return S_OK;
    }


	//-----------------------------------------------------
	//	If the child ID refers to the status bar, return
	//	  the system defined role for a status bar.
	//-----------------------------------------------------

    else if ( varChild.lVal == CHILDID_STATBAR )
    {
        pVarRole->vt = VT_I4;
        pVarRole->lVal = ROLE_SYSTEM_STATUSBAR;
        return S_OK;
    }


	//-----------------------------------------------------
	//	If the child ID refers to one of the icons,
	//	  load the IDS_ROLEPROP_ALLICONS string from
	//	  the string table resource.
	//-----------------------------------------------------

    else
    {
        pVarRole->vt = VT_BSTR;
        return HrLoadString( IDS_ROLEPROP_ALLICONS, &pVarRole->bstrVal );
    }
}




//-----------------------------------------------------------------------
//	CAccClient::get_accState()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accState().
//
//		Retrieves the current state for the specified object or child.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child to be retrieved.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//		pVarState		[out] Pointer to the VARIANT structure that
//								will contain information describing
//								the specified child's current state.
//								This information may either be in the
//								form of one or more object state
//								constants or a custom description
//								string.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if either parameter is invalid or
//						  S_OK.
//
//	NOTES:
//
//		Since the icons are HWND based objects, they can never truly
//		have the input focus.  However, if the user clicks one, the main
//		window treats the icon as if it had the focus.  So, the state
//		of the client area should not indicate "focused" when an icon
//		is said to have the focus.
//
//		The push button can have the focus, but it cannot be selected.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accState( VARIANT varChild, VARIANT * pVarState )
{
	int		i;


	//-----------------------------------------------------
	//	Validate the parameters.
	//-----------------------------------------------------

    if ( !pVarState || !IsValidChildVariant( &varChild ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	For any child, we will return its state in the
	//	  form of an object state constant (using the
	//	  VT_I4 lVal member of the VARIANT union).
	//-----------------------------------------------------

	pVarState->vt = VT_I4;

	
	//-----------------------------------------------------
	//	If the child ID refers to the Accessible object
	//	  itself, determine the current state of the
	//	  client area.  In all cases, its state includes
	//	  STATE_SYSTEM_FOCUSABLE.  And, if it has the
	//	  input focus and it is not "pretending" one of
	//	  the icons has the focus, then its state also
	//	  includes STATE_SYSTEM_FOCUSED.
	//-----------------------------------------------------

    if ( varChild.lVal == CHILDID_SELF )
	{
		pVarState->lVal = STATE_SYSTEM_FOCUSABLE;
		if ( GetFocus() == m_hWnd )
		{
			pVarState->lVal |= STATE_SYSTEM_FOCUSED;
			for ( i = 0; i < NUM_ICONS; i++ )
				if ( g_rgIcons[i].bHasFocus )
					pVarState->lVal = STATE_SYSTEM_FOCUSABLE;
		}
	}
	else
	{
		//-----------------------------------------------------
		//	If the child ID refers to the status bar, return
		//	  a state to STATE_SYSTEM_READONLY.
		//-----------------------------------------------------

		if ( varChild.lVal == CHILDID_STATBAR )
			pVarState->lVal = STATE_SYSTEM_READONLY;


		//-----------------------------------------------------
		//	The child ID refers to an icon or the push button.
		//-----------------------------------------------------

		else
		{
			//-----------------------------------------------------
			//	If the child ID refers to the push button,
			//	  initialize the state to STATE_SYSTEM_FOCUSABLE.
			//	  Then, call Button_HasFocus() to determine 
			//	  whether or not the button has the input focus.
			//	  And, finally, call Button_IsPushed() to
			//	  determine whether or not the button is pressed.
			//-----------------------------------------------------

			if ( varChild.lVal == CHILDID_BUTTON )
			{
				pVarState->lVal = STATE_SYSTEM_FOCUSABLE;
				pVarState->lVal |= ( Button_HasFocus() ? 
				                     STATE_SYSTEM_FOCUSED :
				                     0 );

				if ( Button_IsPushed() )
					pVarState->lVal |= STATE_SYSTEM_PRESSED;
			}


			//-----------------------------------------------------
			//	The child ID refers to one of the icons.
			//-----------------------------------------------------

			else
			{
				//-------------------------------------------------
				//	All icons should be marked with the states
				//	  of STATE_SYSTEM_FOCUSABLE and
				//	  STATE_SYSTEM_SELECTABLE.  Moreover, since
				//	  more than one icon may be selected at any
				//	  time, all icons should also be marked with
				//	  the STATE_SYSTEM_MULTISELECTABLE flag and
				//	  the STATE_SYSTEM_EXTSELECTABLE flag.
				//-------------------------------------------------

				pVarState->lVal = STATE_SYSTEM_FOCUSABLE |
				                  STATE_SYSTEM_SELECTABLE |
				                  STATE_SYSTEM_MULTISELECTABLE |
				                  STATE_SYSTEM_EXTSELECTABLE;


				//-------------------------------------------------
				//	Examine the externally linked g_rgIcons[]
				//	  to determine whether or not the requested
				//	  child icon has either the focus or is
				//	  selected.  If so, mark it as such.
				//-------------------------------------------------

				i = GetOffsetFromChildID( varChild.lVal );

				if ( g_rgIcons[i].bHasFocus )
					pVarState->lVal |= STATE_SYSTEM_FOCUSED;

				if ( g_rgIcons[i].bIsSelected )
					pVarState->lVal |= STATE_SYSTEM_SELECTED;
			}
		}
	}


	return S_OK;
}





//-----------------------------------------------------------------------
//	CAccClient::get_accHelp()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accHelp().
//
//		Retrieves the help property string for the specified child.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child to be retrieved.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//		pszHelp			[out] Pointer to the BSTR that will contain
//								the child's help property string.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if either parameter is invalid,
//						  DISP_E_MEMBERNOTFOUND if VarChild refers
//						  to any icon child, or the return value from
//						  either the standard client window implementation
//						  of get_accHelp() or the private method
//						  HrLoadString().
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accHelp( VARIANT varChild, BSTR* pszHelp )
{
	//-----------------------------------------------------
	//	Validate the parameters.
	//-----------------------------------------------------

    if ( !pszHelp || !IsValidChildVariant( &varChild ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	Initialize the out parameter.
	//-----------------------------------------------------

	*pszHelp = NULL;


	//-----------------------------------------------------
	//	If the child identifier is CHILDID_SELF, the help
	//	  property of the Accessible object itself is
	//	  being requested.  Delegate this request to the
	//	  standard implementation.
	//-----------------------------------------------------

	if ( varChild.lVal == CHILDID_SELF )
        return m_pDefAccClient->get_accHelp( varChild, pszHelp );


	//-----------------------------------------------------
	//	If the child identifier is CHILDID_BUTTON, load
	//	  and return the help property string associated
	//	  with the button.
	//-----------------------------------------------------

	else if ( varChild.lVal == CHILDID_BUTTON )
	    return HrLoadString( IDS_HELPPROP_BUTTON, pszHelp );


	//-----------------------------------------------------
	//	If the child identifier is CHILDID_STATBAR, load
	//	  and return the help property string associated
	//	  with the status bar.
	//-----------------------------------------------------

	else if ( varChild.lVal == CHILDID_STATBAR )
	    return HrLoadString( IDS_HELPPROP_STATUSBAR, pszHelp );


	//-----------------------------------------------------
	//	Otherwise, the child ID refers to an icon.
	//	  We don't support a help property for any
	//	  icon, so return DISP_E_MEMBERNOTFOUND.
	//-----------------------------------------------------

	else
		return DISP_E_MEMBERNOTFOUND;
}




//-----------------------------------------------------------------------
//	CAccClient::get_accHelpTopic()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accHelpTopic().
//
//		Retrieves the fully qualified path name of the help file
//		associated with the specified object, as well as a pointer
//		to the appropriate topic with in that file.
//
//	PARAMETERS:
//
//		pszHelpFile		[out] Pointer to the BSTR that will contain
//								the fully qualified path name of the
//								help file associated with the child.
//
//		varChild		[in]  VARIANT structure that identifies the
//								child to be retrieved.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//		pidTopic		[out] Pointer to the value identifying the
//								help file topic associated with the
//								object.
//
//	RETURNS:
//
//		HRESULT			DISP_E_MEMBERNOTFOUND because the help topic
//						  property is not supported for the Accessible
//						  object or any of its children.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accHelpTopic( BSTR* pszHelpFile, VARIANT varChild, long* pidTopic )
{
	//-----------------------------------------------------
	//	The help topic property is not supported for
	//	  either the Accessible object or any of its
	//	  children.
	//-----------------------------------------------------

    return DISP_E_MEMBERNOTFOUND;
}




//-----------------------------------------------------------------------
//	CAccClient::get_accKeyboardShortcut()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method
//		get_accKeyboardShortcut().
//
//		Retrieves the specified object's keyboard shortcut property.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child to be retrieved.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//		pszShortcut		[out] Pointer to the BSTR that will contain
//								the keyboard shortcut string, or NULL
//								if no keyboard shortcut is associated
//								with this item.
//
//
//	RETURNS:
//
//		HRESULT			DISP_E_MEMBERNOTFOUND because the keyboard
//						  shortcut property is not supported for the
//						  Accessible object or any of its children.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accKeyboardShortcut( VARIANT varChild, BSTR* pszShortcut )
{
	//-----------------------------------------------------
	//	The keyboard shortcut property is not supported
	//	  for either the Accessible object or any of its
	//	  children.  So, set pszShortcut to NULL and
	//	  return DISP_E_MEMBERNOTFOUND.
	//-----------------------------------------------------

	pszShortcut = NULL;


    return DISP_E_MEMBERNOTFOUND;
}




//-----------------------------------------------------------------------
//	CAccClient::get_accFocus()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accFocus().
//
//		Retrieves the child object that currently has the input focus.
//		Only one object or item within a container can have the current
//		focus at any one time.
//
//	PARAMETERS:
//
//		pVarFocus		[out] Pointer to the VARIANT structure that
//								will contain information describing
//								the specified child's current state.
//								This information may either be in the
//								form of one or more object state
//								constants or a custom description
//								string.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if the pVarFocus parameter is
//						  invalid or S_OK.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accFocus( VARIANT * pVarFocus )
{
	//-----------------------------------------------------
	//	Validate the out parameter.
	//-----------------------------------------------------

    if ( !pVarFocus )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	In our server, if a Windows object has the focus,
	//	  it will be either the main window or the button,
	//	  the status bar never receives the focus.
	//	  In some cases (namely when a mouse click occurs
	//	  above an icon), the main window may actually
	//	  have the focus, but it treats an icon as if the
	//	  icon itself had the focus.  So, we need to
	//	  determine if either the button or the main
	//	  window has the the focus, and if the main
	//	  window has the focus is it treating an icon
	//	  as if the icon had the focus.
	//-----------------------------------------------------


	//-----------------------------------------------------
	//	Initialize the vt member of the out VARIANT
	//	  to VT_I4.
	//-----------------------------------------------------

	pVarFocus->vt = VT_I4;


	//-----------------------------------------------------
	//	Does the button have the focus?  Call
	//	  Button_HasFocus() to find out.  If the button
	//	  has the focus, set the out VARIANT lVal to the
	//	  value of the button child ID.
	//-----------------------------------------------------

	if ( Button_HasFocus() )
		pVarFocus->lVal = CHILDID_BUTTON;


	//-----------------------------------------------------
	//	Since the button doesn't have the focus, does
	//	  the main window?
	//-----------------------------------------------------

	else if ( GetFocus() == m_hWnd )
    {
		//-----------------------------------------------------
		//	The main window has the focus, so set the out
		//	  VARIANT lVal to CHILDID_SELF.
		//-----------------------------------------------------

		pVarFocus->lVal = CHILDID_SELF;


		//-----------------------------------------------------
		//	Since the main window has the focus, is it
		//	  actually treating an icon as if that icon had
		//	  the focus?  If so, update the out VARIANT lVal
		//	  with the correct child ID.
		//-----------------------------------------------------

		for ( int i = 0; i < NUM_ICONS; i++ )
			if ( g_rgIcons[i].bHasFocus )
			{
				pVarFocus->lVal = GetChildIDFromOffset( i );
				break;
			}
    }


	//-----------------------------------------------------
	//	Since neither the button nor the server window
	//	  have the focus, set the vt member of the out
	//	  VARIANT to VT_EMPTY.
	//-----------------------------------------------------

    else
        pVarFocus->vt = VT_EMPTY;


	//-----------------------------------------------------
	//	Return S_OK because the method succeeded.
	//-----------------------------------------------------

	return S_OK;
}




//-----------------------------------------------------------------------
//	CAccClient::get_accSelection()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accSelection().
//
//		Retrieves the selected children of this object.
//
//	PARAMETERS:
//
//		pVarSel  		[out] Pointer to the VARIANT structure that
//								will be filled with information about
//								the selected child object or objects.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if the pVarSel parameter is
//						  invalid or S_OK.
//
//	NOTES:
//
//		Refer to the MSAA SDK documentation for a full description
//		of this method and the possible settings of pVarSel.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accSelection( VARIANT * pVarSel )
{
	int		i, nSelCnt;


	//-----------------------------------------------------
	//	Validate the out parameter.
	//-----------------------------------------------------

    if ( !pVarSel )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	For our server, there are two mutually exclusive
	//	  selection states:
	//
	//		1) no children are selected, or
	//		2) one or more icons are are selected.
	//
	//	(The status bar and push button can not be
	//	  selected, although the push button may have
	//	  the focus.)
	//-----------------------------------------------------
	

	//-----------------------------------------------------
	//	Since there may be no selected icons (thus,
	//	  no selected children), initialize the vt field
	//	  of pVarSel to VT_EMPTY.
	//-----------------------------------------------------

	pVarSel->vt = VT_EMPTY;


	//-----------------------------------------------------
	//	Are any of the icons selected?  If one icon
	//	  is selected, return its child ID in pVarSel.
	//	  If multiple icons are selected, create a VARIANT
	//	  enumerator, fill it with the selected icons'
	//	  child IDs, set the vt field of pVarSel to
	//	  VT_UNKNOWN, and return the IUnknown interface
	//	  pointer of the enumerator in pVarSel->punkVal.
	//-----------------------------------------------------

	
	//-----------------------------------------------------
	//	Loop through the icon information array counting
	//	  the number of selected icons.
	//-----------------------------------------------------

	nSelCnt = 0;

	for ( i = 0; i < NUM_ICONS; i++ )
		if ( g_rgIcons[i].bIsSelected )
			nSelCnt++;


	//-----------------------------------------------------
	//	If only one icon is selected, return its child ID
	//	  in pVarSel.
	//-----------------------------------------------------

	if ( nSelCnt == 1 )
	{
		for ( i = 0; i < NUM_ICONS; i++ )
			if ( g_rgIcons[i].bIsSelected )
			{
				pVarSel->vt = VT_I4;
				pVarSel->lVal = GetChildIDFromOffset( i );
				break;
			}
	}


	//-----------------------------------------------------
	//	If more than one icon is selected, create a
	//	  VARIANT enumerator containing one VARIANT per
	//	  selected icon initialized with the icon's
	//	  child ID, and return an IUnknown pointer to
	//	  the enumerator in pVarSel.
	//-----------------------------------------------------

	else if ( nSelCnt > 1 )
	{
		CEnumVariant*	pcenum;
		HRESULT			hr;

		hr = CreateVarEnumOfSelIcons( &pcenum, nSelCnt );

		if ( FAILED( hr ) )
			return hr;

		((LPUNKNOWN) pcenum)->AddRef();

		pVarSel->vt = VT_UNKNOWN;
		pVarSel->punkVal = (LPUNKNOWN) pcenum;
	}


    return S_OK;
}




//-----------------------------------------------------------------------
//	CAccClient::get_accDefaultAction()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method get_accDefaultAction().
//
//		Retrieves a string containing a localized, human-readable sentence
//		that describes the object's default action.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child whose default action string is
//								to be retrieved.  Since CAccClient
//								only supports child IDs, the vt member
//								of this structure must equal VT_I4.
//
//		pszDefAct		[out] Pointer to the BSTR that will contain
//								the child's default action string,
//								or NULL if there is no default action
//								for this object.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if either parameter is invalid,
//						  DISP_E_MEMBERNOTFOUND if VarChild refers
//						  to any icon child or the status bar child,
//						  or the return value from either the standard
//						  client window implementation of
//						  get_accDefaultAction() or the private method
//						  HrLoadString().
//
//	NOTES:
//
//		The only CAccClient child that has a default action is
//		the push button.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::get_accDefaultAction( VARIANT varChild, BSTR* pszDefAct )
{
	//-----------------------------------------------------
	//	Validate the parameters.
	//-----------------------------------------------------

    if ( !pszDefAct || !IsValidChildVariant( &varChild ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	Initialize the out parameter.
	//-----------------------------------------------------

    *pszDefAct = NULL;


	//-----------------------------------------------------
	//	If the child identifier is CHILDID_SELF, the
	//	  default action property of the Accessible
	//	  object itself is being requested.   Delegate
	//	  this request to the standard implementation.
	//-----------------------------------------------------

	if ( varChild.lVal == CHILDID_SELF )
        return m_pDefAccClient->get_accDefaultAction( varChild, pszDefAct );


	//-----------------------------------------------------
	//	If the child identifier is CHILDID_BUTTON, load
	//	  and return the deafult action property string
	//	  associated with the button.
	//-----------------------------------------------------

	else if ( varChild.lVal == CHILDID_BUTTON )
	    return HrLoadString( IDS_DEFACTPROP_BUTTON, pszDefAct );


	//-----------------------------------------------------
	//	Otherwise, the child ID refers to an icon or
	//	  to the status bar.  We don't support a default
	//	  action for either of these, so return
	//	  DISP_E_MEMBERNOTFOUND.
	//-----------------------------------------------------

	else
		return DISP_E_MEMBERNOTFOUND;
}




//-----------------------------------------------------------------------
//	CAccClient::accDoDefaultAction()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method accDoDefaultAction().
//
//		Performs the object's default action.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child whose default action will be
//								invoked.  Since CAccClient only
//								supports child IDs, the vt member of
//								this structure must equal VT_I4.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if the in-parameter is invalid,
//						  DISP_E_MEMBERNOTFOUND if VarChild refers
//						  to any icon child or the status bar child,
//						  S_OK if VarChild refers to the push button,
//						  or the return value from the standard
//						  client window implementation of
//						  accDoDefaultAction().
//
//	NOTES:
//
//		The only CAccClient child that has a default action is
//		the push button.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::accDoDefaultAction( VARIANT varChild )
{
	//-----------------------------------------------------
	//	Validate the parameter.
	//-----------------------------------------------------

    if ( !IsValidChildVariant( &varChild ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	We only support a default action property for the
	//	  main window and the button.
	//-----------------------------------------------------


	//-----------------------------------------------------
	//	If the child identifier is CHILDID_SELF, we are
	//	  being asked to perform the default action of
	//	  the Accessible object itself.  Delegate this
	//	  request to the standard implementation.
	//-----------------------------------------------------

	if ( varChild.lVal == CHILDID_SELF )
        return m_pDefAccClient->accDoDefaultAction( varChild );


	//-----------------------------------------------------
	//	If the child identifier is CHILDID_BUTTON, we are
	//	  being asked to perform the default action of
	//	  "Press" for the button.
	//-----------------------------------------------------

	else if ( varChild.lVal == CHILDID_BUTTON )
	{
		Button_Click();

		return S_OK;
	}


	//-----------------------------------------------------
	//	Otherwise, the child ID refers to an icon or
	//	  to the status bar.  We don't support a default
	//	  action for either of these, so return
	//	  DISP_E_MEMBERNOTFOUND.
	//-----------------------------------------------------

	else
		return DISP_E_MEMBERNOTFOUND;
}




//-----------------------------------------------------------------------
//	CAccClient::accSelect()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method accSelect().
//
//		Modifies the selection or moves the keyboard focus according
//		to the specified flags.
//
//	PARAMETERS:
//
//		flagsSel		[in]  Value specifying how to change the
//								the current selection.  This parameter
//								can be a combination of the values
//								from the SELFLAG enumerated type.
//
//		varChild		[in]  VARIANT structure that identifies the
//								child to be selected.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if either of the parameters
//						  is invalid, S_FALSE if the selection
//						  and/or focus cannot be placed at the
//						  requested location, or S_OK if the
//						  selection and/or focus can be placed
//						  at the requested location.
//
//	NOTES:
//
//		For more information on selected objects, please see the
//		MSAA SDK Documentation.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::accSelect( long flagsSel, VARIANT varChild )
{
	int		nIcon;


	//-----------------------------------------------------
	//	Validate the requested selection.
	//	  SELFLAG_ADDSELECTION may not be combined
	//	  with SELFLAG_REMOVESELECTION.
	//-----------------------------------------------------

    if ( (flagsSel & SELFLAG_ADDSELECTION) &&
	     (flagsSel & SELFLAG_REMOVESELECTION) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	Validate the VARIANT parameter.
	//-----------------------------------------------------

    if ( !IsValidChildVariant( &varChild ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	Examine for which child the selection and/or focus
	//	  action is to take place.
	//-----------------------------------------------------

	switch ( varChild.lVal )
	{
		//-----------------------------------------------------
		//	If the child ID is CHILDID_SELF, we are being
		//	  asked to perform some selection change (as
		//	  specified by flagsSel) on the Accessible object
		//	  itself.  For this object, only support the
		//	  SELFLAG_TAKEFOCUS flag because the client area
		//	  can only be given the focus (it cannot be
		//	  selected).  Thus, if flagsSel equals only
		//	  SELFLAG_TAKEFOCUS, set the focus to only the
		//	  main window's client area (none of the icons
		//	  should be focused) and return S_OK.  Otherwise,
		//	  do nothing so that S_FALSE will be returned.
		//-----------------------------------------------------

		case CHILDID_SELF:
			if ( flagsSel == SELFLAG_TAKEFOCUS )
			{
				if ( GetFocus() != m_hWnd )
					SetFocus( m_hWnd );

				UpdateIconSelection( NO_ICON_CLICKED, 0 );
				return S_OK;
			}
			break;


		//-----------------------------------------------------
		//	If the child ID is CHILDID_STATBAR, do nothing
		//	  such that S_FALSE is returned because the
		//	  status bar can neither be selected nor given
		//	  the focus.
		//-----------------------------------------------------

		case CHILDID_STATBAR:
			break;


		//-----------------------------------------------------
		//	If the child ID is CHILDID_BUTTON, we are being
		//	  asked to perform some selection change (as
		//	  specified by flagsSel) on the push button.
		//	  For this object, only support the
		//	  SELFLAG_TAKEFOCUS flag because the button
		//	  can only be given the focus (it cannot be
		//	  selected).  Thus, if flagsSel equals only
		//	  SELFLAG_TAKEFOCUS, set the focus to the
		//	  button and return S_OK.  Otherwise,
		//	  do nothing so that S_FALSE will be returned.
		//-----------------------------------------------------

		case CHILDID_BUTTON:
			if ( flagsSel == SELFLAG_TAKEFOCUS )
			{
				Button_SetFocus();
				return S_OK;
			}
			break;


		//-----------------------------------------------------
		//	Otherwise, the child ID specifies only of the
		//	  the icons.  Since icons can be focused, selected,
		//	  and multiply selected, there a bit of work
		//	  to be done here.
		//-----------------------------------------------------

		default:
			//-----------------------------------------------------
			//  Give the focus to the main window if it doesn't
			//	  already have it.
			//-----------------------------------------------------

			if ( GetFocus() != m_hWnd )
				SetFocus( m_hWnd );


			//-----------------------------------------------------
			//  Convert the Accessible child icon ID into an icon
			//	  offset.
			//-----------------------------------------------------

			nIcon = GetOffsetFromChildID( varChild.lVal );


			//-----------------------------------------------------
			//  For the specified icon, process only certain
			//	  selection flag combinations, failing all others.
			//-----------------------------------------------------

			switch ( flagsSel )
			{
				//-----------------------------------------------------
				//	If the selection flag is just SELFLAG_TAKEFOCUS
				//	  the icon needs to have the focus and be the
				//	  selection anchor, but the selection state of all
				//	  icons does not change.
				//-----------------------------------------------------

				case SELFLAG_TAKEFOCUS:
					FocusAndAnchorIcon( nIcon );
					return S_OK;


				//-----------------------------------------------------
				//	If the selection flag is just SELFLAG_TAKESELECTION,
				//	  make the specified icon only one selected, and if
				//	  there is no selection anchor, make this icon the
				//	  anchor (but don't alter the focus).
				//-----------------------------------------------------

				case SELFLAG_TAKESELECTION:
					SelectIconOnly( nIcon );
					return S_OK;


				//-----------------------------------------------------
				//	If the selection flag is SELFLAG_TAKEFOCUS and
				//	  SELFLAG_TAKESELECTION, the icon needs to have
				//	  the focus, be the selection anchor, and be the
				//	  only icon selected.
				//-----------------------------------------------------

				case (SELFLAG_TAKEFOCUS | SELFLAG_TAKESELECTION):
					UpdateIconSelection( nIcon, 0 );
					return S_OK;


				//-----------------------------------------------------
				//	If the selection flag is SELFLAG_TAKEFOCUS
				//	  and SELFLAG_ADDSELECTION, the icon needs
				//	  to be given the focus, to be the selection
				//	  anchor, and to be added to the selection without
				//	  changing the selection state of any other icons.
				//
				//	The desired state is essentially like a CTRL+CLICK
				//	  on the icon, except if the icon is already
				//	  selected.  In this case, a CTRL+CLICK would
				//	  focus and anchor the icon, but deselect
				//	  it.  So, to circumvent this behavior, manually
				//	  "deselect" the icon (set its bIsSelected flag
				//	  to FALSE) and then perform a CTRL+CLICK on the
				//	  icon.
				//-----------------------------------------------------

				case (SELFLAG_TAKEFOCUS | SELFLAG_ADDSELECTION):
					g_rgIcons[nIcon].bIsSelected = FALSE;
					UpdateIconSelection( nIcon, MK_CONTROL );
					return S_OK;


				//-----------------------------------------------------
				//	If the selection flag is SELFLAG_TAKEFOCUS
				//	  and SELFLAG_REMOVESELECTION, the icon needs
				//	  to be given the focus, to be the selection
				//	  anchor, and to be deselected without changing
				//	  the selection state of any other icons.
				//
				//	The desired state is essentially like a CTRL+CLICK
				//	  on the icon, except if the icon is already
				//	  deselected.  In this case, a CTRL+CLICK would
				//	  focus and anchor the icon, but select it.
				//	  So, to circumvent this behavior, manually
				//	  "select" the icon (set its bIsSelected flag
				//	  to FALSE) and then perform a CTRL+CLICK on the
				//	  icon.
				//-----------------------------------------------------

				case (SELFLAG_TAKEFOCUS | SELFLAG_REMOVESELECTION):
					g_rgIcons[nIcon].bIsSelected = TRUE;
					UpdateIconSelection( nIcon, MK_CONTROL );
					return S_OK;


				//-----------------------------------------------------
				//	If the selection flag is SELFLAG_TAKEFOCUS
				//	  and SELFLAG_EXTENDSELECTION, the icon needs
				//	  to be given the focus, to be the selection
				//	  anchor, and to be selected.  Also, all icons
				//	  between this one and the previous selection
				//	  anchor need to be selected.
				//-----------------------------------------------------

				case (SELFLAG_TAKEFOCUS | SELFLAG_EXTENDSELECTION):
					UpdateIconSelection( nIcon, MK_SHIFT );
					FocusAndAnchorIcon( nIcon );
					return S_OK;
			}
			break;
	}


	return S_FALSE;
}




//-----------------------------------------------------------------------
//	CAccClient::accLocation()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method accLocation().
//
//		Retrieves the specified child's current screen location in
//		screen coordinates.
//
//	PARAMETERS:
//
//		pxLeft			[out] Address of the child's left most
//								boundary.
//
//		pyTop			[out] Address of the child's upper most
//								boundary.
//
//		pcxWid			[out] Address of the child's width.
//
//		pcyHt			[out] Address of the child's height.
//
//		varChild		[in]  VARIANT structure that identifies the
//								child whose screen location is to be
//								retrieved.  Since CAccClient only
//								supports child IDs, the vt member
//								of this structure must equal VT_I4.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if any of the parameters
//						  are invalid, E_UNEXPECTED if we are for
//						  some reason unable to determine the
//						  window rect of the button or status bar,
//						  S_OK if the screen coordinates of the
//						  child are successfully determined, or
//						  the return value from the standard client
//						  window implementation of accLocation().
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::accLocation( long* pxLeft,
                                      long* pyTop,
                                      long* pcxWid,
                                      long* pcyHt,
                                      VARIANT varChild )
{
    RECT    rc;
	int		i;


	//-----------------------------------------------------
	//	Validate the parameters.
	//-----------------------------------------------------

    if ( !pxLeft || !pyTop || !pcxWid || !pcyHt || !IsValidChildVariant( &varChild ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	If the child ID is CHILDID_SELF, we are being
	//	  asked to retrieve the current screen location
	//	  of the Accessible object itself.   Delegate
	//	  this request to the standard implementation.
	//-----------------------------------------------------

    if ( varChild.lVal == CHILDID_SELF )
        return m_pDefAccClient->accLocation( pxLeft, pyTop, pcxWid, pcyHt, varChild );


	//-----------------------------------------------------
	//	Initialize the out parameters with default values.
	//-----------------------------------------------------

    *pxLeft = *pyTop = *pcxWid = *pcyHt = 0;


	//-----------------------------------------------------
	//	If the child ID is CHILDID_BUTTON or
	//	  CHILDID_STATBAR, simply query the associated
	//	  window object for its window rectangle and
	//	  copy the appropriate values into the out
	//	  parameters.
	//-----------------------------------------------------

    if ( varChild.lVal == CHILDID_BUTTON || varChild.lVal == CHILDID_STATBAR )
    {
		if ( varChild.lVal == CHILDID_BUTTON )
		{
			if ( !Button_GetWindowRect( &rc ) )
				return E_UNEXPECTED;
		}
		else
		{
			if ( !StatusBar_GetWindowRect( &rc ) )
				return E_UNEXPECTED;
		}

        *pxLeft = rc.left;
        *pyTop = rc.top;
        *pcxWid = rc.right - rc.left;
        *pcyHt = rc.bottom - rc.top;
    }


	//-----------------------------------------------------
	//	Otherwise, the child ID refers to an icon.
	//	  In this case, obtain the client rectangle
	//	  of the main window, map that rectangle to
	//	  screen coordinates, and calculate the
	//	  location of the icon using the icon
	//	  information array.
	//-----------------------------------------------------

    else
    {
		i = GetOffsetFromChildID(varChild.lVal);

        GetClientRect( m_hWnd, &rc );
        MapWindowPoints( m_hWnd, HWND_DESKTOP, (LPPOINT)&rc, 2 );

        *pxLeft = rc.left + g_rgIcons[i].rcBounds.left;
        *pyTop = rc.top + g_rgIcons[i].rcBounds.top;

        *pcxWid = g_rgIcons[i].rcBounds.right - g_rgIcons[i].rcBounds.left;
        *pcyHt = g_rgIcons[i].rcBounds.bottom - g_rgIcons[i].rcBounds.top;
    }


    return S_OK;
}




//-----------------------------------------------------------------------
//	CAccClient::accNavigate()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method accNavigate().
//
//		Retrieves the next or previous sibling or child object in a
//		specified direction.  This direction can be spatial order
//		(such as Left and Right) or in navigational order (such as
//		Next and Previous).
//
//	PARAMETERS:
//
//		navDir			[in]  A navigational constant specifying
//								the direction in which to move.
//
//		varStart		[in]  VARIANT structure that identifies the
//								child from which the navigational
//								change will originate.  Since
//								CAccClient only supports child IDs,
//								the vt member of this structure must
//								equal VT_I4.
//
//		pVarEndUpAt		[out] Pointer to the VARIANT structure that
//								will contain information describing
//								the destination child or object.
//								If the vt member is VT_I4, then the
//								lVal member is a child ID.  If the
//								vt member is VT_EMPTY, then the
//								navigation failed.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if the varStart parameter is
//						  invalid, or the return value from the
//						  default implementation of the window client
//						  area default Accessible object,
//						  DISP_E_MEMBERNOTFOUND if the combination
//						  of the navigation flag and the varStart
//						  setting is invalid, S_FALSE if the
//						  navigation fails, or S_OK.
//
//	NOTES:
//
//		Since the CAccClient object has no child objects (only child
//		elements), pVarEndUpAt will never be a pointer to a IDispatch
//		interface of a child object.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::accNavigate( long navDir, VARIANT varStart, VARIANT* pVarEndUpAt )
{
	//-----------------------------------------------------
	//	Validate the parameters.
	//-----------------------------------------------------

    if ( !IsValidChildVariant( &varStart ) )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	If the child ID is CHILDID_SELF, the navigation
	//	  request starts at the Accessible object itself.
	//	  If the navigation flag is either
	//	  NAVDIR_FIRSTCHILD or NAVDIR_LASTCHILD, we will
	//	  process the navigation request (because the
	//	  default implementation has no knowledge of our
	//	  particular non-window children).  If the
	//	  navigation flag is any other value, we will
	//	  delegate the navigation request to the default
	//	  implementation.  This will provide the proper
	//	  peer-to-peer movement within Windows.
	//-----------------------------------------------------

	if ( varStart.lVal == CHILDID_SELF )
	{
		if ( navDir == NAVDIR_FIRSTCHILD || navDir == NAVDIR_LASTCHILD )
		{
			pVarEndUpAt->vt = VT_I4;
			pVarEndUpAt->lVal = ( NAVDIR_FIRSTCHILD ? CHILDID_RING_ICON : CHILDID_STATBAR );
			return S_OK;
		}
		else
	        return m_pDefAccClient->accNavigate( navDir, varStart, pVarEndUpAt );
	}


	//-----------------------------------------------------
	//	IsValidChildVariant() weeded out any invalid
	//	  VARIANTs and we've handled the case where the
	//	  child ID refers to the Accessible object.
	//	  Thus, we know that varStart.lVal is a child ID
	//	  of one of the Accessible object's children
	//	 (i.e., CHILDID_RING_ICON, ..., CHILDID_STATBAR).
	//-----------------------------------------------------


	//-----------------------------------------------------
	//	Since the children of the Accessible object have
	//	  no children themselves, navigation requests with
	//	  the navigation flag set to NAVDIR_FIRSTCHILD
	//	  or NAVDIR_LASTCHILD are invalid.  In these cases,
	//	  return DISP_E_MEMBERNOTFOUND.
	//-----------------------------------------------------

	if ( navDir == NAVDIR_FIRSTCHILD || navDir == NAVDIR_LASTCHILD )
		return DISP_E_MEMBERNOTFOUND;


	//-----------------------------------------------------
	//	Optimistically initialize the variant type member
	//	  of pVarEndUpAt (i.e., initialize with VT_I4
	//	  implying successful navigation to another child
	//	  object, not with VT_EMPTY implying unsuccessful
	//	  navigation).
	//-----------------------------------------------------

	pVarEndUpAt->vt = VT_I4;


	//-----------------------------------------------------
	//	Process the navigation request amongst the
	//	  children based upon navigation flag.
	//-----------------------------------------------------

	BOOL	bNavigationSuccessful = TRUE;


	switch ( navDir )
	{
		//------------------------------------------------------------------
		// NAVDIR_UP:  All children except the status bar fail to navigate
		//             in this direction.  The status bar navigates to the
		//             button.
		//------------------------------------------------------------------
		case NAVDIR_UP:
			if ( varStart.lVal != CHILDID_STATBAR )
				bNavigationSuccessful = FALSE;
			else
				pVarEndUpAt->lVal = CHILDID_BUTTON;
			break;


		//------------------------------------------------------------------
		// NAVDIR_DOWN:  All children except the status bar navigate to
		//               the status bar.  The status bar fails to navigate
		//               in this direction.
		//------------------------------------------------------------------
		case NAVDIR_DOWN:
			if ( varStart.lVal == CHILDID_STATBAR )
				bNavigationSuccessful = FALSE;
			else
				pVarEndUpAt->lVal = CHILDID_STATBAR;
			break;


		//------------------------------------------------------------------
		// NAVDIR_LEFT:      All children except the ring icon and the
		// NAVDIR_PREVIOUS:  status bar navigate to their spatial left.
		//                   The status bar navigates to the button.
		//                   The ring icon fails to navigate in this
		//                   direction.
		//------------------------------------------------------------------
		case NAVDIR_LEFT:
		case NAVDIR_PREVIOUS:
			if ( varStart.lVal == CHILDID_RING_ICON )
				bNavigationSuccessful = FALSE;
			else
				pVarEndUpAt->lVal =
					GetChildIDFromOffset( GetOffsetFromChildID( varStart.lVal ) - 1 );
			break;


		//------------------------------------------------------------------
		// NAVDIR_RIGHT:     All children except the status bar and the
		// NAVDIR_NEXT:      button to their spatial right.  The button
		//                   navigates to the status bar.  The status bar
		//                   fails to navigate in this direction.
		//------------------------------------------------------------------
		case NAVDIR_RIGHT:
		case NAVDIR_NEXT:
			if ( varStart.lVal == CHILDID_STATBAR )
				bNavigationSuccessful = FALSE;
			else
				pVarEndUpAt->lVal =
					GetChildIDFromOffset( GetOffsetFromChildID( varStart.lVal ) + 1 );
			break;
	}


	//-----------------------------------------------------
	//	If the navigation succeeded, return S_OK.
	//	  Otherwise, set the vt member of pVarEndUpAt to
	//	  VT_EMPTY and return S_FALSE.
	//-----------------------------------------------------

	if ( bNavigationSuccessful )
		return S_OK;
	else
	{
		pVarEndUpAt->vt = VT_EMPTY;
		return S_FALSE;
	}
}




//-----------------------------------------------------------------------
//	CAccClient::accHitTest()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method accHitTest().
//
//		Retrieves the ID of the a child at a given point on the screen.
//
//	PARAMETERS:
//
//		xLeft and yTop	[in]  The screen coordinates of the point
//								to be hit tested.
//
//		pVarHit			[out] Pointer to the VARIANT structure that
//								will contain information describing
//								the hit child.  If the vt member is
//								VT_I4, then the lVal member is a child
//								ID.  If the vt member is VT_EMPTY,
//								then the navigation failed.
//
//	RETURNS:
//
//		HRESULT			E_INVALIDARG if the pVarHit parameter is
//						  invalid, or S_OK.
//
//	NOTES:
//
//		Since the CAccClient object has no child objects (only child
//		elements), pVarHit will never be a pointer to a IDispatch
//		interface of a child object.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::accHitTest( long xLeft, long yTop, VARIANT* pVarHit )
{
    POINT   pt;
    RECT    rc;
	HWND	hWndChild;
    int     nIcon;


	//-----------------------------------------------------
	//	Validate the out parameter.
	//-----------------------------------------------------

    if ( !pVarHit )
        return E_INVALIDARG;


	//-----------------------------------------------------
	//	Determine if the point to be hit tested is within
	//	  our object (our client window).  First, convert
	//	  the point from screen coordinates into client
	//	  coordinates based on our window.  Second, check
	//	  to see if the point in client coordinates is
	//	  contained in the client area of our window.
	//	  If not, set pVarHit->vt to VT_EMPTY and return
	//	  S_OK.
	//-----------------------------------------------------

	pt.x = xLeft;
    pt.y = yTop;
    ScreenToClient( m_hWnd, &pt );

    GetClientRect( m_hWnd, &rc );

    if ( !PtInRect( &rc, pt ) )
		pVarHit->vt = VT_EMPTY;
	else
	{
		//-----------------------------------------------------
		//	The point is within the window corresponding to our
		//	  Accessible object, so set pVarHit accordingly.
		//-----------------------------------------------------

	    pVarHit->vt = VT_I4;
	    pVarHit->lVal = CHILDID_SELF;


		//-----------------------------------------------------
		//	Determine if the point is also within any of
		//	  our child elements.
		//-----------------------------------------------------

		//-----------------------------------------------------
		//	Call ChildWindowFromPointEx() to determine if
		//	  either of our window's child windows (the
		//	  button and the status bar) contain the point.
		//-----------------------------------------------------

		hWndChild = ChildWindowFromPointEx( m_hWnd, pt, CWP_ALL );


		//-----------------------------------------------------
		//	If the point is within the button, set
		//	  pVarHit->lVal to the button's child ID.
		//-----------------------------------------------------

	    if ( Button_IsEqualHWND( hWndChild ) )
	        pVarHit->lVal = CHILDID_BUTTON;


		//-----------------------------------------------------
		//	Otherwise, if the point is within the status bar,
		//	  set pVarHit->lVal to the status bar's child ID.
		//-----------------------------------------------------

		else if ( StatusBar_IsEqualHWND( hWndChild ) )
	        pVarHit->lVal = CHILDID_STATBAR;


		//-----------------------------------------------------
		//	Otherwise, if the point is above an icon,
		//	  set pVarHit->lVal to that icon's child ID.
		//	  (Use the server.cpp function
		//	  HasAnIconBeenClicked() to determine if our hit
		//	  test point is above an icon.)
		//-----------------------------------------------------

		else
		{
			nIcon = HasAnIconBeenClicked( pt );
			if ( nIcon != NO_ICON_CLICKED )
				pVarHit->lVal = GetChildIDFromOffset( nIcon );
		}
	}


    return S_OK;
}



//-----------------------------------------------------------------------
//	CAccClient::put_accName()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method put_accName().
//
//		Sets the name property for the specified child.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child whose name property is to be
//								set.  Since CAccClient only supports
//								child IDs, the vt member of this
//								structure must equal VT_I4.
//
//		szName			[in]  String that specifies the new name for
//								this child.
//
//	RETURNS:
//
//		HRESULT			S_FALSE because the name property for any
//						  child may not be changed.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::put_accName( VARIANT varChild, BSTR szName )
{
	//-----------------------------------------------------
	//	We don't allow clients to change the name
	//	  property of any child so we simply return
	//	  S_FALSE.
	//-----------------------------------------------------


    return S_FALSE;
}




//-----------------------------------------------------------------------
//	CAccClient::put_accValue()
//
//	DESCRIPTION:
//
//		Implements the IAccessible interface method put_accValue().
//
//		Sets the value property for the specified child.
//
//	PARAMETERS:
//
//		varChild		[in]  VARIANT structure that identifies the
//								child whose value property is to be
//								set.  Since CAccClient only supports
//								child IDs, the vt member of this
//								structure must equal VT_I4.
//
//		szValue			[in]  String that specifies the new value for
//								this child.
//
//	RETURNS:
//
//		HRESULT			S_FALSE because the value property for any
//						  child may not be changed.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::put_accValue( VARIANT varChild, BSTR szValue )
{
	//-----------------------------------------------------
	//	We don't allow clients to change the value
	//	  property of the status bar (the only child that
	//	  has a value property) so we simply return S_FALSE.
	//-----------------------------------------------------

    
	return S_FALSE;
}




//-----------------------------------------------------------------------
//	CAccClient::SendWinEventForChild()
//
//	DESCRIPTION:
//
//		Sends a specified WinEvent for a specified child.
//
//	PARAMETERS:
//
//		dvEvt			[in]  Event constant to be sent.
//
//		nChildOffset	[in]  The server's ID for the child.  This
//								ID must be converted into an external
//								(Accessible) ID.
//
//	RETURNS:
//
//		None.
//
//-----------------------------------------------------------------------

void CAccClient::SendWinEventForChild( DWORD dwEvt, int nChildOffset )
{
	//-----------------------------------------------------
	//	Call NotifyWinEvent() with the specified event
	//	  for the specified child.
	//-----------------------------------------------------

	NotifyWinEvent( dwEvt,
	                m_hWnd,
					OBJID_CLIENT,
	                GetChildIDFromOffset( nChildOffset ) );
}



//===========================================================================
//  Protected CAccClient Methods
//===========================================================================


//-----------------------------------------------------------------------
//	CAccClient::CreateVarEnumOfAllChildren()
//
//	DESCRIPTION:
//
//		Create a VARIANT enumerator that contains one VARIANT structure
//		for each child of CAccClient.
//
//	PARAMETERS:
//
//		ppcenum			[out] Pointer to a pointer to the object that
//								implements the VARIANT enumerator.
//
//	RETURNS:
//
//		HRESULT			NOERROR if the enumerator was created and
//						  initialized successfully, COM error code
//						  otherwise.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::CreateVarEnumOfAllChildren( CEnumVariant** ppcenum )
{
	HRESULT			hr;
	VARIANT			var;
	SAFEARRAY FAR*	psa;
	SAFEARRAYBOUND	rgsbnd[1];
	long			ix[1];


	//-----------------------------------------------------
	//	Create a SAFEARRAY to hold the child ID VARIANTs.
	//	  Note that the number of elements of the array
	//	  is the number of children of CAccClient.
	//-----------------------------------------------------

	rgsbnd[0].lLbound = 0;
	rgsbnd[0].cElements = NUM_CHILDREN;

	psa = SafeArrayCreate( VT_VARIANT, 1, rgsbnd );
	if ( psa == NULL )
		return E_OUTOFMEMORY;


	//-----------------------------------------------------
	//	Initialize the VARIANT structure that will be
	//	  used to add elements to the array.  Set the
	//	  vt member to VT_I4 because the children are
	//	  referred to by numeric IDs.
	//-----------------------------------------------------

	VariantInit( &var );

	var.vt = VT_I4;


	//-----------------------------------------------------
	//	For each child, set the VARIANT's lVal member
	//	  to the child's external (Accessible) ID and
	//	  add an element to the SAFEARRAY.
	//-----------------------------------------------------

	for ( int i = 0; i < NUM_CHILDREN; i++ )
	{
		var.lVal = GetChildIDFromOffset( i );

		ix[0] = i;

		hr = SafeArrayPutElement( psa, ix, &var );
		if ( FAILED( hr ) )
		{
			SafeArrayDestroy( psa );
			return hr;
		}
	}


	//-----------------------------------------------------
	//	Create the enumerator.
	//-----------------------------------------------------

	hr = CEnumVariant::Create( psa, NUM_CHILDREN, ppcenum );


	//-----------------------------------------------------
	//	Clean up by destroying the SAFEARRAY.
	//-----------------------------------------------------

	SafeArrayDestroy( psa );


	return hr;
}




//-----------------------------------------------------------------------
//	CAccClient::CreateVarEnumOfSelIcons()
//
//	DESCRIPTION:
//
//		Creates a VARIANT enumerator that contains one VARIANT
//		structure for each currently selected child icon of CAccClient.
//
//	PARAMETERS:
//
//		ppcenum			[out] Pointer to a pointer to the object that
//								implements the VARIANT enumerator.
//
//		nNumSelIcons	[in]  The number of selected icons.
//
//	RETURNS:
//
//		HRESULT			NOERROR if the enumerator was created and
//						  initialized successfully, COM error code
//						  otherwise.
//
//-----------------------------------------------------------------------

STDMETHODIMP CAccClient::CreateVarEnumOfSelIcons( CEnumVariant** ppcenum, int nNumSelIcons )
{
	HRESULT			hr;
	VARIANT			var;
	SAFEARRAY FAR*	psa;
	SAFEARRAYBOUND	rgsbnd[1];
	long			ix[1];
	int				i, nNumIconsAdded;


	//-----------------------------------------------------
	//	Create a SAFEARRAY to hold the child ID VARIANTs.
	//	  Note that the number of elements of the array
	//	  is the number of selected icon children of
	//	  CAccClient.
	//-----------------------------------------------------

	rgsbnd[0].lLbound = 0;
	rgsbnd[0].cElements = nNumSelIcons;

	psa = SafeArrayCreate( VT_VARIANT, 1, rgsbnd );
	if ( psa == NULL )
		return E_OUTOFMEMORY;


	//-----------------------------------------------------
	//	Initialize the VARIANT structure that will be
	//	  used to add elements to the array.  Set the
	//	  vt member to VT_I4 because the children are
	//	  referred to by numeric IDs.
	//-----------------------------------------------------

	VariantInit( &var );

	var.vt = VT_I4;


	//-----------------------------------------------------
	//	For each selected icon child, set the VARIANT's
	//	  lVal member to the child's external (Accessible)
	//	  ID and add an element to the SAFEARRAY.
	//-----------------------------------------------------

	for ( i = 0, nNumIconsAdded = 0;
	      nNumIconsAdded < nNumSelIcons && i < NUM_ICONS;
	      i++ )
	{
		if ( g_rgIcons[i].bIsSelected )
		{
			var.lVal = GetChildIDFromOffset( i );

			ix[0] = nNumIconsAdded;

			hr = SafeArrayPutElement( psa, ix, &var );
			if ( FAILED( hr ) )
			{
				SafeArrayDestroy( psa );
				return hr;
			}

			nNumIconsAdded++;
		}
	}


	//-----------------------------------------------------
	//	Create the enumerator.
	//-----------------------------------------------------

	hr = CEnumVariant::Create( psa, nNumSelIcons, ppcenum );


	//-----------------------------------------------------
	//	Clean up by destroying the SAFEARRAY.
	//-----------------------------------------------------

	SafeArrayDestroy( psa );

	return hr;
}
	



//-----------------------------------------------------------------------
//	CAccClient::IsValidChildVariant()
//
//	DESCRIPTION:
//
//		Determines whether or not the VARIANT in-parameter contains
//		a valid child identifier.  Note that only the "32-bit integer"
//		type child IDs are supported.
//
//	PARAMETERS:
//
//		pVar			[in] Pointer to the VARIANT structure to be
//								validated.
//
//	RETURNS:
//
//		BOOL			TRUE if the vt member of the VARIANT has the
//						  correct type (VT_I4) and if the lVal member
//						  is CHILDID_SELF or one of the external
//						  (Accessible) child IDs; FALSE otherwise.
//
//-----------------------------------------------------------------------

BOOL CAccClient::IsValidChildVariant(VARIANT * pVar)
{

    if ( pVar->vt == VT_I4 )
	{
		switch ( pVar->lVal )
		{
			case CHILDID_SELF:
			case CHILDID_RING_ICON:
			case CHILDID_MONEY_ICON:
			case CHILDID_ART_ICON:
			case CHILDID_MANSION_ICON:
			case CHILDID_PERSON_ICON:
			case CHILDID_PLANE_ICON:
			case CHILDID_CLOTHING_ICON:
			case CHILDID_BUTTON:
			case CHILDID_STATBAR:
				return TRUE;
		}
	}

	return FALSE;
}



//-----------------------------------------------------------------------
//	CAccClient::HrLoadString()
//
//	DESCRIPTION:
//
//		Loads a specified string from the resource table.
//
//	PARAMETERS:
//
//		iStr			[in] Resource ID for the desired string.
//
//		psz				[out] Pointer to the BSTR that will receive
//								the loaded string.
//
//	RETURNS:
//
//		HRESULT			S_OK.
//
//-----------------------------------------------------------------------

HRESULT CAccClient::HrLoadString( int iStr, BSTR * psz )
{
    TCHAR	szString[256];
    OLECHAR wszString[256];


    LoadString( m_hInst, iStr, szString, 256 );

    
	MultiByteToWideChar( CP_ACP, 0, szString, -1, wszString, 256 );

    
	*psz = SysAllocString( wszString );


    return S_OK;
}




//-----------------------------------------------------------------------
//	CAccClient::GetOffsetFromChildID()
//
//	DESCRIPTION:
//
//		Converts an external (Accessible) child ID (the ID
//		CAccClient uses to identify its children to the world outside
//		of server) into an offset or server based ID (the ID SERVER.CPP
//		uses to identify one of the children objects within its window).
//
//	PARAMETERS:
//
//		lChildID		[in] The child ID to convert to an offset.
//
//
//	RETURNS:
//
//		int				The child offset corresponding to lChildID.
//
//	NOTES:
//
//		The external (Accessible) child IDs are simply powers of 2.
//		The child offsets are zero based.
//
//-----------------------------------------------------------------------

int	CAccClient::GetOffsetFromChildID( long lChildID )
{
	long	l = lChildID;
	int		nOffset = 0;

	while ( (l = _lrotr(l,1)) > 1 )
		nOffset++;

	return nOffset;
}




//-----------------------------------------------------------------------
//	CAccClient::GetChildIDFromOffset()
//
//	DESCRIPTION:
//
//		Converts a child offset to an external (Accessible) child
//		ID (the ID CAccClient uses to identify its children to the
//		world outside of server).
//
//	PARAMETERS:
//
//		nOffset			[in] The child offset to convert to child ID.
//
//
//	RETURNS:
//
//		long			The child ID corresponding to nOffset.
//
//	NOTES:
//
//		The external (Accessible) child IDs are simply powers of 2.
//		The child offsets are zero based.
//
//-----------------------------------------------------------------------

long CAccClient::GetChildIDFromOffset( int nOffset )
{
	long lID = (long)(pow(2,(nOffset + 1)));

	return lID;
}




/*************************************************************************
    THE INFORMATION AND CODE PROVIDED HEREUNDER (COLLECTIVELY REFERRED TO
    AS "SOFTWARE") IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN
    NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR
    ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL,
    CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF
    MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR
    LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE
    FOREGOING LIMITATION MAY NOT APPLY.
*************************************************************************/


//----  End of ACCESS.CPP  ----