/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright IBM Corporation 2010.
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "stdafx.h"
#include "UAccCOM2.h"
#include "MAccessible.h"

#include <algorithm>
#include "AccAction.h"

#include <com/sun/star/accessibility/XAccessibleText.hpp>
#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
#include <com/sun/star/accessibility/XAccessibleImage.hpp>
#include <com/sun/star/accessibility/XAccessibleTable.hpp>
#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp>
#include <com/sun/star/accessibility/XAccessibleAction.hpp>
#include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp>
#include <com/sun/star/accessibility/XAccessibleHyperText.hpp>
#include <com/sun/star/accessibility/XAccessibleHyperlink.hpp>
#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/XAccessibleGroupPosition.hpp>
#include <com/sun/star/accessibility/XAccessibleValue.hpp>
#include <com/sun/star/accessibility/XAccessibleExtendedAttributes.hpp>
#include <com/sun/star/style/LineSpacing.hpp>
#include <com/sun/star/style/TabStop.hpp>
#include <com/sun/star/container/XIndexReplace.hpp>

#include "AccessibleRole.h"

using namespace com::sun::star::accessibility::AccessibleStateType;

// IA2 states mapping, and name
// maintenance the consistency, change one array, change the three all
long IA2_STATES[] =
    {
        IA2_STATE_ACTIVE,					// =					0x1;
        IA2_STATE_ARMED,					// =					0x2;
        IA2_STATE_DEFUNCT,					// =					0x4;
        IA2_STATE_EDITABLE,					// =					0x8;
        IA2_STATE_HORIZONTAL,				// =					0x10;
        IA2_STATE_ICONIFIED,				// =					0x20;
        IA2_STATE_INVALID_ENTRY,			// =					0x80;
        IA2_STATE_MANAGES_DESCENDANTS,		// =					0x100;
        IA2_STATE_MODAL,					// =					0x200;
        IA2_STATE_MULTI_LINE,				// =					0x400;
        IA2_STATE_OPAQUE,					// =					0x800;
        IA2_STATE_REQUIRED,					// =					0x2000;
        IA2_STATE_SELECTABLE_TEXT,			// =					0x3000;
        IA2_STATE_SINGLE_LINE,				// =					0x4000;
        IA2_STATE_STALE,					// =					0x8000;
        IA2_STATE_SUPPORTS_AUTOCOMPLETION,	// =					0x10000;
        IA2_STATE_TRANSIENT,				//=						0x20000;
        IA2_STATE_VERTICAL					// =					0x40000;
    };
/*
 
<=== map ===>  
 
*/
short UNO_STATES[] =
    {
        ACTIVE,			// = (sal_Int16)1;
        ARMED,			// = (sal_Int16)2;
        DEFUNC,			// = (sal_Int16)5;
        EDITABLE,		// = (sal_Int16)6;
        HORIZONTAL,		// = (sal_Int16)12;
        ICONIFIED,		// = (sal_Int16)13;
        -1,				//IA2_STATE_INVALID_ENTRY
        MANAGES_DESCENDANTS, // = (sal_Int16)15;
        MODAL,			// = (sal_Int16)16;
        MULTI_LINE,		// = (sal_Int16)17;
        OPAQUE,			// = (sal_Int16)19;
        -1,				//IA2_STATE_REQUIRED
        -1,				//IA2_STATE_SELECTABLE_TEXT
        SINGLE_LINE,	// = (sal_Int16)26;
        STALE,			// = (sal_Int16)27;
        -1,				//IA2_STATE_SUPPORTS_AUTOCOMPLETION
        TRANSIENT,		//IA2_STATE_TRANSIENT
        VERTICAL		// = (sal_Int16)29;
    };

//  <=== map ===>

BSTR IA2_STATES_NAME[] =
    {
        _T("Active"),
        _T("Armed"),
        _T("Defunct"),
        _T("Editable"),
        _T("Horizontal"),
        _T("Iconified"),
        _T("Invalid Entry"),
        _T("Manages Decendents"),
        _T("Modal"),
        _T("Multi Line"),
        _T("Opaque"),
        _T("Required"),
        _T("Selectable Text"),
        _T("Single Line"),
        _T("Stale"),
        _T("Supports Autocompletion"),
        _T("Transient"),
        _T("Vertical")
    };

// IA2 states mapping, and name
// maintenance the consistency. change one, change them all

BSTR UNO_ALL_STATES[] =
    {
        _T("INVALID"),			// 	INVALID	( 0 )
        _T("ACTIVE"),			// 	ACTIVE	( 1 )
        _T("ARMED"),			// 	ARMED	( 2 )
        _T("BUSY"),				// 	BUSY	( 3 )
        _T("CHECKED"),			// 	CHECKED	( 4 )
        _T("DEFUNC"),			// 	DEFUNC	( 5 )
        _T("EDITABLE"),			// 	EDITABLE	( 6 )
        _T("ENABLED"),			// 	ENABLED	( 7 )
        _T("EXPANDABLE"),		// 	EXPANDABLE	( 8 )
        _T("EXPANDED"),			// 	EXPANDED	( 9 )
        _T("FOCUSABLE"),		// 	FOCUSABLE	( 10 )
        _T("FOCUSED"),			// 	FOCUSED	( 11 )
        _T("HORIZONTAL"),		// 	HORIZONTAL	( 12 )
        _T("ICONIFIED"),		// 	ICONIFIED	( 13 )
        _T("INDETERMINATE"),	// 	INDETERMINATE	( 14 )
        _T("MANAGES_DESCENDANTS"),// 	MANAGES_DESCENDANTS	( 15 )
        _T("MODAL"),			// 	MODAL	( 16 )
        _T("MULTI_LINE"),		// 	MULTI_LINE	( 17 )
        _T("MULTI_SELECTABLE"),	// 	MULTI_SELECTABLE	( 18 )
        _T("OPAQUE"),			// 	OPAQUE	( 19 )
        _T("PRESSED"),			// 	PRESSED	( 20 )
        _T("RESIZABLE"),		// 	RESIZABLE	( 21 )
        _T("SELECTABLE"),		// 	SELECTABLE	( 22 )
        _T("SELECTED"),			// 	SELECTED	( 23 )
        _T("SENSITIVE"),		// 	SENSITIVE	( 24 )
        _T("SHOWING"),			// 	SHOWING	( 25 )
        _T("SINGLE_LINE"),		// 	SINGLE_LINE	( 26 )
        _T("STALE"),			// 	STALE	( 27 )
        _T("TRANSIENT"),		// 	TRANSIENT	( 28 )
        _T("VERTICAL"),			// 	VERTICAL	( 29 )
        _T("VISIBLE"),			// 	VISIBLE	( 30 )
        _T("MOVEABLE"),			//  MOVEABLE ( 31 )
        _T("OFFSCREEN"),		//  OFFSCREEN ( 32 )
        _T("COLLAPSE"),			//  COLLAPSE ( 33 )
        _T("DEFAULT")			//  DEFAULT ( 34 )
    };


using namespace com::sun::star::accessibility::AccessibleRole;



#define QUERYXINTERFACE(ainterface)	\
{							\
	if(pXAcc == NULL)		\
		return FALSE;		\
	pRContext = pXAcc->getAccessibleContext();	\
	if( !pRContext.is() )	\
	{						\
		return FALSE;		\
	}						\
	Reference<X##ainterface> pRXI(pRContext,UNO_QUERY);\
	if( !pRXI.is() )		\
	{						\
		return FALSE;		\
	}						\
	*ppXI = (XInterface*)pRXI.get();		\
	return TRUE;			\
}

#define ISDESTROY()	\
	if(m_isDestroy)	\
		return S_FALSE;


AccObjectManagerAgent* CMAccessible::g_pAgent = NULL;

CMAccessible::CMAccessible():
        m_iRole(0x00),
        m_dState(0x00),
        m_dChildID(0x00),
        m_dFocusChildID(UACC_NO_FOCUS),
        m_hwnd(NULL),
        m_pIParent(NULL),
        m_pszName(NULL),
        m_pszValue(NULL),
        m_pszDescription(NULL),
        m_isDestroy(FALSE),
        m_pszActionDescription(NULL),
        m_pXAction(NULL),
        m_bRequiresSave(FALSE),
        pUNOInterface(NULL)
{
    m_sLocation.m_dLeft=0;
    m_sLocation.m_dTop = 0;
    m_sLocation.m_dWidth=0;
    m_sLocation.m_dHeight=0;
    CEnumVariant::Create(&m_pEnumVar);
}

CMAccessible::~CMAccessible()
{
        if(m_pszName!=NULL)
    {
        SAFE_SYSFREESTRING(m_pszName);
        m_pszName=NULL;
    }
    if(m_pszValue!=NULL)
    {
        SAFE_SYSFREESTRING(m_pszValue);
        m_pszValue=NULL;
    }
    if(m_pszDescription!=NULL)
    {
        SAFE_SYSFREESTRING(m_pszDescription);
        m_pszDescription=NULL;
    }

    if(m_pszActionDescription!=NULL)
    {
        SAFE_SYSFREESTRING(m_pszActionDescription);
        m_pszActionDescription=NULL;
    }

    if(m_pIParent)
    {
        m_pIParent->Release();
        m_pIParent=NULL;
    }
    pRef = NULL;
    m_pEnumVar->Release();
    m_containedObjects.clear();
    pRContext = NULL;
}

