/*************************************************************************
    Project:    Microsoft Active Accessibility
    Module:     OBJECTS.CPP

    Author:     LauraBu, SteveDon, PeteW
    Date:       5/1/96
    
    Notes:      Functions for dealing with IAccessible objects,
                given IDs passed by WinEvents.

    Copyright (C) 1996 by Microsoft Corporation.  All rights reserved.
    See bottom of file for disclaimer
    
    History:    

*************************************************************************/

#include <windows.h>
#include <windowsx.h>
#include <winable.h>
#include <ole2.h>
#include <oleacc.h>
#include "event.h"

#define CCH_NAME_MAX            128
#define CCH_ROLE_MAX             64
#define CCH_PARENT_MAX          192
#define CCH_STATE_MAX           512
#define CCH_VALUE_MAX           256
#define CCH_DESCRIPTION_MAX     256
#define CCH_DEFACTION_MAX        64
#define CCH_SHORTCUT_MAX         32
#define CCH_HELP_MAX            512

#define BASICSTR(s) wsprintf(lpszBuf, "-- %s: hwnd 0x%lx, idContainer 0x%lx, idObject 0x%lx ERR 0x%lx", s, hwnd, idContainer, idObject, GetLastError())

//pkw
#ifdef _DEBUG
  #define DBOUTPUT(x) OutputDebugString(x)
#else
  #define DBOUTPUT(x)
#endif 

IAccessible* GetObject(HWND, LONG, LONG, VARIANT*);
IAccessible* GetObjectAtCursor(VARIANT*);

// SEF_CREATION
UINT    GetObjectCreateString(HWND, LONG, LONG, LPTSTR, UINT);
UINT    GetObjectDestroyString(HWND, LONG, LONG, LPTSTR, UINT);

// SEF_LOCATION
UINT    GetObjectMoveString(HWND, LONG, LONG, LPTSTR, UINT);
UINT    GetObjectReorderString(HWND, LONG, LONG, LPTSTR, UINT);
UINT    GetObjectParentString(HWND, LONG, LONG, LPTSTR, UINT);

// SEF_STATE
UINT    GetObjectStateString(HWND, LONG, LONG, LPTSTR, UINT);

// SEF_FOCUSSEL
UINT    GetObjectFocusString(HWND, LONG, LONG, LPTSTR, UINT);
UINT    GetObjectSelectedItemString(HWND, LONG, LONG, DWORD, LPTSTR, UINT);
UINT    GetObjectSelectionString(HWND, LONG, LONG, LPTSTR, UINT);

// SEF_DESCRIPTION
UINT    GetObjectNameString(HWND, LONG, LONG, LPTSTR, UINT);
UINT    GetObjectDescriptionString(HWND, LONG, LONG, LPTSTR, UINT);
UINT    GetObjectValueString(HWND, LONG, LONG, LPTSTR, UINT);

// SEF_OTHER
UINT    GetObjectHelpString(HWND, LONG, LONG, LPTSTR, UINT);
UINT    GetObjectDefActionString(HWND, LONG, LONG, LPTSTR, UINT);
UINT    GetObjectAcceleratorString(HWND, LONG, LONG, LPTSTR, UINT);

// SEF_MODETRACK
UINT    GetObjectModeString(HWND, LONG, LONG, DWORD, LPTSTR, UINT);


// FAKE EVENTS (queries)
UINT    DoObjectDefAction(LPTSTR, UINT);
UINT    DoObjectFocus(LPTSTR, UINT);
UINT    DoObjectSelection(DWORD, LPTSTR, UINT);
UINT    DoObjectHitTest(LPTSTR, UINT);


