The ATL Sample's Program File

When creating a DTC in Visual C++, you need to make changes to the control's implementation file such as SinkDTC.cpp. The following code shows the differences between the generic header file provided by the wizard and the additions made to create the ATLSample control. Additions appear in boldface below. Deletions appear as strikethrough text.

Tip   If you paste code from help topics into your project file, be sure to copy the line above and below the entire code sample as well. Otherwise the text you paste loses the formatting it had while in the help topic. You can also copy code from the ATLSample project.

// SinkDTC.cpp : Implementation of CSinkDTCImplement the two DTC interfaces
#include "stdafx.h"
#include <designer.h>
#include <dtc60.h>
#include "ATLSample.h"
#include "SinkDTC.h"
///////////
// CSinkDTC
CSinkDTC::CSinkDTC()
{
   m_sizeExtent.cx = 4000;         // 100'ths of millimeters
   m_sizeExtent.cy = 1500;         // 100'ths of millimeters
   m_sizeNatural = m_sizeExtent;
}

HRESULT 
CSinkDTC::OnDraw(ATL_DRAWINFO& di)
{
   RECT& rc = *(RECT*)di.prcBounds;
   COLORREF   clr;
   char      achBuf[256];
   LOGFONT      lf;
   HFONT      hfont;
   HFONT      hfontOld;

   clr = ::SetBkColor(di.hdcDraw, RGB(0xC0, 0xC0, 0xC0));   // make it look gray.

   lf.lfHeight = 14;
   lf.lfWidth = 0;
   lf.lfEscapement = 0;
   lf.lfOrientation = 0;
   lf.lfWeight = FW_NORMAL;
   lf.lfItalic = FALSE;
   lf.lfUnderline = FALSE;
   lf.lfStrikeOut = FALSE;
   lf.lfCharSet = ANSI_CHARSET;
   lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
   lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
   lf.lfQuality = DEFAULT_QUALITY;
   lf.lfPitchAndFamily = FF_DONTCARE;
   strcpy(lf.lfFaceName, "MS Sans Serif");
   hfont = ::CreateFontIndirect(&lf);
   hfontOld = static_cast<HFONT>(::SelectObject(di.hdcDraw, hfont));

   ::SetTextAlign(di.hdcDraw, TA_BASELINE);
   achBuf[0] = '\0';
   ::WideCharToMultiByte(CP_ACP, 0, m_sSelectedFruit, -1, achBuf, sizeof (achBuf), 0, 0);
   achBuf[255] = '\0';
   ::ExtTextOut(di.hdcDraw,
      rc.left + (rc.right - rc.left) / 10, 
      (rc.top + rc.bottom) / 2, 
      ETO_OPAQUE,
      &rc,
      achBuf, 
      lstrlen(achBuf),
      NULL);
   ::SetTextAlign(di.hdcDraw, TA_TOP);
   ::ExtTextOut(di.hdcDraw, rc.left + 5, rc.top + 20, 0, &rc, "MyLabelText", 3, NULL);

   ::SetBkColor(di.hdcDraw, clr);
   ::SelectObject(di.hdcDraw, hfontOld);
   ::DeleteObject(hfont);
   return S_OK;
}

// IDesignTimeControl interface

STDMETHODIMP CSinkDTC::get_DesignTimeControlSite(IDesignTimeControlSite ** ppSite)
{
   (*ppSite) = m_spSite.p;
   (*ppSite)->AddRef();

   return S_OK;
}

STDMETHODIMP CSinkDTC::putref_DesignTimeControlSite(IDesignTimeControlSite * pSite)
{
   HRESULT      hr = S_OK;

   m_spSite = pSite;
   if (pSite != NULL)
   {
      CComPtr<ChoiceSinks>   spChoiceSinks;
      CComVariant            vType(LPCOLESTR(L"FruitChoice"));
      VARIANT               vText;
      vText.vt = VT_ERROR;
      // Create a Choice Sink so that we can listen to FruitChoices.
      
      hr = pSite->get_ChoiceSinks(&spChoiceSinks);
      if (hr)
         return hr;
      hr = spChoiceSinks->AddChoiceSink(vType, vText, &m_spChoiceSink);
      if (hr)
         return hr;

   }

   return hr;
}
// IDesignTimeControl
STDMETHODIMP CSinkDTC::get_DesignTimeControlSet(BSTR * pbstr)
{
   (*pbstr) = NULL;      // No-op
   return S_OK;
}