/**
* Returns the Parent IAccessible interface pointer to AT. 
* It should add reference, and the client should release the component.
* It should return E_FAIL when the parent point is null.
* @param	ppdispParent [in,out] used to return the parent interface point.
*			when the point is null, should return null.
* @return   S_OK if successful and E_FAIL if the m_pIParent is NULL.
*/
STDMETHODIMP CMAccessible::get_accParent(IDispatch **ppdispParent)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(ppdispParent == NULL)
    {
        return E_INVALIDARG;
    }

    if(m_pIParent)
    {
        *ppdispParent = m_pIParent;
        (*ppdispParent)->AddRef();
        return S_OK;
    }
    else if(m_hwnd)
    {
        HRESULT hr = AccessibleObjectFromWindow(m_hwnd, OBJID_WINDOW, IID_IAccessible, (void**)ppdispParent);
        if( ! SUCCEEDED( hr ) || ! ppdispParent )
        {
            return S_FALSE;
        }
        return S_OK;
    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns child count of current COM object. 
* @param	pcountChildren [in,out] used to return the children count.
* @return   S_OK if successful.
*/
STDMETHODIMP CMAccessible::get_accChildCount(long *pcountChildren)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pcountChildren == NULL)
    {
        return E_INVALIDARG;
    }

    if(!pUNOInterface)
        return S_FALSE;

    Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
    if( pRContext.is() )
    {
        *pcountChildren = pRContext->getAccessibleChildCount();
    }

    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns child interface pointer for AT according to input child ID. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	ppdispChild, [in,out] use to return the child interface point.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accChild(VARIANT varChild, IDispatch **ppdispChild)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(ppdispChild == NULL)
    {
        return E_INVALIDARG;
    }
    if(varChild.vt==VT_I4)
    {
        //get child interface pointer due to child ID
        if(varChild.lVal==CHILDID_SELF)
        {
            AddRef();
            *ppdispChild = this;
            return S_OK;
        }
        *ppdispChild = GetChildInterface(varChild.lVal);
        (*ppdispChild)->AddRef();
        return (*ppdispChild)?S_OK:S_FALSE;
    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible name of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszName, [in,out] use to return the name of the proper object.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accName(VARIANT varChild, BSTR *pszName)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pszName == NULL)
    {
        return E_INVALIDARG;
    }
    if(varChild.vt==VT_I4)
    {
        if(varChild.lVal==CHILDID_SELF)
        {
            SAFE_SYSFREESTRING(*pszName);
            *pszName = SysAllocString(m_pszName);
            return S_OK;
        }

        long lVal = varChild.lVal;
        varChild.lVal = CHILDID_SELF;
        IMAccessible *pChild = this->GetChildInterface(lVal);
        if(!pChild)
            return E_FAIL;
        return pChild->get_accName(varChild,pszName);
    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible value of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszValue, [in,out] use to return the value of the proper object.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accValue(VARIANT varChild, BSTR *pszValue)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if( pszValue == NULL )
    {
        return E_INVALIDARG;
    }
    if( varChild.vt==VT_I4 )
    {
        if(varChild.lVal==CHILDID_SELF)
        {
            if(m_dState & STATE_SYSTEM_PROTECTED)
                return E_ACCESSDENIED;

            if ( m_pszValue !=NULL && wcslen(m_pszValue) == 0 )
                return S_OK;

            SAFE_SYSFREESTRING(*pszValue);
            *pszValue = SysAllocString(m_pszValue);
            return S_OK;
        }

        long lVal = varChild.lVal;
        varChild.lVal = CHILDID_SELF;
        IMAccessible *pChild = this->GetChildInterface(lVal);
        if(!pChild)
            return E_FAIL;
        return pChild->get_accValue(varChild,pszValue);
    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible description of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszDescription, [in,out] use to return the description of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accDescription(VARIANT varChild, BSTR *pszDescription)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pszDescription == NULL)
    {
        return E_INVALIDARG;
    }
    if(varChild.vt==VT_I4)
    {
        if(varChild.lVal==CHILDID_SELF)
        {
            SAFE_SYSFREESTRING(*pszDescription);
            *pszDescription = SysAllocString(m_pszDescription);
            return S_OK;
        }

        long lVal = varChild.lVal;
        varChild.lVal = CHILDID_SELF;
        IMAccessible *pChild = this->GetChildInterface(lVal);
        if(!pChild)
            return E_FAIL;
        return pChild->get_accDescription(varChild,pszDescription);
    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible role of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pvarRole, [in,out] use to return the role of the proper object.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accRole(VARIANT varChild, VARIANT *pvarRole)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pvarRole == NULL)
    {
        return E_INVALIDARG;
    }
    if(varChild.vt == VT_I4)
    {

        if(varChild.lVal == CHILDID_SELF)
        {
            if( m_iRole < IA2_ROLE_CAPTION )
            {
                VariantInit(pvarRole);
                pvarRole->vt = VT_I4;
                pvarRole->lVal = m_iRole;
            }
            else
            {
                VariantInit(pvarRole);
                pvarRole->vt = VT_I4;
                pvarRole->lVal = ROLE_SYSTEM_CLIENT;
            }
            return S_OK;
        }


        long lVal = varChild.lVal;
        varChild.lVal = CHILDID_SELF;
        IMAccessible *pChild = this->GetChildInterface(lVal);
        if(!pChild)
            return E_FAIL;
        return pChild->get_accRole(varChild,pvarRole);
    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible state of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pvarState, [in,out] use to return the state of the proper object.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accState(VARIANT varChild, VARIANT *pvarState)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pvarState == NULL)
    {
        return E_INVALIDARG;
    }
    if(varChild.vt==VT_I4)
    {
        if(varChild.lVal == CHILDID_SELF)
        {
            if(pUNOInterface)
            {
                Reference< XAccessibleContext > pContext = pUNOInterface->getAccessibleContext();
                if(pContext.is())
                {
					// add the STATE_SYSTEM_LINKED state
                    Reference< XAccessibleHypertext > pRHypertext(pContext,UNO_QUERY);
                    if(pRHypertext.is())
                    {
                        if( pRHypertext->getHyperLinkCount() > 0 )
                            m_dState |= STATE_SYSTEM_LINKED;
                        else
                            m_dState &= ~STATE_SYSTEM_LINKED;
                    }
                    else
                        m_dState &= ~STATE_SYSTEM_LINKED;
                }
            }

            VariantInit(pvarState);
            pvarState->vt = VT_I4;
            pvarState->lVal = m_dState;
            return S_OK;
        }

        long lVal = varChild.lVal;
        varChild.lVal = CHILDID_SELF;
        IMAccessible *pChild = this->GetChildInterface(lVal);
        if(!pChild)
            return E_FAIL;
        return pChild->get_accState(varChild,pvarState);
    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns the accessible helpString of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszHelp, [in,out] use to return the helpString of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accHelp(VARIANT, BSTR *)
{
        return E_NOTIMPL;
}

/**
* Returns the accessible HelpTopic of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszHelpFile, [in,out] use to return the HelpTopic of the proper object.
* @param	pidTopic, use to return the HelpTopic ID of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
* Not implemented yet
*/
STDMETHODIMP CMAccessible::get_accHelpTopic(BSTR *, VARIANT, long *)
{
        return E_NOTIMPL;
}

static void GetMnemonicChar( const ::rtl::OUString& aStr, WCHAR* wStr)
{
    int  nLen    = aStr.pData->length;
    int  i       = 0;
    WCHAR* text = aStr.pData->buffer;

    while ( i < nLen )
    {
        if ( text[i] == L'~' )
            if ( text[i+1] != L'~' )
            {
                wStr[0] = text[i+1];
                break;
            }
        i++;
    }
}

/**
* Returns the accessible keyboard shortcut of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pszKeyboardShortcut, [in,out] use to return the kbshortcut of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK

    ISDESTROY()
    // #CHECK#
    if(pszKeyboardShortcut == NULL)
    {
        return E_INVALIDARG;
    }

    if(varChild.vt==VT_I4)
    {
        if(varChild.lVal == CHILDID_SELF)
        {
            if( pUNOInterface )
            {
                Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext();
                if( !pRContext.is() )
                    return S_FALSE;
                
				Reference<XAccessibleAction> pRXI(pRContext,UNO_QUERY);

                OLECHAR wString[64]={0};

                if( pRXI.is() && pRXI->getAccessibleActionCount() >= 1)
                {
                    Reference< XAccessibleKeyBinding > binding = pRXI->getAccessibleActionKeyBinding(0);
                    if( binding.is() )
                    {
                        long nCount = binding->getAccessibleKeyBindingCount();
                        if(nCount >= 1)
                        {
                            CAccAction::GetkeyBindingStrByXkeyBinding( binding->getAccessibleKeyBinding(0),wString );
                        }
                    }
                }
                if(wString[0] == 0)
                {
                    Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet();
                    if(!pRrelationSet.is())
                    {
                        return S_FALSE;
                    }

                    long nRelCount = pRrelationSet->getRelationCount();

                    // Modified by Steve Yin, for SODC_1552
					if( /*nRelCount <= 0 &&*/ m_iRole == ROLE_SYSTEM_TEXT )
                    {
                        VARIANT varParentRole;
                        VariantInit( &varParentRole );
                    
						m_pIParent->get_accRole(varChild, &varParentRole);
                        
						if( m_pIParent && varParentRole.lVal == ROLE_SYSTEM_COMBOBOX ) // edit in comoboBox
                        {
                            m_pIParent->get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
                            return S_OK;
                        }
                    }

                    AccessibleRelation *paccRelation = NULL;
					AccessibleRelation accRelation;
                    for(int i=0; i<nRelCount ; i++)
                    {
                        if( pRrelationSet->getRelation(i).RelationType == 6 )
						{
							accRelation = pRrelationSet->getRelation(i);
							paccRelation = &accRelation;
						}
                    }

                    if(paccRelation == NULL)
                        return S_FALSE;

                    Sequence< Reference< XInterface > > xTargets = paccRelation->TargetSet;
                    Reference<XInterface> pRAcc = xTargets[0];

                    XAccessible* pXAcc = (XAccessible*)pRAcc.get();

                    Reference<XAccessibleContext> pRLebelContext = pXAcc->getAccessibleContext();
                    if(!pRLebelContext.is())
                        return S_FALSE;

                    pRrelationSet = pRLebelContext->getAccessibleRelationSet();
                    nRelCount = pRrelationSet->getRelationCount();

                    paccRelation = NULL;
                    for(int j=0; j<nRelCount ; j++)
                    {
                        if( pRrelationSet->getRelation(j).RelationType == 5 )
						{
							accRelation = pRrelationSet->getRelation(j);
							paccRelation = &accRelation;
						}
                    }

                    if(paccRelation)
                    {
                        xTargets = paccRelation->TargetSet;
                        pRAcc = xTargets[0];
                        if(pUNOInterface != (XAccessible*)pRAcc.get())
                            return S_FALSE;
                    }

                    Reference<XAccessibleExtendedComponent> pRXIE(pRLebelContext,UNO_QUERY);
                    if(!pRXIE.is())
                        return S_FALSE;

                    ::rtl::OUString ouStr = pRXIE->getTitledBorderText();
                    WCHAR key[2] = {NULL};
                    GetMnemonicChar(ouStr, key);
                    if(key[0] != 0)
                    {
                        wcscat(wString, L"Alt+");
                        wcscat(wString, key);
                    }
                    else
                        return S_FALSE;
                }

                SAFE_SYSFREESTRING(*pszKeyboardShortcut);
                *pszKeyboardShortcut = SysAllocString(wString);

                return S_OK;
            }
            else
            {
                return S_FALSE;
            }
        }

        long lVal = varChild.lVal;
        varChild.lVal = CHILDID_SELF;
        IMAccessible *pChild = this->GetChildInterface(lVal);
        if(!pChild)
            return E_FAIL;

        return pChild->get_accKeyboardShortcut(varChild,pszKeyboardShortcut);
    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns the current focused child to AT. 
