Server Annotation Sample

The following is an example of server annotation. Follow instructions in comments marked with /* TODO */.

// 
//  Skeleton code for class which implements IAccPropServer 
// 

class CMyAccPropServer: public IAccPropServer
{
    ULONG               m_Ref;
    IAccPropServices *  m_pAccPropSvc;

public:

    AccServerBase( IAccPropServices * pAccPropSvc )
        : m_Ref( 1 ),
          m_pAccPropSvc( pAccPropSvc )
    {
        m_pAccPropSvc->AddRef();
    }

    ~AccServerBase()
    {
        m_pAccPropSvc->Release();
    }

    
    /* TODO: Addref/Release/QI go here...
     */

    HRESULT STDMETHODCALLTYPE GetPropValue (const BYTE * pIDString,
        DWORD dwIDStringLen, MSAAPROPID idProp, VARIANT * pvarValue,
        BOOL * pfGotProp )
    {
        // Clear out parameters, in case we return early... 
        pvarValue->vt = VT_EMPTY;
        *pfGotProp = FALSE;
        
        /*  TODO: if you need to access internal data structures, you should
         *  verify that they still exist here. If they no longer exist,
         *  return CO_E_OBJNOTCONNECTED.
         */

        // Figure out which child this request is for... 
        HWND  hwnd;
        DWORD idObject;
        DWORD idChild;

        if( S_OK != m_pAccPropSvc->DecomposeHwndIdentityString( pIDString, 
                  dwIDStringLen, & hwnd, & idObject, & idChild ) )
        {
            // problem decomposing identity string - return early... 
            return S_OK;
        }

        
        /*  TODO: You need to determine which child ids you 
         *  want to handle properties for. Change this 
         *  if or extend it into an if/else/if
         *  to handle each id you need.
         *
         *  To handle all the children of an object, but not 
         *  the parent object itself, 
         *  use "if (idChild != CHILDID_SELF )" as the 
         *  condition.
         */

        if( idChild == CHILDID_SELF )
        {
            
            /*  TODO: change or extend this if(...) for each 
             *  property you are overriding.
             *
             *  The constants for the properties are (from 
             *  oleacc.h):
             *    
             *    PROPID_ACC_NAME
             *    PROPID_ACC_VALUE
             *    PROPID_ACC_DESCRIPTION
             *    PROPID_ACC_ROLE
             *    PROPID_ACC_STATE
             *    PROPID_ACC_HELP
             *    PROPID_ACC_KEYBOARDSHORTCUT
             *    PROPID_ACC_DEFAULTACTION
             *
             *    PROPID_ACC_FOCUS
             *    PROPID_ACC_SELECTION
             *    PROPID_ACC_PARENT
             *
             *    PROPID_ACC_NAV_UP
             *    PROPID_ACC_NAV_DOWN
             *    PROPID_ACC_NAV_LEFT
             *    PROPID_ACC_NAV_RIGHT
             *    PROPID_ACC_NAV_PREV
             *    PROPID_ACC_NAV_NEXT
             *    PROPID_ACC_NAV_FIRSTCHILD
             *    PROPID_ACC_NAV_LASTCHILD
             *
             */
            if( idProp == PROPID_ACC_ROLE )
            {
                
                /*  TODO: lookup or otherwise determine the 
                 *  value you want to return for this 
                 *  property of this child.
                 *
                 *  Note that idChild is a 1-based index of 
                 *  a child element, so you'll need to 
                 *  subtract 1 if you use 0-based indices.
                 *
                 *  If you have a value to return, set 
                 *  pvarValue to that value,
                 *  and set *pfGotProp to TRUE.
                 *
                 *  If you have no value to return, do 
                 *  nothing. (*pfGotProp
                 *  will be FALSE from above.)
                 */

                // For example, pretend that everything is a menu item:
                pvarValue.vt = VT_I4;
                pvarValue.lVal = ROLE_SYSTEM_MENUITEM;

                *pfGotProp = TRUE;
            }
        }

        return S_OK;
    }
};


[ ... ]

// 
//  Skeleton code to register class which implements IAccPropServer
// 
//  Do this after the corresponding HWND is created. 
// 
//  Perf tip: instead of doing this immediately after the HWND is created, 
//  you can delay it until that HWND receives its first WM_GETOBJECT message. 
//  This delays the CoCreate until necessary. You will need to subclass the 
//  HWND to catch the WM_GETOBJECT. After registering, pass the WM_GETOBJECT 
//  on to the original window proc for the HWND. 
// 


    IAccPropServices * pAccPropSvc = NULL;
    HRESULT hr;
    hr = CoCreateInstance( CLSID_AccPropServices, NULL,
            CLSCTX_SERVER, IID_IAccPropServices, (void **) & pAccPropSvc ));
    if( hr == S_OK && pAccPropSvc )
    {
        CMyAccPropServer* pMyPropSrv = new CMyAccPropServer( pAccPropSvc );
        if( pMyPropSrv )
        {
            
            /*  TODO: extend this array if you are 
             *  overriding multiple properties.
             *  Make sure to update the length parameter 
             *  passed to SetHwndPropServer
             *  so that it matches the number of elements in 
             *  this array.
             */
            MSAAPROPID propids[ 1 ];
            propids[ 0 ] = PROPID_ACC_ROLE;

            
            /*  TODO: Specify the appropriate objid and 
             *  childid here. The idObject will
             *  nearly always be OBJID_CLIENT. Use a childid 
             *  of CHILD_CLIENT to refer to
             *  a container or an overall object, or use a 
             *  1-based index to refer to a
             *  specific child item in that container.
             * 
             *  To override properties of all elements in a 
             *  container, use CHILDID_SELF,
             *  and specify the ANNO_CONTAINER in the last 
             *  parameter.
             */
            pAccPropSvc->SetHwndPropServer( hwnd, OBJID_CLIENT,
                    CHILDID_SELF, & propid, 1, pMyPropSrv, 0 );
            pMyPropSrv->Release();
            pAccPropSvc->Release();
        }
    }