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

Workshop  |  Component Development

Design-time Control Tutorial


Jay Massena and Douglas Hodges

Updated: February 12, 1997

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

Summary

This document is a tutorial that covers what it takes to make an ActiveX™ control a design-time control. It also provides some assistance for HTML editors that want to host design-time controls.

Bgsound Code Fragments

These code fragments illustrate what it takes to turn an MFC control wizard-generated ActiveX control into a design-time control.

IActiveDesigner Interface Declaration

/////////////////////////////////////////////////////////////////////////////
// IActiveDesigner Interface Declaration
//
// {51AAE3E0-7486-11cf-A0C2-00AA0062BE57}
/////////////////////////////////////////////////////////////////////////////
DEFINE_GUID(IID_IActiveDesigner, 0x51aae3e0, 0x7486, 0x11cf, 0xa0, 0xc2, 0x0, 0xaa, 0x0, 0x62, 0xbe, 0x57);

#undef  INTERFACE
#define INTERFACE IActiveDesigner

DECLARE_INTERFACE_(IActiveDesigner, IUnknown)
{
   // IUnknown methods
   //
   STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;
   STDMETHOD_(ULONG,AddRef)(THIS) PURE;
   STDMETHOD_(ULONG,Release)(THIS) PURE;

   // IActiveDesigner methods
   //
   STDMETHOD(GetRuntimeClassID)(THIS_ CLSID *pclsid) PURE;
   STDMETHOD(GetRuntimeMiscStatusFlags)(THIS_ DWORD *dwMiscFlags) PURE;
   STDMETHOD(QueryPersistenceInterface)(THIS_ REFIID riidPersist) PURE;
   STDMETHOD(SaveRuntimeState)(THIS_ REFIID riidPersist, REFIID riidObjStgMed, void *pObjStgMed) PURE;
   STDMETHOD(GetExtensibilityObject)(THIS_ IDispatch **ppvObjOut) PURE;
};

const GUID IID_IActiveDesigner = 
      { 0x51aae3e0, 0x7486, 0x11cf, { 0xa0, 0xc2, 0x0, 0xaa, 0x0, 0x62, 0xbe, 0x57 } };
const GUID IID_IPersistTextStream = 
   {0x56223fe3, 0xd397, 0x11cf, { 0xa4, 0x2e, 0x0, 0xaa, 0x0, 0xc0, 0x9, 0x40 } };

Bgsound Class Definition

/////////////////////////////////////////////////////////////////////////////
// CBGSndCtrl class
//    This class implements the BackgroundSound Designer control.
//    This class implements the standard OLE control interfaces by 
//    deriving them from MFC's COleControl class.  This class adds the 
//    implementation of the IActiveDesigner interface to act as an
//    HTML Designer control.
/////////////////////////////////////////////////////////////////////////////
class CBGSndCtrl : public COleControl
{
   DECLARE_DYNCREATE(CBGSndCtrl)

// Constructor
public:
   CBGSndCtrl();

// Overrides
   // ClassWizard generated virtual function overrides
   //{{AFX_VIRTUAL(CBGSndCtrl)
   public:
   virtual void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid);
   virtual void DoPropExchange(CPropExchange* pPX);
   virtual void OnResetState();
   virtual DWORD GetControlFlags();
   //}}AFX_VIRTUAL

// Implementation
protected:
   HBITMAP m_hBitmap;
   
    // control properties
    short m_nLoop;
    CString m_strSource;

    // destruction
   ~CBGSndCtrl();

    virtual HRESULT GetRuntimeText(CString& szHTML);

   DECLARE_OLECREATE_EX(CBGSndCtrl)  // Class factory and guid
   DECLARE_OLETYPELIB(CBGSndCtrl)    // GetTypeInfo
   DECLARE_OLECTLTYPE(CBGSndCtrl) // Type name and misc status

// Message maps
   //{{AFX_MSG(CBGSndCtrl)
      // NOTE - ClassWizard will add and remove member functions here.
      //    DO NOT EDIT what you see in these blocks of generated code !
   //}}AFX_MSG
   DECLARE_MESSAGE_MAP()

// Dispatch maps
   //{{AFX_DISPATCH(CBGSndCtrl)
   afx_msg short GetLoop();
   afx_msg void SetLoop(short nNewValue);
   afx_msg BSTR GetSource();
   afx_msg void SetSource(LPCTSTR lpszNewValue);
    virtual BOOL OnSetExtent(LPSIZEL lpSizeL);
   //}}AFX_DISPATCH
   DECLARE_DISPATCH_MAP()

   afx_msg void AboutBox();

// Event maps
   //{{AFX_EVENT(CBGSndCtrl)
   //}}AFX_EVENT
   DECLARE_EVENT_MAP()

// Interface maps
   DECLARE_INTERFACE_MAP();


public:
//$$$$$$$$$$$$$$$$$$$$$$$DESIGNER SPECIFIC$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 
    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)
//$$$$$$$$$$$$$$$$$$$$$END DESIGNER SPECIFIC$$$$$$$$$$$$$$$$$$$$$$$$$$

// Dispatch and event IDs 
    enum {
   //{{AFX_DISP_ID(CBGSndCtrl)
   dispidLoop = 1L,
   dispidSource = 2L,
   //}}AFX_DISP_ID
   };
};