// --------------------------------------------------------------------------
//
//  ObjectProc()
//
// --------------------------------------------------------------------------
UINT ObjectProc(HWINEVENTHOOK hEvent, DWORD event, HWND hwnd, LONG idContainer,
    LONG idObject, DWORD idThread, LPTSTR lpszBuf, UINT cchBuf)
{
    UINT    cchReturn;
    *lpszBuf = 0;
    cchReturn = 0;
    TCHAR szBuf[64];

    switch (event)
    {
        case EVENT_OBJECT_CREATE:
            if (grfTrack & SEF_CREATION)
            {
                cchReturn = GetObjectCreateString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("CREATE");
            }
            break;

        case EVENT_OBJECT_DESTROY:
            if (grfTrack & SEF_CREATION)
            {
                cchReturn = GetObjectDestroyString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("DESTROY");
            }
            break;

        case EVENT_OBJECT_SHOW: lstrcpy(szBuf, "SHOW"); goto GETSTATE;
        case EVENT_OBJECT_HIDE: lstrcpy(szBuf, "HIDE"); goto GETSTATE;
        case EVENT_OBJECT_STATECHANGE: lstrcpy(szBuf, "STATECHANGE"); goto GETSTATE;
        GETSTATE:
            if (grfTrack & SEF_STATE)
            {
                cchReturn = GetObjectStateString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR(szBuf);
            }
            break;

        case EVENT_OBJECT_REORDER:
            if (grfTrack & SEF_LOCATION)
            {
                cchReturn = GetObjectReorderString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("Reorder");
            }
            break;

        case EVENT_OBJECT_LOCATIONCHANGE:
            if (grfTrack & SEF_LOCATION)
            {
                cchReturn = GetObjectMoveString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("LOCATIONCHANGE");
            }
            break;

        case EVENT_OBJECT_PARENTCHANGE:
            if (grfTrack & SEF_LOCATION)
            {
                cchReturn = GetObjectParentString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("PPARENTCHANGE");
            }
            break;


        case EVENT_OBJECT_FOCUS:
            if ((grfTrack & SEF_FOCUSSEL) && hwnd)
            {
                cchReturn = GetObjectFocusString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("Focus");
            }
            break;

        case EVENT_OBJECT_SELECTION:  lstrcpy(szBuf, "OBJECT_SELECTION"); goto GETSELECT;
        case EVENT_OBJECT_SELECTIONADD:    lstrcpy(szBuf, "OBJECT_SELECTIONADD"); goto GETSELECT;
        case EVENT_OBJECT_SELECTIONREMOVE: lstrcpy(szBuf, "OBJECT_SELECTIONREMOVE"); goto GETSELECT;
        case EVENT_SYSTEM_FOREGROUND: lstrcpy(szBuf, "SYSTEM_FOREGROUND"); goto GETSELECT;
        GETSELECT:
            if (grfTrack & SEF_FOCUSSEL)
            {
                cchReturn = GetObjectSelectedItemString(hwnd, idContainer, idObject, event, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR(szBuf);
            }
            break;

        case EVENT_OBJECT_SELECTIONWITHIN:
            if (grfTrack & SEF_FOCUSSEL)
            {
                cchReturn = GetObjectSelectionString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("Selection within");
            }
            break;

        case EVENT_OBJECT_VALUECHANGE:
            if (grfTrack & SEF_DESCRIPTION)
            {
                cchReturn = GetObjectValueString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("VALUECHANGE");
            }
            break;

        case EVENT_OBJECT_NAMECHANGE:
            if (grfTrack & SEF_DESCRIPTION)
            {
                cchReturn = GetObjectNameString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("NAMECHANGE");
            }
            break;

        case EVENT_OBJECT_DESCRIPTIONCHANGE:
            if (grfTrack & SEF_DESCRIPTION)
            {
                cchReturn = GetObjectDescriptionString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("DESCRIPTIONCHANGE");
            }
            break;

        case EVENT_OBJECT_HELPCHANGE:
            if (grfTrack & SEF_OTHER)
            {
                cchReturn = GetObjectHelpString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("HELPCHANGE");
            }
            break;

        case EVENT_OBJECT_DEFACTIONCHANGE:
            if (grfTrack & SEF_OTHER)
            {
                cchReturn = GetObjectDefActionString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("DEFAULTCHANGE");
            }
            break;
            
        case EVENT_OBJECT_ACCELERATORCHANGE:
            if (grfTrack & SEF_OTHER)
            {
                cchReturn = GetObjectAcceleratorString(hwnd, idContainer, idObject, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR("ACCELERATORCHANGE");
            }
            break;

        case EVENT_SYSTEM_MENUSTART: lstrcpy(szBuf, "MENUSTART"); goto OBJECTMODE;
        case EVENT_SYSTEM_MENUEND:   lstrcpy(szBuf, "MENUEND"); goto OBJECTMODE;
        case EVENT_SYSTEM_MENUPOPUPSTART: lstrcpy(szBuf, "MENUPOPUPSTART"); goto OBJECTMODE;
        case EVENT_SYSTEM_MENUPOPUPEND:   lstrcpy(szBuf, "MENUPOPUPEND"); goto OBJECTMODE;
        case EVENT_SYSTEM_MOVESIZESTART:  lstrcpy(szBuf, "MOVESIZESTART"); goto OBJECTMODE;
        case EVENT_SYSTEM_MOVESIZEEND:    lstrcpy(szBuf, "MOVESIZEEND"); goto OBJECTMODE;
        case EVENT_SYSTEM_CAPTURESTART:   lstrcpy(szBuf, "CAPTURESTART"); goto OBJECTMODE;
        case EVENT_SYSTEM_CAPTUREEND:     lstrcpy(szBuf, "CAPTUREEND"); goto OBJECTMODE;
        case EVENT_SYSTEM_CONTEXTHELPSTART: lstrcpy(szBuf, "ONTEXTHELPSTART"); goto OBJECTMODE;
        case EVENT_SYSTEM_CONTEXTHELPEND: lstrcpy(szBuf, "CONTEXTHELPEND"); goto OBJECTMODE;
        case EVENT_SYSTEM_DRAGDROPSTART:  lstrcpy(szBuf, "DRAGDROPSTART"); goto OBJECTMODE;
        case EVENT_SYSTEM_DRAGDROPEND:    lstrcpy(szBuf, "DRAGDROPEND:"); goto OBJECTMODE;
        case EVENT_SYSTEM_DIALOGSTART:    lstrcpy(szBuf, "DIALOGSTART"); goto OBJECTMODE;
        case EVENT_SYSTEM_DIALOGEND:      lstrcpy(szBuf, "DIALOGEND"); goto OBJECTMODE;
        case EVENT_SYSTEM_SCROLLINGSTART: lstrcpy(szBuf, "SCROLLINGSTART"); goto OBJECTMODE;
        case EVENT_SYSTEM_SCROLLINGEND:   lstrcpy(szBuf, "SCROLLINGEND"); goto OBJECTMODE;
        case EVENT_SYSTEM_SWITCHSTART:    lstrcpy(szBuf, "SWITCHSTART"); goto OBJECTMODE;
        case EVENT_SYSTEM_SWITCHEND:      lstrcpy(szBuf, "SWITCHEND"); goto OBJECTMODE;
        case EVENT_SYSTEM_MINIMIZESTART:  lstrcpy(szBuf, "MINIMIZESTART"); goto OBJECTMODE;
        case EVENT_SYSTEM_MINIMIZEEND:    lstrcpy(szBuf, "MINIMIZEEND"); goto OBJECTMODE;
        OBJECTMODE:
            if (grfTrack & SEF_MODE_TRACK)
            {
                cchReturn = GetObjectModeString(hwnd, idContainer, idObject, event, lpszBuf, cchBuf);
                if (FAILED(GetLastError())) cchReturn = BASICSTR(szBuf);
            }
            break;



        case FAKE_EVENT_SYSTEM_DEFACTION:
            cchReturn = DoObjectDefAction(lpszBuf, cchBuf);
            if (FAILED(GetLastError())) cchReturn = BASICSTR("SYSTEM_DEFACTIO");
            break;

        case FAKE_EVENT_SYSTEM_FOCUS:
            cchReturn = DoObjectFocus(lpszBuf, cchBuf);
            if (FAILED(GetLastError())) cchReturn = BASICSTR("SYSTEM_FOCUS");
            break;

        case FAKE_EVENT_SYSTEM_SELECTION: lstrcpy(szBuf, "SYSTEM_SELECTION"); goto DOSELECT;
        case FAKE_EVENT_SYSTEM_SELECTIONADD: lstrcpy(szBuf, "SYSTEM_SELECTIONADD"); goto DOSELECT;
        case FAKE_EVENT_SYSTEM_SELECTIONREMOVE: lstrcpy(szBuf, "SYSTEM_SELECTIONREMOVE"); goto DOSELECT;
        DOSELECT:
            cchReturn = DoObjectSelection(event, lpszBuf, cchBuf);
            if (FAILED(GetLastError())) cchReturn = BASICSTR(szBuf);
            break;

        case FAKE_EVENT_SYSTEM_UNDERTHECURSOR:
            cchReturn = DoObjectHitTest(lpszBuf, cchBuf);
            if (FAILED(GetLastError())) cchReturn = BASICSTR("SYSTEM_UNDERTHECURSOR");
            break;

		default:
			cchReturn = wsprintf (lpszBuf,"Unknown Event number %lX",event);
    }

    return(cchReturn);
}


// --------------------------------------------------------------------------
//
//  GetObject()
//
//  Returns a pointer to the object.
//
// --------------------------------------------------------------------------
IAccessible* GetObject(HWND hwnd, LONG idContainer, LONG idChild, VARIANT* pvarChild)
{
    IAccessible * pacc;
    HRESULT hr;

    //
    // Do filtering for the object type
    //
    switch (idContainer)
    {
        case OBJID_CURSOR:
            if (!(grfTrack & SEF_CURSOR_OBJECTS))
                return(NULL);
            break;

        case OBJID_CARET:
            if (!(grfTrack & SEF_CARET_OBJECTS))
                return(NULL);
            break;

        case OBJID_SOUND:
            if (!(grfTrack & SEF_SOUND_OBJECTS))
                return(NULL);
            break;

        case OBJID_ALERT:
            if (!(grfTrack & SEF_ALERT_OBJECTS))
                return(NULL);
            break;

        default:
            if (!(grfTrack & SEF_WINDOW_OBJECTS))
                return(NULL);
            break;
    }

    pacc = NULL;
    VariantInit(pvarChild);

// pkw
// In retail, we are not processing events belonging to an invisible
// window. This by-passes some crash bugs we hae with Access 2.0 and 
// Bookshelf 96. 
#ifndef _DEBUG
    if (!idContainer && !IsWindowVisible(hwnd)) return NULL;
#endif

    hr= AccessibleObjectFromEvent(hwnd, idContainer, idChild,
        &pacc, pvarChild);
    SetLastError(hr);
    return(pacc);
}



// --------------------------------------------------------------------------
//
//  GetObjectAtCursor()
//
//  Sees if there is a titlebar at the given screen point.
//
// --------------------------------------------------------------------------
IAccessible * GetObjectAtCursor(VARIANT * pvarChild)
{
    POINT   pt;
    IAccessible * pacc;
    HRESULT hr;

    //
    // Get cursor object & position
    //
    GetCursorPos(&pt);

    //
    // Get object here.
    //
    VariantInit(pvarChild);
    hr = AccessibleObjectFromPoint(pt, &pacc, pvarChild);
    if (SUCCEEDED(hr) && pacc)
        return(pacc);
    else
        return(NULL);
}



// --------------------------------------------------------------------------
//
//  GetObjectCreateString()
//
//  BOGUS!  Get parent name/role string the right way.
//
// --------------------------------------------------------------------------
UINT GetObjectCreateString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    UINT    cchString;
    TCHAR   szName[CCH_NAME_MAX];
    TCHAR   szRole[CCH_ROLE_MAX];
    TCHAR   szParent[CCH_PARENT_MAX];

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "Object %s %s created in the %s.", szName, szRole,
        szParent);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object create string");
    return(cchString);
}