* @param	pvarChild, [in,out] vt member of pvarChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::get_accFocus(VARIANT *pvarChild)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pvarChild == NULL)
    {
        return E_INVALIDARG;
    }
    if( m_dFocusChildID==UACC_NO_FOCUS )
    {
        pvarChild->vt = VT_EMPTY;//no focus on the object and its children
        return S_OK;
    }
	//if the descendant of current object has focus indicated by m_dFocusChildID, return the IDispatch of this focused object
	else
	{
	    IMAccessible* pIMAcc = NULL;
        g_pAgent->GetIAccessibleFromResID(m_dFocusChildID,&pIMAcc);
		pIMAcc->AddRef();
		pvarChild->vt = VT_DISPATCH;
        pvarChild->pdispVal = pIMAcc;

	}
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns the selection of the current COM object to AT. 
* @param	pvarChildren,[in,out]
* if selection num is 0,return VT_EMPTY for vt,
* if selection num is 1,return VT_I4 for vt,and child index for lVal
* if selection num >1,return VT_UNKNOWN for vt, and IEnumVariant* for punkVal
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::get_accSelection(VARIANT *pvarChildren)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pvarChildren == NULL)
    {
        return E_INVALIDARG;
    }
    switch(m_pEnumVar->GetCountOfElements())
    {
    case 0:
        pvarChildren->vt = VT_EMPTY;
        break;
    case 1:
        VARIANT varTmp[1];
        ULONG count;
        VariantInit(&varTmp[0]);
        m_pEnumVar->Next(1,varTmp,&count);
        if(count!=1)
            return S_FALSE;
        pvarChildren->vt = VT_I4;
        pvarChildren->lVal = varTmp[0].lVal;
        VariantClear(&varTmp[0]);
        m_pEnumVar->Reset();
        break;
    default:
        pvarChildren->vt = VT_UNKNOWN;
        m_pEnumVar->AddRef();
        pvarChildren->punkVal = m_pEnumVar;
        break;
    }
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns the location of the current COM object self or its one child to AT. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	pxLeft, [in,out] use to return the x-coordination of the proper object.
* @param	pyTop,  [in,out] use to return the y-coordination of the proper object.
* @param	pcxWidth, [in,out] use to return the x-coordination width of the proper object.
* @param	pcyHeight, [in,out] use to return the y-coordination height of the proper object.
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pxLeft == NULL || pyTop == NULL || pcxWidth == NULL || pcyHeight == NULL)
    {
        return E_INVALIDARG;
    }

    if(varChild.vt==VT_I4)
    {
        if(varChild.lVal==CHILDID_SELF)
        {

            if(pUNOInterface)
            {
                Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
                if( !pRContext.is() )
                    return S_FALSE;
                Reference< XAccessibleComponent > pRComponent(pRContext,UNO_QUERY);
                if( !pRComponent.is() )
                    return S_FALSE;

                ::com::sun::star::awt::Point pCPoint = pRComponent->getLocationOnScreen();
                ::com::sun::star::awt::Size pCSize = pRComponent->getSize();
                *pxLeft = pCPoint.X;
                *pyTop =  pCPoint.Y;
                *pcxWidth = pCSize.Width;
                *pcyHeight = pCSize.Height;
                return S_OK;
            }
            else
            {
                *pxLeft = m_sLocation.m_dLeft;
                *pyTop = m_sLocation.m_dTop;
                *pcxWidth = m_sLocation.m_dWidth;
                *pcyHeight = m_sLocation.m_dHeight;
                return S_OK;
            }
        }

    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
* Returns the current focused child to AT. 
* @param	navDir, the direction flag of the navigation.
* @param	varStart, the start child id of this navigation action.
* @param	pvarEndUpAt, [in,out] the end up child of this navigation action.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pvarEndUpAt == NULL)
    {
        return E_INVALIDARG;
    }
    HRESULT ret = E_FAIL;
    switch (navDir)
    {
    case NAVDIR_FIRSTCHILD:
        ret = GetFirstChild(varStart,pvarEndUpAt);
        break;
    case NAVDIR_LASTCHILD:
        ret = GetLastChild(varStart,pvarEndUpAt);
        break;
    case NAVDIR_NEXT:
        ret = GetNextSibling(varStart,pvarEndUpAt);
        break;
    case NAVDIR_PREVIOUS:
        ret = GetPreSibling(varStart,pvarEndUpAt);
        break;
    case NAVDIR_DOWN://do not implement temporarily
        break;
    case NAVDIR_UP://do not implement temporarily
        break;
    case NAVDIR_LEFT://do not implement temporarily
        break;
    case NAVDIR_RIGHT://do not implement temporarily
        break;
    default:
        break;
    };
    return ret;

    LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarChild)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pvarChild == NULL)
    {
        return E_INVALIDARG;
    }
    long x, y, w, h;
    VARIANT varSelf;
    VariantInit(&varSelf);
    varSelf.vt = VT_I4;
    varSelf.lVal = CHILDID_SELF;
    accLocation(&x,&y,&w,&h,varSelf);
    if( (x < xLeft && (x + w) >xLeft) && (y < yTop && (y + h) >yTop) )
    {
        int i, nCount;
        pvarChild->vt = VT_EMPTY;
        Reference< XAccessibleContext > pRContext = GetContextByXAcc(pUNOInterface);
        nCount = pRContext->getAccessibleChildCount();
        if(nCount > 256)
            return E_FAIL;
        IMAccessible* child = NULL;
        for( i = 0; i<nCount; i++)
        {

            child = GetChildInterface(i + 1);
            if(child && child->accHitTest(xLeft,yTop,pvarChild) == S_OK)
                break;
        }

        if(pvarChild->vt == VT_DISPATCH)
            return S_OK;

        if( i < nCount)
        {
            pvarChild->vt = VT_DISPATCH;
            pvarChild->pdispVal = child;
            child->AddRef();
        }
        else
        {
            pvarChild->vt = VT_I4;
            pvarChild->lVal = CHILDID_SELF;
        }
        return S_OK;
    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
* Get The other Interface from CMAccessible. 
* @param	guidService, must be IID_IAccessible here.
* @param	riid, the IID interface .
* @return   S_OK if successful and S_FALSE if failure.
*/
STDMETHODIMP CMAccessible::QueryService(REFGUID guidService, REFIID riid, void** ppvObject)
{
    if( InlineIsEqualGUID(guidService, IID_IAccessible) )
        return QueryInterface(riid, ppvObject);
    return S_FALSE;
}

/**
* Set the accessible name of the current COM object self or its one child from UNO. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	szName, the name used to set the name of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::put_accName(VARIANT varChild, BSTR szName)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if(varChild.vt==VT_I4)
    {
        if(varChild.lVal==CHILDID_SELF)
        {
            SAFE_SYSFREESTRING(m_pszName);
            m_pszName=SysAllocString(szName);
            return S_OK;
        }

        long lVal = varChild.lVal;
        varChild.lVal = CHILDID_SELF;
        IMAccessible *pChild = this->GetChildInterface(lVal);
        if(!pChild)
            return E_FAIL;
        return pChild->put_accName(varChild,szName);
    }
    return E_FAIL;

    LEAVE_PROTECTED_BLOCK
}

/**
* Set the accessible value of the current COM object self or its one child from UNO. 
* @param	varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID,
* the child ID specify child index from 0 to children count, 0 stands for object self.
* @param	szValue, the value used to set the value of the proper object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::put_accValue(VARIANT varChild, BSTR szValue)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if(varChild.vt==VT_I4)
    {
        if(varChild.lVal==CHILDID_SELF)
        {
            SysAllocString(m_pszValue);
            m_pszValue=SysAllocString(szValue);
            return S_OK;
        }

        long lVal = varChild.lVal;
        varChild.lVal = CHILDID_SELF;
        IMAccessible *pChild = this->GetChildInterface(lVal);
        if(!pChild)
            return E_FAIL;
        return pChild->put_accValue(varChild,szValue);
    }
    return E_FAIL;

    LEAVE_PROTECTED_BLOCK
}

/**
* Set the accessible name of the current COM object self from UNO. 
* @param	pszName, the name value used to set the name of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccName(const OLECHAR __RPC_FAR *pszName)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pszName == NULL)
    {
        return E_INVALIDARG;
    }

    SAFE_SYSFREESTRING(m_pszName);//??
    m_pszName = SysAllocString(pszName);
    if(m_pszName==NULL)
        return E_FAIL;
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
* Set the accessible role of the current COM object self from UNO. 
* @param	pRole, the role value used to set the role of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccRole(unsigned short pRole)
{
        m_iRole = pRole;
    return S_OK;
}

/**
* Add one state into the current state set for the current COM object from UNO. 
* @param	pXSate, the state used to set the name of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::DecreaseState(DWORD pXSate)
{
        m_dState &= (~pXSate);
    return S_OK;
}

/**
* Delete one state into the current state set for the current COM object from UNO. 
* @param	pXSate, the state used to set the name of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::IncreaseState(DWORD pXSate)
{
        m_dState |= pXSate;
    return S_OK;
}

/**
* Set state into the current state set for the current COM object from UNO. 
* @param	pXSate, the state used to set the name of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::SetState(DWORD pXSate)
{
        m_dState = pXSate;
    return S_OK;
}



/**
* Set the accessible description of the current COM object self from UNO. 
* @param	pszDescription, the name used to set the description of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccDescription(const OLECHAR __RPC_FAR *pszDescription)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pszDescription == NULL)
    {
        return E_INVALIDARG;
    }

    SAFE_SYSFREESTRING(m_pszDescription);
    m_pszDescription = SysAllocString(pszDescription);

    if(m_pszDescription==NULL)
        return E_FAIL;
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
* Set the accessible value of the current COM object self from UNO. 
* @param	pszAccValue, the name used to set the value of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccValue(const OLECHAR __RPC_FAR *pszAccValue)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pszAccValue == NULL)
    {
        return E_INVALIDARG;
    }
    SAFE_SYSFREESTRING(m_pszValue);
    m_pszValue = SysAllocString(pszAccValue);
    if(m_pszValue==NULL)
        return E_FAIL;
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
* Set the HWND value of the current COM object self from UNO. It should set the parent IAccessible
* Object through the method AccessibleObjectFromWindow(...).
* @param	hwnd, the HWND used to set the value of the current object.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccWindowHandle(HWND hwnd)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    m_hwnd = hwnd;
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
* Set accessible focus by specifying child ID
* @param	dChildID, the child id identifies the focus child.
* @return   S_OK if successful and E_FAIL if failure.
*/
STDMETHODIMP CMAccessible::Put_XAccFocus(long dChildID)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()

    if(dChildID==CHILDID_SELF)
    {
        if(m_pIParent)
        {
            m_pIParent->Put_XAccFocus(m_dChildID);
        }
    }
    else
    {
        m_dFocusChildID = dChildID;
		//traverse all ancestors to set the focused child ID so that when the get_accFocus is called on 
		//any of the ancestors, this id can be used to get the IAccessible of focused object. 
		if(m_pIParent)
        {
            m_pIParent->Put_XAccFocus(dChildID);
        }
    }
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
 *Set accessible object location for the current COM object
 * @param	sLocation, the location of the current object.
 * @return   S_OK if successful and E_FAIL if failure.
 */
STDMETHODIMP CMAccessible::Put_XAccLocation(const Location sLocation)
{
    
    this->m_sLocation = sLocation;
    return S_OK;
}

/**
 * Set accessible parent object for the current COM object if 
 * the current object is a child of some COM object
 * @param	pIParent, the parent of the current object.
 * @return   S_OK if successful and E_FAIL if failure.
 */
STDMETHODIMP CMAccessible::Put_XAccParent(IMAccessible __RPC_FAR *pIParent)
{
    this->m_pIParent = pIParent;

    if(pIParent)
        m_pIParent->AddRef();

    return S_OK;
}

/**
 * Set unique child id to COM
 * @param	dChildID, the id of the current object.
 * @return   S_OK if successful and E_FAIL if failure.
 */
STDMETHODIMP CMAccessible::Put_XAccChildID(long dChildID)
{
    
    this->m_dChildID = dChildID;
    return S_OK;
}

/**
 * Set AccObjectManagerAgent object pointer to COM
 * @param	pAgent, the AccObjectManagerAgent point.
 * @return   S_OK if successful and E_FAIL if failure.
 */
STDMETHODIMP CMAccessible::Put_XAccAgent(long pAgent)
{
    g_pAgent = (AccObjectManagerAgent*)pAgent;
    return S_OK;
}

/**
 * When a UNO control disposing, it disposes its listeners,
 * then notify AccObject in bridge management, then notify 
 * COM that the XAccessible is invalid,so set pUNOInterface as NULL
 * @param	isDestroy, true is it need to be destroyed.
 * @return   S_OK if successful and E_FAIL if failure.
 */
STDMETHODIMP CMAccessible::NotifyDestroy(BOOL isDestroy)
{
    
    m_isDestroy = isDestroy;
    pUNOInterface = NULL;
    return S_OK;
}

/**
 *private methods that help implement public functions
 */

/**
 * Return child interface pointer by child ID,note: need to call AddRef()
 * @param	lChildID, specify child index,which AT(such as Inspect32) gives.
 * @return  IMAccessible*, pointer to the corresponding child object.
 */
IMAccessible* CMAccessible::GetChildInterface(long dChildID)//for test
{
    
    long dChildIndex = 0;
    if(dChildID<0)
    {
        if(g_pAgent)
        {
            IMAccessible* pIMAcc = NULL;
            g_pAgent->GetIAccessibleFromResID(dChildID,&pIMAcc);
            return pIMAcc;
        }
        return NULL;
    }
    else
    {
        Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
        if( !pRContext.is() )
            return NULL;

        if(dChildID<1 || dChildID>pRContext->getAccessibleChildCount())
            return NULL;

        IAccessible* pChild = NULL;
        Reference< XAccessible > pXChild = pRContext->getAccessibleChild(dChildID-1);
        BOOL isGet = get_IAccessibleFromXAccessible((long)pXChild.get(),&pChild);

        if(!isGet)
        {
            g_pAgent->InsertAccObj(pXChild.get(),pUNOInterface,(long)m_hwnd);
            isGet = get_IAccessibleFromXAccessible((long)pXChild.get(),&pChild);
        }

        if(isGet)
        {
            IMAccessible* pIMAcc =  (IMAccessible*)pChild;
            return pIMAcc;
        }
    }

    return NULL;
}

/**
 * For List, tree and table,these roles belong to manage_decendant in UNO,
 * need to process specifically when navigate
 * @return  BOOL, if it is decendantmanager, return true.
 */
BOOL CMAccessible::IsDecendantManage()
{
    
    return (m_iRole==ROLE_SYSTEM_LIST)||(m_iRole==ROLE_SYSTEM_OUTLINE)||(m_iRole==ROLE_SYSTEM_TABLE);
}

/**
 * for decendantmanager circumstance,provide child interface when navigate
 * @param	varCur, the current child.
 * @param	flags, the navigation direction.
 * @return  IMAccessible*, the child of the end up node.
 */
IMAccessible* CMAccessible::GetNavigateChildForDM(VARIANT varCur, short flags)
{
    
    XAccessibleContext* pXContext = GetContextByXAcc(pUNOInterface);
    if(pXContext==NULL)
    {
        return NULL;
    }

    int count = pXContext->getAccessibleChildCount();
    if(count<1)
    {
        return NULL;
    }

    IMAccessible* pCurChild = NULL;
    XAccessible* pChildXAcc = NULL;
    Reference<XAccessible> pRChildXAcc;
    XAccessibleContext* pChildContext = NULL;
    int index = 0,delta=0;
    switch(flags)
    {
    case DM_FIRSTCHILD:
        pRChildXAcc = pXContext->getAccessibleChild(0);
        break;
    case DM_LASTCHILD:
        pRChildXAcc = pXContext->getAccessibleChild(count-1);
        break;
    case DM_NEXTCHILD:
    case DM_PREVCHILD:
        pCurChild = GetChildInterface(varCur.lVal);
        if(pCurChild==NULL)
        {
            return NULL;
        }
        pCurChild->GetUNOInterface((long*)&pChildXAcc);
        if(pChildXAcc==NULL)
        {
            return NULL;
        }
        pChildContext = GetContextByXAcc(pChildXAcc);
        if(pChildContext == NULL)
        {
            return NULL;
        }
        delta = (flags==DM_NEXTCHILD)?1:-1;
        //currently, getAccessibleIndexInParent is error in UNO for
        //some kind of List,such as ValueSet, the index will be less 1 than
        //what should be, need to fix UNO code
        index = pChildContext->getAccessibleIndexInParent()+delta;
        if((index>=0)&&(index<=count-1))
        {
            pRChildXAcc = pXContext->getAccessibleChild(index);
        }
        break;
    default:
        break;
    }

    if(!pRChildXAcc.is())
    {
        return NULL;
    }
    pChildXAcc = pRChildXAcc.get();
    g_pAgent->InsertAccObj(pChildXAcc,pUNOInterface);
    return g_pAgent->GetIMAccByXAcc(pChildXAcc);
}

/**
 *the following 4 private methods are for accNavigate implementation
 */

/**
 * Return first child for parent container, process differently according 
 * to whether it is decendant manage
 * @param	varStart, the start child id of this navigation action.
 * @param	pvarEndUpAt, [in,out] the end up child of this navigation action.
 * @return   S_OK if successful and E_FAIL if failure.
 */
HRESULT CMAccessible::GetFirstChild(VARIANT varStart,VARIANT* pvarEndUpAt)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pvarEndUpAt == NULL)
    {
        return E_INVALIDARG;
    }
    if(varStart.vt != VT_I4)
    {
        pvarEndUpAt->vt = VT_EMPTY;
        return E_INVALIDARG;
    }

    pvarEndUpAt->pdispVal = GetNavigateChildForDM(varStart, DM_FIRSTCHILD);
    if(pvarEndUpAt->pdispVal)
    {
        pvarEndUpAt->pdispVal->AddRef();
        pvarEndUpAt->vt = VT_DISPATCH;
        return S_OK;
    }

    pvarEndUpAt->vt = VT_EMPTY;
    return E_FAIL;

    LEAVE_PROTECTED_BLOCK
}

