Referring to One Dispatch Interface from Another

You will now implement the Position property you added at the end of Step 2. This property exposes the document’s m_pt member variable by using the second dispatch interface implemented by CAutoClickPoint. You will expose this new property by adding code to the Get and Set member functions (GetPosition and SetPosition) which you declared in Step 2. The return type of GetPosition and the type of the parameter passed to SetPosition is LPDISPATCH, a pointer to a dispatch object.

The following two Autodriv message handlers, OnGetPosition and OnSetPosition, found in the CAutoDrivDlg class, access the Position property of AutoClik’s document dispatch interface using the GetPosition property:

void CAutoDrivDlg::OnGetPosition()
{
   CClikPoint point;
   point.AttachDispatch(m_autoClikObject.GetPosition());

   m_x = point.GetX();
   m_y = point.GetY();
   UpdateData(FALSE);
}

void CAutoDrivDlg::OnSetPosition()
{
   CClikPoint point;
   point.AttachDispatch(m_autoClikObject.GetPosition());

   UpdateData(TRUE);
   point.SetX((short)m_x);
   point.SetY((short)m_y);
   m_autoClikObject.SetPosition(point.m_lpDispatch);
}

The code:

   CClikPoint point;
   point.AttachDispatch(m_autoClikObject.GetPosition());

accesses AutoClik’s Position property, which is declared as LPDISPATCH in the MFC Automation server’s dispatch map. The Automation client gets initial access to AutoClik’s document dispatch interface object by creating it (in the OnCreate method):

   if (!m_autoClikObject.CreateDispatch(_T("AutoClick.Document")))
   {
      AfxMessageBox(IDP_CANNOT_CREATE_AUTOCLICK);
      return -1;   // fail
   }
   m_autoClikObject.ShowWindow();

To declare one dispatch interface object as a property of another dispatch interface

  1. From the View menu, click ClassWizard.

  2. Click the Automation tab.

  3. In the Class name box, select CAutoClickDoc.

  4. In the External names box, select Position.

    This is the property you added in Step 2.

  5. Click Edit Code to implement the Get and Set member functions.

    This takes you to their stub implementations in AutoClickDoc.cpp.

  6. Implement the Get and Set member functions as shown by the following code:

    LPDISPATCH CAutoClickDoc::GetPosition()
    {
    CAutoClickPoint* pPos = new CAutoClickPoint;
    pPos->m_x = (short) m_pt.x;
    pPos->m_y = (short) m_pt.y;
    
    LPDISPATCH lpResult = pPos->GetIDispatch(FALSE);
    return lpResult;
    }
    
    void CAutoClickDoc::SetPosition(LPDISPATCH newValue)
    {
    CAutoClickPoint* pPos =
    (CAutoClickPoint*)CCmdTarget::FromIDispatch(newValue);
    if (pPos != NULL && pPos->IsKindOf
    (RUNTIME_CLASS(CAutoClickPoint)))
    {
    m_pt.x = pPos->m_x;
    m_pt.y = pPos->m_y;
    Refresh();
    }
    }
    
  7. Add the following #include statement at the top of AutoClickDoc.cpp:

    #include "AutoClickPoint.h"
    

    This is required because the implementation of SetPosition refers to the CAutoClickPoint class.

  8. In ClassView, double-click CAutoClickPoint to display AutoClickPoint.h in the text editor.

  9. Change the declaration of CAutoClickPoint’s OLE dispatch map from protected to public, by adding the public keyword just before the comment line:

    public:
    // Generated OLE dispatch map functions
    //{{AFX_DISPATCH(CAutoClickPoint)
    short m_x;
    short m_y;
    //}}AFX_DISPATCH
    DECLARE_DISPATCH_MAP()
    

    This is required because CAutoClickDoc directly accesses CAutoClickPoint’s member variables m_x and m_y in its implementation of GetPosition and SetPosition.

The implementation of GetPosition creates a new CAutoClickPoint object. The CAutoClickPoint object, which is an Automation-enabled CCmdTarget object, in turn creates a dispatch interface object, through the help of the framework.

Finally, GetPosition gets the OLE IDispatch pointer by calling the CCmdTarget::GetIDispatch member function of the CAutoClickPoint object and returns this IDispatch pointer to the Automation client. The AddRef parameter of GetIDispatch is FALSE, because the OLE reference count of this dispatch interface object was already set to 1 when the CAutoClickPoint object was constructed.

The implementation of SetPosition does a C++ down-casting of the IDispatch pointer to a CAutoClickPoint pointer. It tests the down-casting with IsKindOf to make sure the Automation client passed back an IDispatch pointer to a CAutoClickPoint object rather than an IDispatch pointer to some other kind of object.

Finally, SetPosition updates the view to reflect the new position of the text by calling the document’s Refresh function. Because Refresh is called by SetPosition, it is not necessary to implement the OnXChanged and OnYChanged member functions to update the views for the CAutoClickPoint class.