// --------------------------------------------------------------------------
//
//  GetObjectDestroyString()
//
// --------------------------------------------------------------------------
UINT GetObjectDestroyString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
	{
        return(0);
	}

	// When an app is shutting down,  EVENT_OBJECT_DESTROY events are 
	// sent.Calling  IAccessible properties  at this point can crash. 
	// In particular, when the call references a dll that is unloaded 
	// first. Calling get_accName is a good example. It eventually 
	// calls SysAllocString exported by oleaut32.dll. If oleaut32.dll 
	// is unloaded first, it crashes. 
	// The fix is to, upon EVENT_OBJECT_DESTROY,  call these 
	// properties only for visible windows. We believe that  
	// only invisible windows are dangerous since some of them are 
	// destroyed  late in the game.
	// If you did want to get the name of the invisible window, 
      // try GetWindowText.
	{
		VARIANT varState, varRole;
		HRESULT hr;
		VariantInit(&varState);
		VariantInit(&varRole);
		hr = pacc->get_accState(varChild, &varState);
		if (FAILED(hr)) {DBOUTPUT("get_accState failed\r\n"); goto BAILOUT;}
            hr = pacc->get_accRole(varChild, &varRole);
		if (FAILED(hr)) {DBOUTPUT("get_accRole failed\r\n"); goto BAILOUT;}
		if ((varState.vt == VT_I4) && (varState.lVal & STATE_SYSTEM_INVISIBLE)
		  &&(varRole.vt == VT_I4) && (varRole.lVal == ROLE_SYSTEM_WINDOW))
		{
		BAILOUT:
			return wsprintf(lpszBuf, "Destroying invisible window 0x%lx idContainer 0x%lx idObject 0x%lx", 
				hwnd, idContainer, idObject);
		}
		VariantClear(&varState);
		VariantClear(&varRole);
	}

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "Object %s %s destroyed in the %s.",
        szName, szRole, szParent);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object destroy string");
    return(cchString);

}