/**
 * Return last child for parent container, process differently according 
 * to whether it is decendant manage
 * @param	varStart, the start child id of this navigation action.
 * @param	pvarEndUpAt, [in,out] the end up child of this navigation action.
 * @return   S_OK if successful and E_FAIL if failure.
 */
HRESULT CMAccessible::GetLastChild(VARIANT varStart,VARIANT* pvarEndUpAt)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pvarEndUpAt == NULL)
    {
        return E_INVALIDARG;
    }
    if(varStart.vt != VT_I4)
    {
        pvarEndUpAt->vt = VT_EMPTY;
        return E_INVALIDARG;
    }

    pvarEndUpAt->pdispVal = GetNavigateChildForDM(varStart, DM_LASTCHILD);
    if(pvarEndUpAt->pdispVal)
    {
        pvarEndUpAt->pdispVal->AddRef();
        pvarEndUpAt->vt = VT_DISPATCH;
        return S_OK;
    }
    pvarEndUpAt->vt = VT_EMPTY;
    return E_FAIL;

    LEAVE_PROTECTED_BLOCK
}

/**
 * The method GetNextSibling is general, whatever it is decendant manage or not
 * Get the next sibling object.
 * @param	varStart, the start child id of this navigation action.
 * @param	pvarEndUpAt, [in,out] the end up child of this navigation action.
 * @return   S_OK if successful and E_FAIL if failure.
 */
HRESULT CMAccessible::GetNextSibling(VARIANT varStart,VARIANT* pvarEndUpAt)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if(varStart.vt != VT_I4)
    {
        pvarEndUpAt->vt = VT_EMPTY;
        return E_INVALIDARG;
    }

    Reference< XAccessibleContext > pRContext = GetContextByXAcc(pUNOInterface);
    if(pRContext.is())
    {
        varStart.iVal = sal_Int16(pRContext->getAccessibleIndexInParent() + 2);
        if(m_pIParent)
            if( m_pIParent->get_accChild(varStart,&pvarEndUpAt->pdispVal) == S_OK)
            {
                pvarEndUpAt->vt = VT_DISPATCH;
                return S_OK;
            }
    }
    pvarEndUpAt->vt = VT_EMPTY;
    return E_FAIL;

    LEAVE_PROTECTED_BLOCK
}

/**
 *the method GetPreSibling is general, whatever it is decendant manage or not
 * @param	varStart, the start child id of this navigation action.
 * @param	pvarEndUpAt, [in,out] the end up child of this navigation action.
 * @return   S_OK if successful and E_FAIL if failure.
 */
HRESULT CMAccessible::GetPreSibling(VARIANT varStart,VARIANT* pvarEndUpAt)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pvarEndUpAt == NULL)
    {
        return E_INVALIDARG;
    }
    if(varStart.vt != VT_I4)
    {
        pvarEndUpAt->vt = VT_EMPTY;
        return E_INVALIDARG;
    }

    Reference< XAccessibleContext > pRContext = GetContextByXAcc(pUNOInterface);
    if(pRContext.is())
    {
        varStart.iVal = sal_Int16(pRContext->getAccessibleIndexInParent());
        if(m_pIParent && varStart.iVal > 0)
            if( m_pIParent->get_accChild(varStart,&pvarEndUpAt->pdispVal) == S_OK)
            {
                pvarEndUpAt->vt = VT_DISPATCH;
                return S_OK;
            }
    }
    pvarEndUpAt->vt = VT_EMPTY;
    return E_FAIL;

    LEAVE_PROTECTED_BLOCK
}

/**
 * For IAccessible2 implementation methods
 */
