Microsoft HomeproductssearchsupportshopWrite Us   Microsoft Home
Magazine
 |  Community
 |  Workshop
 |  Tools & Samples
 |  Training
 |  Site Info

Workshop  |  Component Development

MFC Step-by-Step


Jay Massena and Douglas Hodges

Updated: February 12, 1997

DownloadDownload this document in Microsoft Word (.DOC) format (zipped, 4.92K).

Summary

This document is a step-by-step tutorial for creating the Bgsound design-time control using Microsoft® Foundation Classes (MFC).

Contents
Step 1: Use MFC OLE ControlWizard to create your control
Step 2: Add IActiveDesigner interface to class definition
Step 3: Implement IActiveDesigner interface]



Create an ActiveX Control

Step 1: Use MFC OLE ControlWizard to Create Your Control

A. Create new project workspace and run OleControlWizard to create a project named "BGSound". Set to Windowless activation in advanced options.

B. Add the Design-time Control SDK include directory to INCLUDE Path

c:\progra~1\dcsdk\Samples\Mfc\include
C. Use View.ClassWizard to add Property Get/Set methods

BSTR Source
short Loop

D. Add Member Variables (in BGSoundCtl.h)

   // control properties
   short m_nLoop;
   CString m_strSource;

E. Add Get/Set Methods (in BGSoundCtl.cpp)

short CBGSoundCtrl::GetLoop() 
{
   return m_nLoop;
}

void CBGSoundCtrl::SetLoop(short nNewValue) 
{
   // verify loop property is valid
   if (nNewValue >= -1)
   {
      // set our internal loop value
      m_nLoop = nNewValue;

      // notify container that a property was modified
      SetModifiedFlag();

      // notify property browsers that this property changed
      BoundPropertyChanged(dispidLoop);
   }
   else
   {
      ThrowError(CTL_E_INVALIDPROPERTYVALUE, 
            _T("Loop must be an integer greater than or equal to -1"));
   }
}

BSTR CBGSoundCtrl::GetSource() 
{
   return m_strSource.AllocSysString();
}

void CBGSoundCtrl::SetSource(LPCTSTR lpszNewValue) 
{
    // set our internal source string
    m_strSource = lpszNewValue;

    // notify container that a property was modified
    SetModifiedFlag();

    // notify property browsers that this property changed
    BoundPropertyChanged(dispidSource);

    // make sure we get repainted since 'Source' is our caption
    InvalidateControl();
}

F. Add Support to persist properties (in CBGSoundCtrl::DoPropExchange)

   // persist our properties
   PX_String(pPX, _T("Source"), m_strSource, _T(""));
   PX_Short(pPX, _T("Loop"), m_nLoop, -1);

G. Add Drawing Code (in CBGSoundCtrl::OnDraw)

void CBGSoundCtrl::OnDraw(
         CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
    CFont fnt;
    CRect rcText;

    // get text rect;
    rcText = rcBounds;
    rcText.left += 2;
    rcText.right -= 2;
    rcText.top += 2;
    rcText.bottom -= 2;

    // create font
    fnt.CreatePointFont(160, _T("MS Sans Serif"), pdc);
    CFont* pOldFont = pdc->SelectObject(&fnt);
    pdc->SetBkMode(TRANSPARENT);

    // fill our rect with gray
    pdc->FillRect(rcBounds,)                                                
                      
   CBrush::FromHandle((HBRUSH)GetStockObject(LTGRAY_BRUSH)));

    // draw an edge
    pdc->DrawEdge(&(RECT)rcBounds, EDGE_RAISED, BF_RECT);

    // draw the Source text
    pdc->DrawText(_T("\"") + m_strSource + _T("\""), &(RECT)rcText, DT_WORDBREAK | DT_CENTER); 

    // return to old font
    pdc->SelectObject(pOldFont);
}

TopBack to top

Add Design-time Control Support

Step 2: Add IActiveDesigner Interface to Class Definition

A. Add IActiveDesigner interface definition (in BGSoundCtl.h)

#include "designer.h"
#include "webdc.h"

B. Declare Interface_Map and IActiveDesigner interface (in BGSoundCtl.h - protected)

   // Interface maps
   DECLARE_INTERFACE_MAP();

   // IActiveDesigner Interface
   BEGIN_INTERFACE_PART(ActiveDesigner, IActiveDesigner)
      STDMETHOD(GetRuntimeClassID)(CLSID *pclsid);
      STDMETHOD(GetRuntimeMiscStatusFlags)(DWORD *dwMiscFlags);
      STDMETHOD(QueryPersistenceInterface)(REFIID riidPersist);
      STDMETHOD(SaveRuntimeState)(REFIID riidPersist, REFIID riidObjStgMed, void *pObjStgMed);
      STDMETHOD(GetExtensibilityObject)(IDispatch **ppvObjOut);
   END_INTERFACE_PART(ActiveDesigner)

   virtual HRESULT GetRuntimeText(CString& strText);

TopBack to top

Step 3: Implement IActiveDesigner Interface

A. Add intialization of IActiveDesigner GUIDs (in BGSoundCtl.cpp after Stdafx.h)

// Define and initialize required GUIDs
#include <initguid.h>
#include "designer.h"
#include "webdc.h"

B. Add Interface Map (in BGSoundCtl.cpp)

////////////////////////////////////////////////////////////////////////
// Interface Map