// --------------------------------------------------------------------------
//
//  GetObjectMoveString()
//
// --------------------------------------------------------------------------
UINT GetObjectMoveString(HWND hwnd, LONG idContainer, LONG idObject, LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    TCHAR szLocation[64];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (! pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)) ||
        !GetObjectLocation(pacc, &varChild, szLocation, ARRAYSIZE(szLocation)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The %s %s in the %s is now at %s.", szName, szRole,
        szParent, szLocation);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object move string");
    return(cchString);
}



// --------------------------------------------------------------------------
//
//  GetObjectStateString()
//
// --------------------------------------------------------------------------
UINT GetObjectStateString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    TCHAR szState[CCH_STATE_MAX];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (! pacc)
        return(0);
return 0;

    cchString = 0;

    //
    // Get the name, role, parent role, and state strings.
    //
    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName))     ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole))     ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)) ||
        !GetObjectState(pacc, &varChild, szState, ARRAYSIZE(szState)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The %s %s in the %s changed state to %s.",
        szName, szRole, szParent, szState);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object state string");
    return(cchString);
}


// --------------------------------------------------------------------------
//
//  GetObjectFocusString()
//
// --------------------------------------------------------------------------
UINT GetObjectFocusString(HWND hwnd, LONG idContainer, LONG idObject, LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    UINT cchString;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (! pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName))     ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole))     ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The %s %s in the %s has the focus.", szName, szRole,
        szParent);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object focus string");
    return(cchString);
}