STDMETHODIMP CMAccessible::get_nRelations( long __RPC_FAR *nRelations)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK

    // #CHECK#
    if(nRelations == NULL)
    {
        return E_INVALIDARG;
    }

    *nRelations = 0;

    if( !pRContext.is() )
        return E_FAIL;
    Reference<XAccessibleRelationSet> pRrelationSet = pRContext.get()->getAccessibleRelationSet();
    if(!pRrelationSet.is())
    {
        *nRelations = 0;
        return S_OK;
    }

    *nRelations = pRrelationSet->getRelationCount();
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible::get_relation( long relationIndex, IAccessibleRelation __RPC_FAR *__RPC_FAR *relation)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(relation == NULL)
    {
        return E_INVALIDARG;
    }

    if( !pRContext.is() )
        return E_FAIL;


    long nMax = 0;
    long nReal = 0;
    get_nRelations(&nMax);

    *relation = (IAccessibleRelation*)::CoTaskMemAlloc(sizeof(IAccessibleRelation));

    // #CHECK Memory Allocation#
    if(*relation == NULL)
    {
        return E_FAIL;
    }

    if( relationIndex < nMax )
    {


        Reference<XAccessibleRelationSet> pRrelationSet = pRContext.get()->getAccessibleRelationSet();
        if(!pRrelationSet.is())
        {

            return E_FAIL;
        }

        IAccessibleRelation* pRelation = NULL;
        HRESULT hr = CoCreateInstance( CLSID_AccRelation, NULL, CLSCTX_SERVER ,
                                       IID_IAccessibleRelation,
                                       (void **)&pRelation);
        if(SUCCEEDED(hr))
        {
            IUNOXWrapper* wrapper = NULL;
            hr = pRelation->QueryInterface(IID_IUNOXWrapper, (void**)&wrapper);
            if(SUCCEEDED(hr))
            {
                AccessibleRelation accRelation = pRrelationSet->getRelation(relationIndex);
                wrapper->put_XSubInterface((long)&accRelation);
                wrapper->Release();
                *relation = pRelation;
                return S_OK;
            }

        }
    }

    return E_FAIL;

    LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible::get_relations( long, IAccessibleRelation __RPC_FAR *__RPC_FAR *relation, long __RPC_FAR *nRelations)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK

    // #CHECK#
    if(relation == NULL || nRelations == NULL)
    {
        return E_INVALIDARG;
    }
    // #CHECK XInterface#

    if( !pRContext.is() )
        return E_FAIL;

    Reference<XAccessibleRelationSet> pRrelationSet = pRContext.get()->getAccessibleRelationSet();
    if(!pRrelationSet.is())
    {
        *nRelations = 0;
        return S_OK;
    }

    long nCount = pRrelationSet->getRelationCount();

    *relation = (IAccessibleRelation*)::CoTaskMemAlloc(nCount*sizeof(IAccessibleRelation));

    // #CHECK Memory Allocation#
    if(*relation == NULL)
    {
        return E_FAIL;
    }

    for(int i=0; i<nCount ; i++)
    {
        IAccessibleRelation* pRelation = NULL;
        HRESULT hr = CoCreateInstance( CLSID_AccRelation, NULL, CLSCTX_SERVER ,
                                       IID_IAccessibleRelation,
                                       (void **)&pRelation);
        if(SUCCEEDED(hr))
        {
            IUNOXWrapper* wrapper = NULL;
            hr = pRelation->QueryInterface(IID_IUNOXWrapper, (void**)&wrapper);
            if(SUCCEEDED(hr))
            {
                AccessibleRelation accRelation = pRrelationSet->getRelation(i);
                wrapper->put_XSubInterface((long)&accRelation);
                wrapper->Release();
            }
            (relation)[i] = pRelation;
        }
    }

    *nRelations = nCount;
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible::role(long __RPC_FAR *role)
{
    ENTER_PROTECTED_BLOCK

    (*role) = m_iRole;

    return S_OK;

    LEAVE_PROTECTED_BLOCK
}


STDMETHODIMP CMAccessible:: get_nActions(long __RPC_FAR *nActions)
{
    
    try
    {
        ISDESTROY()
        // #CHECK#
        if(nActions == NULL)
        {
            return E_INVALIDARG;
        }
        *nActions = 0L;
        IAccessibleAction* pAcc = NULL;
        HRESULT hr = QueryInterface(IID_IAccessibleAction, (void**)&pAcc);
        if( hr == S_OK )
        {
            pAcc->nActions(nActions);
            pAcc->Release();
        }

        return S_OK;
    }
    catch(...)
    {
        *nActions = 0L;
        return S_OK;
    }
}


STDMETHODIMP CMAccessible:: scrollToPoint(enum IA2CoordinateType, long, long)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    return E_NOTIMPL;
    LEAVE_PROTECTED_BLOCK

}
STDMETHODIMP CMAccessible:: scrollTo(enum IA2ScrollType)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()

    return E_NOTIMPL;

    LEAVE_PROTECTED_BLOCK
}

static XAccessible* getTheParentOfMember(XAccessible* pXAcc)
{
    // #CHECK#
    if(pXAcc == NULL)
    {
        return NULL;
    }
    Reference<XAccessibleContext> pRContext = pXAcc->getAccessibleContext();
    Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet();
    long nRelations = pRrelationSet->getRelationCount();
    for(int i=0 ; i<nRelations ; i++)
    {
        AccessibleRelation accRelation = pRrelationSet->getRelation(i);
        if(accRelation.RelationType == 7)
        {
            Sequence< Reference< XInterface > > xTargets = accRelation.TargetSet;
            return (XAccessible*)xTargets[0].get();
        }
    }
    return NULL;
}

STDMETHODIMP CMAccessible:: get_groupPosition(long __RPC_FAR *groupLevel,long __RPC_FAR *similarItemsInGroup,long __RPC_FAR *positionInGroup)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(groupLevel == NULL || similarItemsInGroup == NULL || positionInGroup == NULL)
    {
        return E_INVALIDARG;
    }

    Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext();
    if(!pRContext.is())
        return E_FAIL;
    long Role = pRContext->getAccessibleRole();

    *groupLevel = 0;
    *similarItemsInGroup = 0;
    *positionInGroup = 0;

    if (Role != AccessibleRole::DOCUMENT)
    {
        Reference< XAccessibleGroupPosition > xGroupPosition( pRContext, UNO_QUERY );
        if ( xGroupPosition.is() )
        {
            Sequence< sal_Int32 > rSeq = xGroupPosition->getGroupPosition( makeAny( pRContext ) );
            sal_Int32* pSeq = rSeq.getArray();
            if ( pSeq )
            {
                *groupLevel = pSeq[0];
                *similarItemsInGroup = pSeq[1];
                *positionInGroup = pSeq[2];
                return S_OK;
            }
            return S_OK;
        }
    }

    Reference< XAccessible> pParentAcc = pRContext->getAccessibleParent();
    if( !pParentAcc.is() )
    {
        return S_OK;
    }

    Reference<XAccessibleContext> pRParentContext = pParentAcc->getAccessibleContext();

    int level = 0;
    int index = 0;
    int number = 0;

    if( Role ==  RADIO_BUTTON )
    {
        Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet();
        long nRel = pRrelationSet->getRelationCount();
        for(int i=0 ; i<nRel ; i++)
        {
            AccessibleRelation accRelation = pRrelationSet->getRelation(i);
            if(accRelation.RelationType == 7)
            {
                Sequence< Reference< XInterface > > xTargets = accRelation.TargetSet;
                int nCount = xTargets.getLength();

                Reference<XInterface> pRAcc = xTargets[0];
                for(int j=0; j<pRParentContext->getAccessibleChildCount(); j++)
                {
                    if( getTheParentOfMember(pRParentContext->getAccessibleChild(j).get())
                            == (XAccessible*)pRAcc.get() &&
                            pRParentContext->getAccessibleChild(j)->getAccessibleContext()->getAccessibleRole() == RADIO_BUTTON)
                        number++;
                    if(pRParentContext->getAccessibleChild(j).get() == pUNOInterface)
                        index = number;
                }
            }
        }
        *groupLevel = 1;
        *similarItemsInGroup = number;
        *positionInGroup = index;
        return S_OK;
    }

    else if ( COMBO_BOX == Role )
    {
        *groupLevel = 1;
        *similarItemsInGroup = 0;
        *positionInGroup = -1;

        long nCount = pRContext->getAccessibleChildCount();
        if( 2 != nCount)
        {
            return S_OK;
        }
        Reference<XAccessible> xList=pRContext->getAccessibleChild(1);
        if (!xList.is())
        {
            return S_OK;
        }
        Reference<XAccessibleContext> xListContext(xList,UNO_QUERY);
        if (!xListContext.is())
        {
            return S_OK;
        }
        Reference<XAccessibleSelection> xListSel(xList,UNO_QUERY);
        if (!xListSel.is())
        {
            return S_OK;
        }
        *similarItemsInGroup = xListContext->getAccessibleChildCount();
        if (*similarItemsInGroup > 0 )
        {
            try
            {
                Reference<XAccessible> xChild = xListSel->getSelectedAccessibleChild(0);
                if (xChild.is())
                {
                    Reference<XAccessibleContext> xChildContext(xChild,UNO_QUERY);
                    if (xChildContext.is())
                    {
                        *positionInGroup=xChildContext->getAccessibleIndexInParent() + 1 ;
                        return S_OK;
                    }
                }
            }
            catch(...)
            {}
        }
        return S_OK;
    }
    else if ( PAGE_TAB == Role )
    {
        *groupLevel = 1;
        *similarItemsInGroup = pRParentContext->getAccessibleChildCount();

        if (*similarItemsInGroup > 0 )
        {
            *positionInGroup=pRContext->getAccessibleIndexInParent() + 1 ;
        }
        else
        {
            *positionInGroup = -1;
        }
        return S_OK;
    }


    BOOL isFound = FALSE;
    while( pParentAcc.is() && !isFound)
    {
        level++;
        pRParentContext = pParentAcc->getAccessibleContext();
        Role = pRParentContext->getAccessibleRole();
        if( (Role == TREE) || (Role == LIST) )
            isFound = TRUE;
        pParentAcc = pRParentContext->getAccessibleParent();
    }

    if( isFound )
    {
        Reference< XAccessible> pTempAcc = pRContext->getAccessibleParent();
        pRParentContext = pTempAcc->getAccessibleContext();
        *groupLevel = level;
        *similarItemsInGroup = pRParentContext->getAccessibleChildCount();
        *positionInGroup = pRContext->getAccessibleIndexInParent() + 1;
    }
    else
    {
        *groupLevel = 0;
        *similarItemsInGroup = 0;
        *positionInGroup = 0;
    }
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible:: get_extendedStates( long, BSTR __RPC_FAR *__RPC_FAR *, long __RPC_FAR *)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()

    return E_NOTIMPL;

    LEAVE_PROTECTED_BLOCK
}


STDMETHODIMP CMAccessible:: get_uniqueID(long __RPC_FAR *uniqueID)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(uniqueID == NULL)
    {
        return E_INVALIDARG;
    }
    *uniqueID = m_dChildID;
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible:: get_windowHandle(HWND __RPC_FAR *windowHandle)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(windowHandle == NULL)
    {
        return E_INVALIDARG;
    }

    HWND nHwnd = m_hwnd;
    IAccessible* pParent = m_pIParent;
    CMAccessible* pChild = this;
    while((nHwnd==0) && pParent)
    {
        pChild = (CMAccessible*)pParent;
        if(pChild)
        {
            pParent = (IAccessible*)pChild->m_pIParent;
            nHwnd = (HWND)pChild->m_hwnd;
        }
        else
            pParent = NULL;
    }

    *windowHandle = nHwnd;
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
 * Get XAccessibleContext directly from UNO by the stored XAccessible pointer
 * @param	pXAcc, UNO XAccessible object point.
 * @return   XAccessibleContext*, the context of the pXAcc.
 */
XAccessibleContext* CMAccessible::GetContextByXAcc( XAccessible* pXAcc )
{
        Reference< XAccessibleContext > pRContext;
    if( pXAcc == NULL)
        return NULL;

    pRContext = pXAcc->getAccessibleContext();
    if( !pRContext.is() )
        return NULL;
    return pRContext.get();
}

/**
 * Return the member variable m_pXAccessibleSelection, instead of 
 * get XAccessibleSelection according to XAccessibleContext because if so,it will 
 * depend on the UNO implementation code,so when COM is created, put XAccessibleSelection
 * by bridge management system
 * @return   XAccessibleSelection*, the selection of the current object.
 */