BEGIN_INTERFACE_MAP(CBGSoundCtrl, COleControl)
   INTERFACE_PART(CBGSoundCtrl, IID_IActiveDesigner, ActiveDesigner)
END_INTERFACE_MAP()

C. Add IActiveDesigner interface implementation (in BGSoundCtl.cpp)

////////////////////////////////////////////////////////////////////////
// CBGSoundCtrl::XActiveDesigner - IActiveDesigner interface
//
// The following functions represent the implementation of the IActiveDesigner
// interface. For the most part, these functions can be left as is. The
// SaveRuntimeState() function will call the CBGSoundCtrl::GetRuntimeText()
// function when it needs to generate run-time text.

STDMETHODIMP_(ULONG) CBGSoundCtrl::XActiveDesigner::AddRef(void)
{
   METHOD_MANAGE_STATE(CBGSoundCtrl, ActiveDesigner)
   return (ULONG)pThis->ExternalAddRef();
}

STDMETHODIMP_(ULONG) CBGSoundCtrl::XActiveDesigner::Release(void)
{
   METHOD_MANAGE_STATE(CBGSoundCtrl, ActiveDesigner)
   return (ULONG)pThis->ExternalRelease();
}

STDMETHODIMP CBGSoundCtrl::XActiveDesigner::QueryInterface(REFIID iid,
   
   LPVOID far* ppvObj)
{
   METHOD_MANAGE_STATE(CBGSoundCtrl, ActiveDesigner)
   return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}

STDMETHODIMP CBGSoundCtrl::XActiveDesigner::GetRuntimeClassID(CLSID *pclsid)
{
    *pclsid = CLSID_NULL;
    return S_FALSE;
}

STDMETHODIMP CBGSoundCtrl::XActiveDesigner::GetRuntimeMiscStatusFlags(DWORD *pdwMiscFlags)
{
   if (!pdwMiscFlags)
      return E_INVALIDARG;
   *pdwMiscFlags = NULL;
   return E_UNEXPECTED;
}

STDMETHODIMP CBGSoundCtrl::XActiveDesigner::QueryPersistenceInterface(REFIID riid)
{
   if (riid == IID_IPersistTextStream)
      return S_OK;
   return S_FALSE;
}

STDMETHODIMP CBGSoundCtrl::XActiveDesigner::SaveRuntimeState
(
   REFIID riidPersist,
   REFIID riidObjStgMed,
   void  *pObjStgMed
)
{
   HRESULT  hr;
   CString  cstrText;
   BSTR     bstrText;

   METHOD_MANAGE_STATE(CBGSoundCtrl, ActiveDesigner)

   if (riidPersist != IID_IPersistTextStream)
      return E_NOINTERFACE;

   if (riidObjStgMed != IID_IStream)
      return E_NOINTERFACE;

   hr = pThis->GetRuntimeText(cstrText);
   if (SUCCEEDED(hr))
   {
      bstrText = cstrText.AllocSysString();
      if (bstrText)
      {
         hr = ((IStream *)pObjStgMed)->Write(bstrText, 
         SysStringByteLen(bstrText) + sizeof(OLECHAR), NULL);
         SysFreeString(bstrText);
      }
      else
         hr = E_OUTOFMEMORY;
   }

   return hr;
}

STDMETHODIMP CBGSoundCtrl::XActiveDesigner::GetExtensibilityObject(IDispatch **ppvObjOut)
{
   if (!ppvObjOut)
      return E_INVALIDARG;
   return this->QueryInterface(IID_IDispatch, (void **)ppvObjOut);
}

////////////////////////////////////////////////////////////////////////
// CBGSoundCtrl::GetRuntimeText - Generates run-time text for the control
//
// GetRuntimeText() is called whenever the container needs to update the
// run-time text after property changes or other state changes are made.

HRESULT CBGSoundCtrl::GetRuntimeText(CString& strText)
{
    // our run-time Text template
   CString strTemplate = _T("<BGSOUND SRC=\"%s\" LOOP=%d>");

    // format our string with our properties
   strText.Format(strTemplate, m_strSource, m_nLoop);

   return S_OK;
}


Did you find this article useful? Gripes? Compliments? Suggestions for other articles? Write us!

Back to topBack to top

© 1998 Microsoft Corporation. All rights reserved. Terms of use.

 

Magazine Home
Ask Jane
DHTML Dude
Extreme XML
For Starters
More or Hess
Servin' It Up
Site Lights
Web Men Talking
Member Community Home
Benefits: Freebies & Discounts
Benefits: Promote Your Site
Benefits: Connect with Your Peers
Benefits at a Glance
Online Special-Interest Groups
Your Membership
SBN Stores
Join Now
Workshop Home
Essentials
Content & Component Delivery
Component Development
Data Access & Databases
Design
DHTML, HTML & CSS
Extensible Markup Language (XML)
Languages & Development Tools
Messaging & Collaboration
Networking, Protocols & Data Formats
Reusing Browser Technology
Security & Cryptography
Server Technologies
Streaming & Interactive Media
Web Content Management
Workshop Index
Tools & Samples Home
Tools
Samples, Headers, Libs
Images
Sounds
Style Sheets
Web Fonts
Training Home
SBN Live Seminars
SBN Live Chats
Courses
Peer Support
CD-ROM Training
Books & Training Kits
Certification
SBN Home
New to SBN?
What's New on SBN
Site Map
Site Search
Glossary
Write Us
About This Site