// --------------------------------------------------------------------------
//
//  GetObjectSelectedItemString()
//
// --------------------------------------------------------------------------
UINT GetObjectSelectedItemString(HWND hwnd, LONG idContainer, LONG idObject, DWORD event, LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    UINT cchString;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (! pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)))
        goto Done;

    if ((event == EVENT_OBJECT_SELECTION) || (event == EVENT_SYSTEM_FOREGROUND))
    {
        cchString = wsprintf(lpszBuf, "The %s %s is the current selection in the %s.",
            szName, szRole, szParent);
    }
    else if (event == EVENT_OBJECT_SELECTIONADD)
    {
        cchString = wsprintf(lpszBuf, "The %s %s was selected in the %s.",
            szName, szRole, szParent);
    }
    else if (event == EVENT_OBJECT_SELECTIONREMOVE)
    {
        cchString = wsprintf(lpszBuf, "The %s %s was deselected in the %s.",
            szName, szRole, szParent);
    }

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object selected item string");
    return(cchString);
}



// --------------------------------------------------------------------------
//
//  GetObjectSelectionString()
//
//  Gets a list of the selected items
//
// --------------------------------------------------------------------------
UINT GetObjectSelectionString(HWND hwnd, LONG idContainer, LONG idObject, LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    VARIANT varRet;
    TCHAR   szName[CCH_NAME_MAX];
    TCHAR   szRole[CCH_ROLE_MAX];
    TCHAR   szNameChild[CCH_NAME_MAX];
    HRESULT hr;
    IEnumVARIANT* penum;
    UINT    cchString;
    UINT    cchT;
    ULONG   celt;
    UINT    cchBufRemaining;

    if (hwnd)
        pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    else
        pacc = GetObjectAtCursor(&varChild);

    if (!pacc)
        return(0);

    cchString = 0;
    cchBufRemaining = cchBuf;

    //
    // Get the name and role of the container that selection is changing
    // within.
    //
    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName))  ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)))
        goto Done;

    //
    // Get the current selection
    //
    VariantInit(&varChild);
    hr = pacc->get_accSelection(&varChild);
    if (!SUCCEEDED(hr) || (varChild.vt == VT_EMPTY))
    {
        goto Done;
    }

    //
    // If there is one child (VT_I4 or VT_DISPATCH), get the child info and
    // we are done.  If there are more (VT_UNKNOWN), try to enumerate.
    //

    VariantInit(&varRet);
    if (varChild.vt == VT_I4)
    {
        //
        // If VT_I4, then mention this item, and we are done
        //
        if (varChild.lVal)
        {
            varRet.pdispVal = NULL;
            hr = pacc->get_accChild(varChild, &varRet.pdispVal);
            if (SUCCEEDED(hr) && varRet.pdispVal)
            {
                varChild.vt = VT_DISPATCH;
                varChild.pdispVal = varRet.pdispVal;
                goto WeHaveOneObjectChild;
            }
        }

        GetObjectName(pacc, &varChild, szNameChild, ARRAYSIZE(szNameChild));
        cchString = wsprintf(lpszBuf, "The selection in the %s %s is %s.",
            szName, szRole, szNameChild);

        goto Done;
    }
    else if (varChild.vt == VT_DISPATCH)
    {
WeHaveOneObjectChild:
        //
        // Ask the child directly what its name is.
        //
        pacc->Release();
        pacc = NULL;

        hr = varChild.pdispVal->QueryInterface(IID_IAccessible, (void**)&pacc);
        varChild.pdispVal->Release();

        if (SUCCEEDED(hr) && pacc)
        {
            VariantInit(&varChild);
            GetObjectName(pacc, &varChild, szNameChild, ARRAYSIZE(szNameChild));
            cchString = wsprintf(lpszBuf, "The selection in the %s %s is %s.",
                szName, szRole, szNameChild);
        }

        goto Done;
    }
    else if (varChild.vt != VT_UNKNOWN)
    {
        VariantClear(&varChild);
        goto Done;
    }

    //
    // We have an IEnumVARIANT.  Loop through the items getting their names.
    //
    penum = NULL;
    hr = varChild.punkVal->QueryInterface(IID_IEnumVARIANT, (void**)&penum);
    varChild.punkVal->Release();

    if (!SUCCEEDED(hr))
        goto Done;

    //
    // Sit in a loop
    //
    cchT = wsprintf(lpszBuf, "The selection in the %s %s is: ", szName, szRole);
    cchString += cchT;
    lpszBuf += cchT;
    cchBufRemaining -= cchT;

    penum->Reset();

    while (TRUE)
    {
        VariantInit(&varChild);
        celt = 0;

        // Get the next element
        hr = penum->Next(1, &varChild, &celt);
        if (!SUCCEEDED(hr))
        {
            cchString = 0;
            goto EnumDone;
        }

        // Are we at end?
        if (!celt)
            break;

        // Get this child's name.
        if (varChild.vt == VT_DISPATCH)
        {
            IAccessible * paccChild;

            paccChild = NULL;
            hr = varChild.pdispVal->QueryInterface(IID_IAccessible,
                (void**)&paccChild);
            varChild.pdispVal->Release();

            if (!SUCCEEDED(hr))
            {
                cchString = 0;
                break;
            }

            VariantInit(&varChild);
            cchT = GetObjectName(paccChild, &varChild, lpszBuf, cchBufRemaining);
            paccChild->Release();
        }
        else if (varChild.vt == VT_I4)
        {
            cchT = GetObjectName(pacc, &varChild, lpszBuf, cchBufRemaining);
        }
        else
        {
            VariantClear(&varChild);
            cchString = 0;
            break;
        }

        // need to make sure we don't exceed the length of the buffer we
        // were given!!!
        if (cchBufRemaining < (cchT + 2))
        {
            *(lpszBuf) = 0;                 // This ensures NULL termination...
            break;
        }
        
        // now add a separator
        lpszBuf += cchT;
        *(lpszBuf++) = ';';
        *(lpszBuf++) = ' ';
        *(lpszBuf) = 0;                 // This ensures NULL termination...
        cchString += cchT + 2;
        cchBufRemaining -= (cchT + 2);
    }