Reference< XAccessibleSelection > CMAccessible::GetSelection()
{
        if( pUNOInterface == NULL )
        return NULL;
    Reference< XAccessibleContext > pRContext = pUNOInterface->getAccessibleContext();
    if(pRContext.is())
    {
        Reference< XAccessibleSelection > pRSelection(pRContext,UNO_QUERY);
        return pRSelection;
    }
    return NULL;
}

/**
 * Select one XAccessible item, for accSelect implementation
 * @param	pItem, the item should be selected.
 * @return  S_OK if successful.
 */
HRESULT CMAccessible::SelectChild(XAccessible* pItem)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    XAccessibleContext* pParentContext = GetContextByXAcc( pUNOInterface );
    XAccessibleContext* pContext = GetContextByXAcc( pItem );
    if( pParentContext == NULL || pContext == NULL )
        return E_FAIL;

    Reference< XAccessibleSelection > pRSelection = GetSelection();
    if( !pRSelection.is() )
        return E_FAIL;
    long Index = pContext->getAccessibleIndexInParent();
    pRSelection->selectAccessibleChild( Index );
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
 * Deselect one XAccessible item, for accSelect implimentation
 * @param	pItem, the item should be deselected.
 * @return  S_OK if successful.
 */
HRESULT CMAccessible::DeSelectChild(XAccessible* pItem)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    XAccessibleContext* pParentContext = GetContextByXAcc( pUNOInterface );
    ;
    XAccessibleContext* pContext = GetContextByXAcc( pItem );
    if( pParentContext == NULL || pContext == NULL )
        return E_INVALIDARG;

    Reference< XAccessibleSelection > pRSelection = GetSelection();
    if( !pRSelection.is() )
        return E_FAIL;
    long Index = pContext->getAccessibleIndexInParent();
    pRSelection->deselectAccessibleChild( Index );

    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
 * Select multiple XAccessible items,for implementation of accSelect
 * @param	pItem, the items should be selected.
 * @param	size, the size of the items.
 * @return  S_OK if successful.
 */
HRESULT	CMAccessible::SelectMutipleChidren( XAccessible** pItem,int size )
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pItem == NULL)
    {
        return E_INVALIDARG;
    }
    for(int index = 0;index < size;index++)
    {
        SelectChild( pItem[index] );
    }
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
 * Deselect multiple XAccessible items,for implementation of accSelect
 * @param	pItem, the items should be selected.
 * @param	size, the size of the items.
 * @return  S_OK if successful.
 */
HRESULT CMAccessible::DeSelectMutipleChildren( XAccessible** pItem,int size )
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pItem == NULL)
    {
        return E_INVALIDARG;
    }
    for(int index = 0;index < size;index++)
    {
        DeSelectChild( pItem[index] );
    }
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
 * When COM is created, UNO set XAccessible pointer to it
 * in order to COM can operate UNO information
 * @param	pXAcc, the XAccessible object of current object.
 * @return  S_OK if successful.
 */
STDMETHODIMP CMAccessible::SetXAccessible(long pXAcc)
{
    pUNOInterface = (XAccessible*)pXAcc;
    pRef = pUNOInterface;
    m_pEnumVar->PutSelection(/*XAccessibleSelection*/(long)pUNOInterface);

    pRContext = pUNOInterface->getAccessibleContext();
    pRContextInterface = (XAccessibleContext*)pRContext.is();

    return S_OK;
}

/**
 * accSelect method has many optional flags, needs to process comprehensively
 * Mozilla and Microsoft do not implement SELFLAG_EXTENDSELECTION flag. 
 * The implementation of this flag is a little trouble-shooting,so we also
 * do not implement it now
 * @param	flagsSelect, the selection flag of the select action.
 * @param	varChild, the child object pointer of current action.
 * @return  S_OK if successful.
 */
STDMETHODIMP CMAccessible::accSelect(long flagsSelect, VARIANT varChild)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if( (flagsSelect&SELFLAG_ADDSELECTION) &&
            (SELFLAG_REMOVESELECTION&flagsSelect) )
        return E_INVALIDARG;

    if ( (flagsSelect&SELFLAG_TAKESELECTION) &&
            (
                (flagsSelect&SELFLAG_ADDSELECTION) ||
                (flagsSelect&SELFLAG_REMOVESELECTION) ||
                (flagsSelect&SELFLAG_EXTENDSELECTION )
            )
       )
        return E_INVALIDARG;

    if ( varChild.vt !=	VT_I4 )
        return E_INVALIDARG;

    IMAccessible* pSelectAcc;
    if( varChild.lVal == CHILDID_SELF )
    {
        pSelectAcc = this;
        pSelectAcc->AddRef();
    }
    else
    {
        pSelectAcc = GetChildInterface(varChild.lVal);
    }

    if( pSelectAcc == NULL )
        return E_INVALIDARG;

    if( flagsSelect&SELFLAG_TAKEFOCUS )
    {
        long pTempUNO = 0;
        pSelectAcc->GetUNOInterface( &pTempUNO);

        if( pTempUNO == NULL )
            return NULL;

        Reference< XAccessibleContext > pRContext = ( (XAccessible*)pTempUNO)->getAccessibleContext();
        Reference< XAccessibleComponent > pRComponent(pRContext,UNO_QUERY);
        Reference< XAccessible > pRParentXAcc = pRContext->getAccessibleParent();
        Reference< XAccessibleContext > pRParentContext = pRParentXAcc->getAccessibleContext();
        Reference< XAccessibleComponent > pRParentComponent(pRParentContext,UNO_QUERY);
        Reference< XAccessibleSelection > pRParentSelection(pRParentContext,UNO_QUERY);


        pRComponent->grabFocus();

        if( flagsSelect & SELFLAG_TAKESELECTION )
        {
            pRParentSelection->clearAccessibleSelection();
            pRParentSelection->selectAccessibleChild( pRContext->getAccessibleIndexInParent() );
        }

        if( flagsSelect & SELFLAG_ADDSELECTION  )
        {
            pRParentSelection->selectAccessibleChild( pRContext->getAccessibleIndexInParent() );
        }

        if( flagsSelect & SELFLAG_REMOVESELECTION )
        {
            pRParentSelection->deselectAccessibleChild( pRContext->getAccessibleIndexInParent() );
        }

        if( flagsSelect & SELFLAG_EXTENDSELECTION  )
        {
            long indexInParrent = pRContext->getAccessibleIndexInParent();

            if( pRParentSelection->isAccessibleChildSelected( indexInParrent + 1 ) ||
                    pRParentSelection->isAccessibleChildSelected( indexInParrent - 1 ) )
            {
                pRParentSelection->selectAccessibleChild( indexInParrent );
            }
        }

    }

    pSelectAcc->Release();
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

/**
 * Return XAccessible interface pointer when needed
 * @param pXAcc, [in, out] the Uno interface of the current object.
 * @return S_OK if successful.
 */
STDMETHODIMP CMAccessible::GetUNOInterface(long* pXAcc)
{
        // #CHECK#
    if(pXAcc == NULL)
        return E_INVALIDARG;

    *pXAcc = (long)pUNOInterface;
    return S_OK;
}

/**
 * Helper method for Implementation of get_accDefaultAction
 * @param pAction, the default action point of the current object.
 * @return S_OK if successful.
 */
STDMETHODIMP CMAccessible::SetDefaultAction(long pAction)
{
    m_pXAction = (XAccessibleAction*)pAction;
    return S_OK;
}

/**
 * This method is called when AT open some UI elements initially
 * the UI element takes the default action defined here
 * @param varChild, the child id of the defaultaction.
 * @param pszDefaultAction,[in/out] the description of the current action.
 * @return S_OK if successful.
 */
HRESULT STDMETHODCALLTYPE CMAccessible::get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(pszDefaultAction == NULL)
    {
        return E_INVALIDARG;
    }
    if(varChild.vt==VT_I4)
    {
        if(varChild.lVal==CHILDID_SELF)
        {
            if( m_pXAction == NULL )
                return DISP_E_MEMBERNOTFOUND;
            SAFE_SYSFREESTRING(*pszDefaultAction);
            *pszDefaultAction = SysAllocString(m_pszActionDescription);
            return S_OK;
        }

        long lVal = varChild.lVal;
        varChild.lVal = CHILDID_SELF;
        IMAccessible *pChild = this->GetChildInterface(lVal);
        if(!pChild)
            return E_FAIL;
        return pChild->get_accDefaultAction(varChild,pszDefaultAction);
    }
    return S_FALSE;

    LEAVE_PROTECTED_BLOCK
}

/**
 * AT call this method to operate application
 * @param varChild, the child id of the action object.
 * @return S_OK if successful.
 */
HRESULT STDMETHODCALLTYPE CMAccessible::accDoDefaultAction(VARIANT varChild)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if( varChild.vt != VT_I4 )
        return E_INVALIDARG;
    if( m_pXAction == NULL )
        return E_FAIL;
    if( m_pXAction->getAccessibleActionCount() == 0 )
        return E_FAIL;

    if(varChild.lVal==CHILDID_SELF)
    {
        if(m_pXAction->getAccessibleActionCount() > 0)
            m_pXAction->doAccessibleAction(0);
        return S_OK;
    }

    long lVal = varChild.lVal;
    varChild.lVal = CHILDID_SELF;
    IMAccessible *pChild = this->GetChildInterface(lVal);
    if(!pChild)
        return E_FAIL;
    return pChild->accDoDefaultAction( varChild );

    LEAVE_PROTECTED_BLOCK
}

/**
 * UNO set description information for action to COM.
 * @param szAction, the action description of the current object.
 * @return S_OK if successful.
 */
STDMETHODIMP CMAccessible::Put_ActionDescription( const OLECHAR* szAction)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(szAction == NULL)
    {
        return E_INVALIDARG;
    }
    SAFE_SYSFREESTRING(m_pszActionDescription );
    m_pszActionDescription = SysAllocString( szAction );
    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

BOOL CMAccessible::GetXInterfaceFromXAccessible(XAccessible* pXAcc, XInterface** ppXI, int index)
{
        Reference< XAccessibleContext > pRContext;

    switch(index)
    {
    case XI_COMPONENT:
        QUERYXINTERFACE(AccessibleComponent)
        break;
    case XI_TEXT:
        QUERYXINTERFACE(AccessibleText)
        break;
    case XI_EDITABLETEXT:
        QUERYXINTERFACE(AccessibleEditableText)
        break;
    case XI_TABLE:
        QUERYXINTERFACE(AccessibleTable)
        break;
    case XI_SELECTION:
        QUERYXINTERFACE(AccessibleSelection)
        break;
    case XI_EXTENDEDCOMP:
        QUERYXINTERFACE(AccessibleExtendedComponent)
        break;
    case XI_KEYBINDING:
        QUERYXINTERFACE(AccessibleKeyBinding)
        break;
    case XI_ACTION:
        QUERYXINTERFACE(AccessibleAction)
        break;
    case XI_VALUE:
        QUERYXINTERFACE(AccessibleValue)
        break;
    case XI_HYPERTEXT:
        QUERYXINTERFACE(AccessibleHypertext)
        break;
    case XI_HYPERLINK:
        QUERYXINTERFACE(AccessibleHyperlink)
        break;
    case XI_IMAGE:
        QUERYXINTERFACE(AccessibleImage)
        break;
    default:
        break;
    }
    
    return FALSE;
}