STDMETHODIMP CSinkDTC::OnGetChoices(Choices *)
{
   return S_OK;         // No-op. We have no dynamic choices.
}

STDMETHODIMP CSinkDTC::OnRebind(Choices *)
{
   return S_OK;         // No-op. We have no UI to show available choices.
}

STDMETHODIMP CSinkDTC::OnChoiceConflict(Choice *, VARIANT_BOOL)
{
   return S_OK;         // No-op.
}

STDMETHODIMP CSinkDTC::OnChoiceChange(ChoiceSink * pCS, dtcChoiceChange change)
{
   HRESULT   hr = S_OK;

   // Verifies that it's the correct choice sink

   if (pCS == m_spChoiceSink)
   {
      CComPtr<Choice>   spChoice;

//Notes that the BoundChoice has changed. 

      hr = pCS->get_BoundChoice(&spChoice);
      if (hr)
         return hr;
      if (spChoice != NULL)
      {
         spChoice->get_Description(&m_sSelectedFruit);
      }
      else
      {
         m_sSelectedFruit.Empty();
      }

      // Notifies editor to update.

      SetDirty(true);
//      FireOnChanged(DISPID_UNKNOWN);   
      SendOnDataChange(0);// Notifies the editor of a change.
      FireViewChange();            // Repaints.
   }

   return hr;
}

STDMETHODIMP CSinkDTC::OnHostingChange(dtcHostingChange change, VARIANT_BOOL *)
{
   // Called when the DTC UI is replaced with its runtime text.
   return S_OK;
}

STDMETHODIMP CSinkDTC::GetRuntimeClassID(CLSID *pclsid)
{
   return E_NOTIMPL;
}

STDMETHODIMP CSinkDTC::GetRuntimeMiscStatusFlags(DWORD * pdw)
{
   if (pdw == NULL)
      return E_INVALIDARG;

   *pdw = 0;
   return S_OK;
}

STDMETHODIMP CSinkDTC::QueryPersistenceInterface(REFIID iid)
{
   if (iid == IID_IPersistTextStream)
      return S_OK;

   return S_FALSE;
}

STDMETHODIMP CSinkDTC::SaveRuntimeState(REFIID iidPersist, REFIID iidObjStgMed, void * pObjStgMed)
{
   HRESULT         hr = S_OK;
   IStream *      pStm;
   ULONG         cbWritten;
   CComBSTR      sRuntimeText;

   if (iidPersist != IID_IPersistTextStream)
      return E_INVALIDARG;
   if (iidObjStgMed != IID_IStream)
      return E_INVALIDARG;

   pStm = static_cast<IStream *>(pObjStgMed);

   sRuntimeText =  L"<B>This is the chosen fruit: ";
   sRuntimeText += m_sSelectedFruit;
   sRuntimeText += "</B><P>";

   hr = pStm->Write(
         sRuntimeText.m_str,
         sRuntimeText.Length() * sizeof (OLECHAR),
         &cbWritten);

   return hr;
}

STDMETHODIMP CSinkDTC::GetExtensibilityObject(IDispatch ** ppDisp)
{
   return QueryInterface(IID_IDispatch, (void **) ppDisp);
}

STDMETHODIMP CSinkDTC::get_SelectedFruit(BSTR *pVal)
{
   m_sSelectedFruit.CopyTo(pVal);

   return S_OK;
}

STDMETHODIMP CSinkDTC::put_SelectedFruit(BSTR newVal)
{
   m_sSelectedFruit = newVal;

   return S_OK;
}