EnumDone:
    penum->Release();

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object selection string");
    return(cchString);
}



// --------------------------------------------------------------------------
//
//  GetObjectAcceleratorString()
//
// --------------------------------------------------------------------------
UINT GetObjectAcceleratorString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    TCHAR szShortcut[CCH_SHORTCUT_MAX];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)) ||
        !GetObjectShortcut(pacc, &varChild, szShortcut, ARRAYSIZE(szShortcut)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The %s %s in the %s changed its shortcut to %s.",
        szName, szRole, szParent, szShortcut);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object accelerator string");
    return(cchString);

    return(0);
}



// --------------------------------------------------------------------------
//
//  GetObjectDefActionString()
//
// --------------------------------------------------------------------------
UINT GetObjectDefActionString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    TCHAR szDefAction[CCH_DEFACTION_MAX];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)) ||
        !GetObjectDefAction(pacc, &varChild, szDefAction, ARRAYSIZE(szDefAction)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The %s %s in the %s changed its default action to %s.",
        szName, szRole, szParent, szDefAction);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object default action string");
    return(cchString);

    return(0);
}



// --------------------------------------------------------------------------
//
//  GetObjectHelpString()
//
// --------------------------------------------------------------------------
UINT GetObjectHelpString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    TCHAR szHelp[CCH_HELP_MAX];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)) ||
        !GetObjectHelp(pacc, &varChild, szHelp, ARRAYSIZE(szHelp)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The %s %s in the %s changed its help to %s.",
        szName, szRole, szParent, szHelp);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object help string");
    return(cchString);

    return(0);
}