HRESULT WINAPI CMAccessible::SmartQI(void* pv, REFIID iid, void** ppvObject)
{
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if( ImplIsEqualGUID(iid,IID_IAccIdentity) ||
            ImplIsEqualGUID(iid,IID_IStdMarshalInfo) ||
            ImplIsEqualGUID(iid,IID_IMarshal) ||
            ImplIsEqualGUID(iid,IID_IExternalConnection)||
            ImplIsEqualGUID(iid,IID_IOleWindow))
        return E_FAIL;

        
    _UNO_AGGMAP_ENTRY* pMap = _GetAggEntries();
    while(pMap && pMap->piid)
    {
        if(ImplIsEqualGUID(iid, *pMap->piid))
        {
                        XInterface* pXI = NULL;
                        BOOL bFound = GetXInterfaceFromXAccessible(pUNOInterface,&pXI,pMap->XIFIndex);
            if(!bFound)
            {
                                return E_FAIL;
            }

            XGUIDToComObjHash::iterator pIndTemp = m_containedObjects.find( iid );
            if ( pIndTemp != m_containedObjects.end() )
            {
                                return pIndTemp->second.p->QueryInterface( iid, ppvObject );
            }
            else
            {
                                HRESULT hr = pMap->pfnCreateInstance(pv, iid, ppvObject);
                if(hr == S_OK)
                {
                    m_containedObjects.insert(XGUIDToComObjHash::value_type(*pMap->piid,(IUnknown*)*ppvObject));
                    IUNOXWrapper* wrapper = NULL;
                    ((IUnknown*)*ppvObject)->QueryInterface(IID_IUNOXWrapper, (void**)&wrapper);
                    if(wrapper)
                    {
                        wrapper->put_XInterface((long)pUNOInterface);
                        wrapper->Release();
                    }
                    return S_OK;
                }
            }
            return E_FAIL;
        }
        pMap++;
    }
    return E_FAIL;

    LEAVE_PROTECTED_BLOCK
}

BOOL CMAccessible::get_IAccessibleFromXAccessible(long pXAcc, IAccessible **ppIA)
{
    
    ENTER_PROTECTED_BLOCK

    // #CHECK#
    if(ppIA == NULL)
    {
        return E_INVALIDARG;
    }
    BOOL isGet = FALSE;
    if(g_pAgent)
        isGet = g_pAgent->GetIAccessibleFromXAccessible((XAccessible*)pXAcc,ppIA);
    
    if(isGet)
        return TRUE;
    else
        return FALSE;

    LEAVE_PROTECTED_BLOCK
}

void CMAccessible::get_OLECHARFromAny(Any& pAny, OLECHAR* pChar)
{
    // #CHECK#
    if(pChar == NULL)
        return;

    switch(pAny.getValueTypeClass())
    {
    case TypeClass_CHAR:
        {
            sal_Int8 val;
            pAny >>= val;
            swprintf( pChar, L"%d", val);
            break;
        }
    case TypeClass_BOOLEAN:
        {
            sal_Bool val;
            pAny >>= val;
            swprintf( pChar, L"%d", val);
            break;
        }
    case TypeClass_BYTE:
        {
            sal_Int8 val;
            pAny >>= val;
            swprintf( pChar, L"%d", val);
            break;
        }
    case TypeClass_SHORT:
        {
            SHORT val;
            pAny >>= val;
            swprintf( pChar, L"%d", val);
            break;
        }
    case TypeClass_UNSIGNED_SHORT:
        {
            USHORT val;
            pAny >>= val;
            swprintf( pChar, L"%d", val);
            break;
        }
    case TypeClass_LONG:
        {
            LONG val;
            pAny >>= val;
            swprintf( pChar, L"%ld", val);
            break;
        }
    case TypeClass_UNSIGNED_LONG:
        {
            ULONG val;
            pAny >>= val;
            swprintf( pChar, L"%ld", val);
            break;
        }
    case TypeClass_FLOAT:
        {
            FLOAT val;
            pAny >>= val;
            swprintf( pChar, L"%.3f", val);
            break;
        }
    case TypeClass_DOUBLE:
        {
            DOUBLE val;
            pAny >>= val;
            swprintf( pChar, L"%.6lf", val);
            break;
        }
    case TypeClass_STRING:
        {
            ::rtl::OUString val;
            pAny >>= val;
            wcscpy(pChar, val.getStr());
            break;
        }
    case TypeClass_SEQUENCE:
        {
            if(pAny.getValueType() == getCppuType( (Sequence< ::rtl::OUString > *)0 ) )
            {
                Sequence < ::rtl::OUString > val;
                pAny >>= val;

                ::rtl::OUString pString;

                int count = val.getLength();

                for( int iIndex = 0;iIndex < count;iIndex++ )
                {
                    pString += val[iIndex];
                }
                wcscpy(pChar, pString.getStr());
            }
            else if (pAny.getValueType() == getCppuType( (Sequence< ::com::sun::star::style::TabStop >* )0 ) )
            {
                Sequence < ::com::sun::star::style::TabStop > val;
                pAny >>= val;
                int count = val.getLength();

                for( int iIndex = 0;iIndex < count;iIndex++ )
                {
                    OLECHAR pAttrs[512] = {NULL};

                    OLECHAR pAttrsPosition[512] = {NULL};
                    OLECHAR pAttrsDescimalChar[512] = {NULL};
                    OLECHAR pAttrsFillChar[512] = {NULL};

                    ::com::sun::star::style::TabStop sigleVal = val[iIndex];

                    swprintf( pAttrsPosition, L"Position=%ld,TabAlign=%ld",
                              sigleVal.Position, sigleVal.Alignment);

                    if(sigleVal.DecimalChar==';' || sigleVal.DecimalChar == ':' || sigleVal.DecimalChar == ',' ||
                            sigleVal.DecimalChar == '=' || sigleVal.DecimalChar == '\\')
                        swprintf( pAttrsDescimalChar, L"DecimalChar=\\%c",sigleVal.DecimalChar);
                    else
                        swprintf( pAttrsDescimalChar, L"DecimalChar=%c",sigleVal.DecimalChar);

                    if(sigleVal.FillChar==';' || sigleVal.FillChar == ':' || sigleVal.FillChar == ',' ||
                            sigleVal.FillChar == '=' || sigleVal.FillChar == '\\')
                        swprintf( pAttrsFillChar, L"FillChar=\\%c",sigleVal.FillChar);
                    else
                        swprintf( pAttrsFillChar, L"FillChar=%c",sigleVal.FillChar);

                    swprintf( pAttrs, L"%s,%s,%s,",pAttrsPosition,pAttrsDescimalChar,pAttrsFillChar);

                    wcscat(pChar,pAttrs);
                }
            }
            break;
        }
    case TypeClass_ENUM:
        {
            if (pAny.getValueType() == getCppuType( (::com::sun::star::awt::FontSlant* )0 ) )
            {
                com::sun::star::awt::FontSlant val;
                pAny >>= val;
                swprintf( pChar, L"%d", val);
            }
        }
    case TypeClass_STRUCT:
        {
            if (pAny.getValueType() == getCppuType( (::com::sun::star::style::LineSpacing* )0 ) )
            {
                com::sun::star::style::LineSpacing val;
                pAny >>= val;
                swprintf( pChar, L"Mode=%ld,Height=%ld,", val.Mode, val.Height);
            }
            else if (pAny.getValueType() == getCppuType( (com::sun::star::accessibility::TextSegment *)0 ) )
            {
                com::sun::star::accessibility::TextSegment val;
                pAny >>= val;
                ::rtl::OUString realVal(val.SegmentText);
                wcscpy(pChar, realVal.getStr());
            }
            break;
        }
    case TypeClass_VOID:
    case TypeClass_HYPER:
    case TypeClass_UNSIGNED_HYPER:
    case TypeClass_TYPE:
    case TypeClass_ANY:
    case TypeClass_TYPEDEF:
    case TypeClass_UNION:
    case TypeClass_EXCEPTION:
    case TypeClass_ARRAY:
    case TypeClass_INTERFACE:
    case TypeClass_SERVICE:
    case TypeClass_MODULE:
    case TypeClass_INTERFACE_METHOD:
    case TypeClass_INTERFACE_ATTRIBUTE:
    case TypeClass_UNKNOWN:
    case TypeClass_PROPERTY:
    case TypeClass_CONSTANT:
    case TypeClass_CONSTANTS:
    case TypeClass_SINGLETON:
    case TypeClass_MAKE_FIXED_SIZE:
        break;
    default:
        break;
    }
}

void CMAccessible::get_OLECHAR4Numbering(const Any& pAny, short numberingLevel,const OUString& numberingPrefix,OLECHAR* pChar)
{
    if(pChar == NULL)
        return;
    Reference< ::com::sun::star::container::XIndexReplace > pXIndex;
    if((pAny>>=pXIndex) && (numberingLevel !=-1))//numbering level is -1,means invalid value
    {
        Any aAny = pXIndex->getByIndex(numberingLevel);
        Sequence< ::com::sun::star::beans::PropertyValue > aProps;
        aAny >>= aProps;
        const ::com::sun::star::beans::PropertyValue* pPropArray = aProps.getConstArray();
        sal_Int32 nCount = aProps.getLength();
        swprintf(pChar,L"Numbering:NumberingLevel=%d,",numberingLevel);
        for( sal_Int32 i=0; i<nCount; i++ )
        {
            ::com::sun::star::beans::PropertyValue rProp = pPropArray[i];
            if(	(rProp.Name.compareTo(OUString::createFromAscii("BulletChar"))==0)||
                    (rProp.Name.compareTo(OUString::createFromAscii("GraphicURL"))==0)||
                    (rProp.Name.compareTo(OUString::createFromAscii("NumberingType"))==0))
            {
                OLECHAR propStr[512] = {NULL};
                swprintf(propStr,L"%s=",rProp.Name.getStr());
                OLECHAR pTemp[256] = {NULL};
                CMAccessible::get_OLECHARFromAny(rProp.Value,pTemp);
                if(rProp.Name.compareTo(OUString::createFromAscii("GraphicURL"))==0)
                {
                    OLECHAR* pOccur = wcschr(pTemp,':');
                    if(pOccur)
                        *pOccur = '.';
                }
                wcscat(propStr,pTemp);
                wcscat(pChar,propStr);
                wcscat(pChar,L",");

                if(rProp.Name.compareTo(OUString::createFromAscii("NumberingType"))==0)
                {
                    if(numberingPrefix.getLength()!=0)
                    {
                        swprintf(pTemp,L"NumberingPrefix=%s,",numberingPrefix.getStr());
                        wcscat(pChar,pTemp);
                    }
                }
            }
        }
    }

    //Because now have three types numbering level:
    //1.real numbering list,numbering level>=0 and numbering Rule !=NULL;
    //2.common paragraph, numbering level >=0, and numbering Rule == NULL;
    //3.TOC paragraph, numbering level >0, and numbering Rule ==NULL;
    // IAText:numberinglevel base on 0, but TOC's level base on 1,
    // so NumberingLevel value will be decreased 1 in bridge code.
    else if(numberingLevel >0)
    {
        swprintf(pChar,L"Numbering:NumberingLevel=%d,NumberingType=4,NumberingPrefix=,",numberingLevel-1);
    }
    else
    {
        swprintf(pChar,L"Numbering:");
    }
}