IActiveDesigner Interface Implementation

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

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

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

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

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

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

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

   METHOD_MANAGE_STATE(CBGSndCtrl, ActiveDesigner)

   if (riidPersist != IID_IPersistTextStream)
      return E_NOINTERFACE;

   if (riidObjStgMed != IID_IStream)
      return E_NOINTERFACE;

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

   return hr;
}

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


GetRuntimeText Helper Function

/////////////////////////////////////////////////////////////////////////////
// CBGSndCtrl::GetRuntimeText - Generates the 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 CBGSndCtrl::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;
}

Tagging a Web Design-time Control with CATID

DEFINE_GUID(CATID_WebDesigntimeControl, 0x73cef3dd, 0xae85, 0x11cf, 0xa4, 0x6, 0x0,  0xaa, 0x0, 0xc0, 0x9, 0x40);

////////////////////////////////////////////////////////////////////////////
// HandleComponentRegisration - registers the controls in this libary as
//   design-time controls.
HRESULT HandleComponentRegistration(BOOL fRegister)
{
   if (fRegister)
      return RegisterControlCategory(CATID_WebDesigntimeControl,
                                      L"Web Design-time Control",
                                      (REFCLSID)CBGSndCtrl::guid);
   else
      return UnRegisterControlCategory(CATID_WebDesigntimeControl, 
                                             (REFCLSID)CBGSndCtrl::guid);
}

/////////////////////////////////////////////////////////////////////////////
// RegisterControlCategory : Register controls with catid

HRESULT RegisterControlCategory(CATID catid, WCHAR* wszDesc, REFCLSID rClsid)
{
    ICatRegister* pcr = NULL ;
    HRESULT hr = S_OK ;

    hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
                          NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister,
                                 (void**)&pcr);
    if (FAILED(hr))
        return hr;

    hr = CreateComponentCategory(pcr, catid, wszDesc);
    if (SUCCEEDED(hr))
   {
      CATID rgcatid[1] ;
      rgcatid[0] = catid;

      hr = pcr->RegisterClassImplCategories(rClsid, 1, rgcatid);
   }

    pcr->Release();
   return hr;
}

/////////////////////////////////////////////////////////////////////////////
// UnRegisterControlCategory : Unregister controls with catid

HRESULT UnRegisterControlCategory(CATID catid, REFCLSID rClsid)
{
    ICatRegister* pcr = NULL ;
    HRESULT hr = S_OK ;

    hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, 
                          NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister,
                                 (void**)&pcr);
    if (FAILED(hr))
        return hr;

   CATID rgcatid[1] ;
   rgcatid[0] = catid;

   hr = pcr->UnRegisterClassImplCategories(rClsid, 1, rgcatid);

    pcr->Release();
   return hr;
}

/////////////////////////////////////////////////////////////////////////////
// CreateComponentCategory : Create a COM Server Category

HRESULT CreateComponentCategory(ICatRegister* pcr, CATID catid, WCHAR* wszCatDescription)
{
    HRESULT hr = S_OK ;

    // Make sure the HKCR\Component Categories\{..catid...} key is registered
    CATEGORYINFO catinfo;
    catinfo.catid = catid;
    catinfo.lcid = 0x0409 ; // english

    // Make sure the provided description is not too long.
    // Only copy the first 127 characters if it is
    int len = wcslen(wszCatDescription);
    if (len>127)
        len = 127;
    wcsncpy(catinfo.szDescription, wszCatDescription, len);
    // Make sure the description is null terminated
    catinfo.szDescription[len] = '\0';

    hr = pcr->RegisterCategories(1, &catinfo);

    return hr;
}

Hosting Code Fragments

These code fragments show how a hosting container can perform some common operations associated with design-time controls. We assume that the container already has containership support for ActiveX™ controls.

Persisting a Web Design-time Control

/////////////////////////////////////////////////////////////////////////////
// The following sample code fragment demonstrates how the container saves the 
// run-time text of a design-time control:

HRESULT SaveRuntimeText( ... IUnknown* pUnk ... )
{
   IActiveDesigner *pActiveDesigner;
   HGLOBAL         hGlobal = NULL;
   IStream         *pStream = NULL;
   OLECHAR         *pstr;
   HRESULT         hr;

   hr = pUnk->QueryInterface( IID_IActiveDesigner, (void**)&pActiveDesigner );
   if ( SUCCEEDED(hr) && pActiveDesigner )
   {
      hr = pActiveDesigner->QueryPersistenceInterface( IID_IPersistTextStream );
      if ( SUCCEEDED(hr) )
      {
         hGlobal = GlobalAlloc( GMEM_MOVEABLE | GMEM_NODISCARD, 0 );
         if ( hGlobal )
         {
            hr = CreateStreamOnHGlobal( hGlobal, FALSE, &pStream );
            if ( SUCCEEDED(hr) )
            {
            hr = pActiveDesigner->SaveRuntimeState( IID_IPersistTextStream,
                 IID_IStream, pStream );
            if ( SUCCEEDED(hr) )
            {
               OLECHAR chZero = 0;
                  ULONG   cbWritten;

                      // Make sure the text has a null terminator
                      pStream->Write(&chZero, sizeof(chZero), &cbWritten);

                      pstr = (OLECHAR *)GlobalLock( hGlobal );
                      if ( pstr )
                      {
                         TCHAR      *pch;

                         pch = MyOLE2T( pstr );

                         //... save out run-time text  ...

                         GlobalUnlock( hGlobal );
                      }
                }
                pStream->Release();
            }
            GlobalFree( hGlobal );
         }
      }
      pActiveDesigner->Release();
   }
   return NOERROR;
}


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