// --------------------------------------------------------------------------
//
//  GetObjectParentString()
//
// --------------------------------------------------------------------------
UINT GetObjectParentString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The %s %s changed parent to the %s.",
        szName, szRole, szParent);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object parent string");
    return(cchString);
}



// --------------------------------------------------------------------------
//
//  GetObjectValueString()
//
// --------------------------------------------------------------------------
UINT GetObjectValueString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    TCHAR szValue[CCH_VALUE_MAX];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)))
    {
        goto Done;
    }

    if (!GetObjectValue(pacc, &varChild, szValue, ARRAYSIZE(szValue)))
        lstrcpy(szValue, "empty");

    cchString = wsprintf(lpszBuf, "The %s %s in the %s changed value to %s.",
        szName, szRole, szParent, szValue);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object value string");
    return(cchString);

}



// --------------------------------------------------------------------------
//
//  GetObjectDescriptionString()
//
// --------------------------------------------------------------------------
UINT GetObjectDescriptionString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible* pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    TCHAR szDescription[CCH_DESCRIPTION_MAX];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)) ||
        !GetObjectDescription(pacc, &varChild, szDescription, ARRAYSIZE(szDescription)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The %s %s in the %s changed description to %s.",
        szName, szRole, szParent, szDescription);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object description string");
    return(cchString);
}



// --------------------------------------------------------------------------
//
//  GetObjectReorderString()
//
// --------------------------------------------------------------------------
UINT GetObjectReorderString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The objects within the %s %s rearranged.",
        szName, szRole);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object reorder string");
    return(cchString);
}



// --------------------------------------------------------------------------
//
//  GetObjectNameString()
//
// --------------------------------------------------------------------------
UINT GetObjectNameString(HWND hwnd, LONG idContainer, LONG idObject,
    LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The %s %s in the %s has a new name.",
        szName, szRole, szParent);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object name string");
    return(cchString);
}



// --------------------------------------------------------------------------
//
//  GetObjectModeString()
//
// --------------------------------------------------------------------------
UINT GetObjectModeString(HWND hwnd, LONG idContainer, LONG idObject,
    DWORD event, LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    TCHAR szName[CCH_NAME_MAX];
    TCHAR szRole[CCH_ROLE_MAX];
    TCHAR szParent[CCH_PARENT_MAX];
    TCHAR szModeType[32];
    BOOL  fEnter = FALSE;
    UINT cchString;

    pacc = GetObject(hwnd, idContainer, idObject, &varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)))
    {
        goto Done;
    }

    switch (event)
    {
        case EVENT_SYSTEM_MENUSTART:
        case EVENT_SYSTEM_MENUEND:
            fEnter = (event == EVENT_SYSTEM_MENUSTART);
            lstrcpy(szModeType, "menu");
            break;

        case EVENT_SYSTEM_MENUPOPUPSTART:
        case EVENT_SYSTEM_MENUPOPUPEND:
            fEnter = (event == EVENT_SYSTEM_MENUPOPUPSTART);
            lstrcpy(szModeType, "popup");
            break;

        case EVENT_SYSTEM_CAPTURESTART:
        case EVENT_SYSTEM_CAPTUREEND:
            fEnter = (event == EVENT_SYSTEM_CAPTURESTART);
            lstrcpy(szModeType, "capture");
            break;

        case EVENT_SYSTEM_MOVESIZESTART:
        case EVENT_SYSTEM_MOVESIZEEND:
            fEnter = (event == EVENT_SYSTEM_MOVESIZESTART);
            lstrcpy(szModeType, "move size");
            break;

        case EVENT_SYSTEM_CONTEXTHELPSTART:
        case EVENT_SYSTEM_CONTEXTHELPEND:
            fEnter = (event == EVENT_SYSTEM_CONTEXTHELPSTART);
            lstrcpy(szModeType, "context help");
            break;

        case EVENT_SYSTEM_DRAGDROPSTART:
        case EVENT_SYSTEM_DRAGDROPEND:
            fEnter = (event == EVENT_SYSTEM_DRAGDROPSTART);
            lstrcpy(szModeType, "drag drop");
            break;

        case EVENT_SYSTEM_DIALOGSTART:
        case EVENT_SYSTEM_DIALOGEND:
            fEnter = (event == EVENT_SYSTEM_DIALOGSTART);
            lstrcpy(szModeType, "dialog");
            break;

        case EVENT_SYSTEM_SCROLLINGSTART:
        case EVENT_SYSTEM_SCROLLINGEND:
            fEnter = (event == EVENT_SYSTEM_SCROLLINGSTART);
            lstrcpy(szModeType, "scrolling");
            break;

        case EVENT_SYSTEM_SWITCHSTART:
        case EVENT_SYSTEM_SWITCHEND:
            fEnter = (event == EVENT_SYSTEM_SWITCHSTART);
            lstrcpy(szModeType, "task switching");
            break;

        case EVENT_SYSTEM_MINIMIZESTART:
        case EVENT_SYSTEM_MINIMIZEEND:
            fEnter = (event == EVENT_SYSTEM_MINIMIZESTART);
            lstrcpy(szModeType, "minimize");
            break;

        default:
            // SHOULD NEVER GET HERE!
            DebugBreak();
    }

    cchString = wsprintf(lpszBuf, "%s %s mode for the %s %s in the %s.",
        (fEnter ? "Entering" : "Leaving"), szModeType, szName, szRole,
        szParent);