void CMAccessible::ConvertAnyToVariant(const ::com::sun::star::uno::Any &rAnyVal, VARIANT *pvData)
{
    if(rAnyVal.hasValue())
    {
        // Clear VARIANT variable.
        VariantClear(pvData);

        // Set value according to value type.
        switch(rAnyVal.getValueTypeClass())
        {
        case TypeClass_CHAR:
            pvData->vt = VT_UI1;
            memcpy(&pvData->bVal, rAnyVal.getValue(), sizeof(sal_Char));
            break;

        case TypeClass_BOOLEAN:
            pvData->vt = VT_BOOL;
            memcpy(&pvData->boolVal, rAnyVal.getValue(), sizeof(sal_Bool));
            break;

        case TypeClass_BYTE:
            pvData->vt = VT_UI1;
            memcpy(&pvData->bVal, rAnyVal.getValue(), sizeof(sal_Int8));
            break;

        case TypeClass_SHORT:
            pvData->vt = VT_I2;
            memcpy(&pvData->iVal, rAnyVal.getValue(), sizeof(sal_Int16));
            break;

        case TypeClass_UNSIGNED_SHORT:
            pvData->vt = VT_I2;
            memcpy(&pvData->iVal, rAnyVal.getValue(), sizeof(sal_uInt16));
            break;

        case TypeClass_LONG:
            pvData->vt = VT_I4;
            memcpy(&pvData->lVal, rAnyVal.getValue(), sizeof(sal_Int32));
            break;

        case TypeClass_UNSIGNED_LONG:
            pvData->vt = VT_I4;
            memcpy(&pvData->lVal, rAnyVal.getValue(), sizeof(sal_uInt32));
            break;

        case TypeClass_FLOAT:
            pvData->vt = VT_R4;
            memcpy(&pvData->fltVal, rAnyVal.getValue(), sizeof(float));
            break;

        case TypeClass_DOUBLE:
            pvData->vt = VT_R8;
            memcpy(&pvData->dblVal, rAnyVal.getValue(), sizeof(double));
            break;

        case TypeClass_STRING:
            {
                pvData->vt = VT_BSTR;
                ::rtl::OUString val;
                rAnyVal >>= val;
                pvData->bstrVal = SysAllocString((OLECHAR *)val.getStr());
                break;
            }

        case TypeClass_VOID:
        case TypeClass_HYPER:
        case TypeClass_UNSIGNED_HYPER:
        case TypeClass_TYPE:
        case TypeClass_ANY:
        case TypeClass_ENUM:
        case TypeClass_TYPEDEF:
        case TypeClass_STRUCT:
        case TypeClass_UNION:
        case TypeClass_EXCEPTION:
        case TypeClass_SEQUENCE:
        case TypeClass_ARRAY:
        case TypeClass_INTERFACE:
            {
                Reference< XAccessible > pXAcc;
                if(rAnyVal >>= pXAcc)
                {
                    if(pXAcc.is())
                    {
                        IAccessible* pIAcc = NULL;
                        get_IAccessibleFromXAccessible((long)pXAcc.get(), &pIAcc);
                        if(pIAcc == NULL)
                        {
                            Reference< XAccessibleContext > pXAccContext = pXAcc->getAccessibleContext();
                            g_pAgent->InsertAccObj(pXAcc.get(),pXAccContext->getAccessibleParent().get());
                            get_IAccessibleFromXAccessible((long)pXAcc.get(), &pIAcc);
                        }
                        if(pIAcc)
                        {
                            pIAcc->AddRef();

                            pvData->vt = VT_UNKNOWN;
                            pvData->pdispVal = (IAccessible2*)pIAcc;
                            break;
                        }
                    }
                }
            }
        case TypeClass_SERVICE:
        case TypeClass_MODULE:
        case TypeClass_INTERFACE_METHOD:
        case TypeClass_INTERFACE_ATTRIBUTE:
        case TypeClass_UNKNOWN:
        case TypeClass_PROPERTY:
        case TypeClass_CONSTANT:
        case TypeClass_CONSTANTS:
        case TypeClass_SINGLETON:
        case TypeClass_MAKE_FIXED_SIZE:
            // Output the type string, if there is other uno value type.
            pvData->vt = VT_BSTR;
            pvData->bstrVal = SysAllocString(rAnyVal.getValueTypeName().getStr());
            break;

        default:
            break;
        }
    }
    else
    {
        VariantClear(pvData);
    }
}

STDMETHODIMP CMAccessible::Get_XAccChildID(long* childID)
{
    // #CHECK#
    if(childID == NULL)
    {
        return E_FAIL;
    }
    *childID = m_dChildID;
    return S_OK;
}
STDMETHODIMP CMAccessible:: get_states(AccessibleStates __RPC_FAR *states )
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK XInterface#
    if( !pRContext.is() )
        return E_FAIL;

    Reference<XAccessibleStateSet> pRStateSet = pRContext.get()->getAccessibleStateSet();
    if(!pRStateSet.is())
    {
        return S_OK;
    }
    Sequence<short> pStates = pRStateSet->getStates();


    long count = pStates.getLength() ;
    *states = 0x0;
    for( int i = 0; i < count; i++  )
    {
        for( int j = 0; j < sizeof(UNO_STATES) / sizeof(UNO_STATES[0]); j++ )
        {
            if( pStates[i] == UNO_STATES[j] )
            {
                *states |= IA2_STATES[j];
                break;
            }
        }
    }
    return S_OK;


    LEAVE_PROTECTED_BLOCK
}

// return the UNO roles
STDMETHODIMP CMAccessible:: get_extendedRole( BSTR __RPC_FAR *  )
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()

    return E_NOTIMPL;

    LEAVE_PROTECTED_BLOCK
}

STDMETHODIMP CMAccessible:: get_localizedExtendedRole( BSTR __RPC_FAR *  )
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    return E_NOTIMPL;

    LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_nExtendedStates( long __RPC_FAR * )
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()

    return E_NOTIMPL;

    LEAVE_PROTECTED_BLOCK
}


STDMETHODIMP CMAccessible:: get_localizedExtendedStates( long, BSTR __RPC_FAR *__RPC_FAR *, long __RPC_FAR *)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    return E_NOTIMPL;

    LEAVE_PROTECTED_BLOCK
}


STDMETHODIMP CMAccessible:: get_indexInParent( long __RPC_FAR *accParentIndex)
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    // #CHECK#
    if(accParentIndex == NULL)
        return E_INVALIDARG;

    // #CHECK XInterface#
    if( !pRContext.is() )
        return E_FAIL;

    *accParentIndex = pRContext.get()->getAccessibleIndexInParent();
    return S_OK;


    LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_locale( IA2Locale __RPC_FAR *locale  )
{
    
	CHECK_ENABLE_INF
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if(locale == NULL)
        return E_INVALIDARG;
    // #CHECK XInterface#

    if( !pRContext.is() )
        return E_FAIL;

    ::com::sun::star::lang::Locale unoLoc = pRContext.get()->getLocale();
    locale->language = SysAllocString((OLECHAR*)unoLoc.Language.getStr());
    locale->country = SysAllocString((OLECHAR*)unoLoc.Country.getStr());
    locale->variant = SysAllocString((OLECHAR*)unoLoc.Variant.getStr());

    return S_OK;

    LEAVE_PROTECTED_BLOCK
}

DWORD GetMSAAStateFromUNO(short xState)
{
    DWORD IState = STATE_SYSTEM_UNAVAILABLE;
    switch( xState )
    {
    case /*AccessibleStateType::*/AccessibleStateType::BUSY:
        IState = STATE_SYSTEM_BUSY;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::CHECKED:
        IState = STATE_SYSTEM_CHECKED;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::DEFUNC:
        IState = STATE_SYSTEM_UNAVAILABLE;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::EXPANDED:
        IState = STATE_SYSTEM_EXPANDED;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::FOCUSABLE:
        IState = STATE_SYSTEM_FOCUSABLE;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::FOCUSED:
        IState = STATE_SYSTEM_FOCUSED;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::INDETERMINATE:
        IState = STATE_SYSTEM_MIXED;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::MULTI_SELECTABLE:
        IState = STATE_SYSTEM_MULTISELECTABLE;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::PRESSED:
        IState = STATE_SYSTEM_PRESSED;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::RESIZABLE:
        IState = STATE_SYSTEM_SIZEABLE;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::SELECTABLE:
        IState = STATE_SYSTEM_SELECTABLE;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::SELECTED:
        IState = STATE_SYSTEM_SELECTED;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::ARMED:
        IState = STATE_SYSTEM_FOCUSED;
        break;
    case /*AccessibleStateType::*/AccessibleStateType::EXPANDABLE:
        IState = STATE_SYSTEM_COLLAPSED;
        break;
    default:
        break;
    }
    return IState;
}

STDMETHODIMP CMAccessible:: get_appName( BSTR __RPC_FAR *name)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if(name == NULL)
        return E_INVALIDARG;

    *name = SysAllocString(OLESTR("Hannover"));
    return S_OK;
    LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_appVersion(BSTR __RPC_FAR *version)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if(version == NULL)
        return E_INVALIDARG;
    *version=SysAllocString(OLESTR("3.0"));
    return S_OK;
    LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_toolkitName(BSTR __RPC_FAR *name)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if(name == NULL)
        return E_INVALIDARG;
    *name = SysAllocString(OLESTR(" "));
    return S_OK;
    LEAVE_PROTECTED_BLOCK
}
STDMETHODIMP CMAccessible:: get_toolkitVersion(BSTR __RPC_FAR *version)
{
    
    ENTER_PROTECTED_BLOCK
    ISDESTROY()
    if(version == NULL)
        return E_INVALIDARG;
    *version = SysAllocString(OLESTR(" "));
    return S_OK;
    LEAVE_PROTECTED_BLOCK
}


STDMETHODIMP CMAccessible::get_attributes(/*[out]*/ BSTR *pAttr)
{
	CHECK_ENABLE_INF
    Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext();
    if( !pRContext.is() )
    {
        return E_FAIL;
    }
    Reference<XAccessibleExtendedAttributes> pRXI(pRContext,UNO_QUERY);
    if( !pRXI.is() )
        return E_FAIL;
    else
    {
        com::sun::star::uno::Reference<com::sun::star::accessibility::XAccessibleExtendedAttributes> pRXAttr;
        pRXAttr = pRXI.get();
        ::com::sun::star::uno::Any	anyVal = pRXAttr->getExtendedAttributes();

        ::rtl::OUString val;
        anyVal >>= val;

        if(*pAttr)
            SAFE_SYSFREESTRING(*pAttr);
        *pAttr = SysAllocString((OLECHAR *)val.getStr());

        return S_OK;
    }
}