Done:
    pacc->Release();
	if (cchString == 0)
		cchString = wsprintf(lpszBuf,"----- ERROR getting object mode string");
    return(cchString);

    return(0);
}



// --------------------------------------------------------------------------
//  
//  DoObjectDefAction()
//
// --------------------------------------------------------------------------
UINT DoObjectDefAction(LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    HRESULT hr;
    TCHAR   szName[CCH_NAME_MAX];
    TCHAR   szRole[CCH_ROLE_MAX];
    TCHAR   szDefAction[64];
    UINT    cchString;

    pacc = GetObjectAtCursor(&varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    //
    // Does this object have a default action?
    //
    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName)) ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole)) ||
        !GetObjectDefAction(pacc, &varChild, szDefAction, ARRAYSIZE(szDefAction)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The default action of the %s %s is %s.",
        szName, szRole, szDefAction);

    //
    // Do it.
    //
    hr = pacc->accDoDefaultAction(varChild);
    if (!SUCCEEDED(hr))
        MessageBeep(0);

Done:
    pacc->Release();
    return(cchString);
}




// --------------------------------------------------------------------------
//
//  DoObjectFocus()
//
//  Changes the item with the focus to the one the cursor is over.
//
// --------------------------------------------------------------------------
UINT DoObjectFocus(LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;

    pacc = GetObjectAtCursor(&varChild);
    if (!pacc)
        return(0);

    pacc->accSelect(SELFLAG_TAKEFOCUS, varChild);

    pacc->Release();
    return(0);
}



// --------------------------------------------------------------------------
//
//  DoObjectSelection()
//
//  Changes the item with the selection to the one the cursor is over, or
//  adds/removes it from the selection.
//
// --------------------------------------------------------------------------
UINT DoObjectSelection(DWORD event, LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible * pacc;
    VARIANT varChild;
    long    selFlags;

    pacc = GetObjectAtCursor(&varChild);
    if (!pacc)
        return(0);

    selFlags = 0;
    if (event == FAKE_EVENT_SYSTEM_SELECTION)
        selFlags = SELFLAG_TAKESELECTION;
    else if (event == FAKE_EVENT_SYSTEM_SELECTIONADD)
        selFlags = SELFLAG_ADDSELECTION;
    else if (event == FAKE_EVENT_SYSTEM_SELECTIONREMOVE)
        selFlags = SELFLAG_REMOVESELECTION;

    pacc->accSelect(selFlags, varChild);

    pacc->Release();
    return(0);
}



// --------------------------------------------------------------------------
//
//  DoObjectHitTest()
//
//  This tests in-process AccessibleObjectFromPoint()
//
// --------------------------------------------------------------------------
UINT DoObjectHitTest(LPTSTR lpszBuf, UINT cchBuf)
{
    IAccessible* pacc;
    VARIANT      varChild;
    TCHAR       szName[CCH_NAME_MAX];
    TCHAR       szRole[CCH_ROLE_MAX];
    TCHAR       szParent[CCH_PARENT_MAX];
    UINT        cchString;

    pacc = GetObjectAtCursor(&varChild);
    if (!pacc)
        return(0);

    cchString = 0;

    if (!GetObjectName(pacc, &varChild, szName, ARRAYSIZE(szName))  ||
        !GetObjectRole(pacc, &varChild, szRole, ARRAYSIZE(szRole))  ||
        !GetObjectParent(pacc, &varChild, szParent, ARRAYSIZE(szParent)))
    {
        goto Done;
    }

    cchString = wsprintf(lpszBuf, "The cursor is over the %s %s in the %s.",
        szName, szRole, szParent);

Done:
    pacc->Release();
    return(cchString);
}


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