Figure 2

Figure 2 COM Interface Methods
IElementalBehavior
Method
Description
Detach
Informs the behavior that it is being detached from the element
Init
Informs the behavior that it's been created
Notify
Notifies the behavior about the various stages in the initialization of both the host document and the attached element
IElementBehaviorFactory
Method
Description
FindBehavior
Instantiates the specified behavior
IElementBehaviorCategory (optional)
Method
Description
GetCategory
Returns the string with the name of the category that the behavior belongs to
IElementBehaviorRender (optional and obsolete in Internet Explorer 5.5)
Method
Description
Draw
Invoked to draw the user interface for the behavior
GetRenderInfo
Retrieves rendering information for the behavior
HitTestPoint
Indicates whether the specified point is contained in the behavior's area
Figure 3 Mouseover Behavior
<PUBLIC:HTC>
<PUBLIC:ATTACH event="onmouseover" 
    handler="fnOver"/>
<PUBLIC:ATTACH event="onmouseout" 
    handler="fnOut"/>
<script LANGUAGE="jscript">
function fnOver()
{element.style.color="red";}
function fnOut()
{element.style.color="";}
</script>
</PUBLIC:HTC>
Figure 4 Binary Mouseover Behavior in C++
// Behavior.h : Declaration of the CBehavior

#ifndef __BEHAVIOR_H_
#define __BEHAVIOR_H_

#include "resource.h"               // main symbols
#include "IElementBehaviorImpl.h"   // IElementBehavior
#include "DHTMLEvents.h"            // 

/////////////////////////////////////////////////////////////////////////////
// CBehavior
class ATL_NO_VTABLE CBehavior : 
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CBehavior, &CLSID_Behavior>,
    public IElementBehaviorImpl,
    public IDispatchImpl<IBehavior, &IID_IBehavior, &LIBID_MYBEHLib>
{
public:
    CBehavior()
    {
        m_pEventSink = NULL;
        m_dwCookie = 0;
    }

DECLARE_REGISTRY_RESOURCEID(IDR_BEHAVIOR)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CBehavior)
    COM_INTERFACE_ENTRY(IElementBehavior)
    COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

// IElementBehavior
public:
    STDMETHOD(Notify)(LONG lEvent, VARIANT *pVar);
    STDMETHOD(Init)(IElementBehaviorSite *pBehaviorSite);
    STDMETHOD(Detach)(void);

    CComPtr<IHTMLElement>           m_spElem;
    CComVariant                     m_oldColor;

private:
    CComPtr<IElementBehaviorSite>   m_spSite;
    CComObject<CDHTMLEvents>*       m_pEventSink;
    DWORD                           m_dwCookie;
};

#endif //__BEHAVIOR_H_


///////////////////////////////////////////////////////////////////////////


// Factory.h : Declaration of the CFactory

#ifndef __FACTORY_H_
#define __FACTORY_H_

#include "resource.h"       // main symbols
#include "behavior.h"       // IElementBehavior


/////////////////////////////////////////////////////////////////////////////
// CFactory
class ATL_NO_VTABLE CFactory : 
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CFactory, &CLSID_Factory>,
    public IObjectSafetyImpl<CFactory,INTERFACESAFE_FOR_UNTRUSTED_CALLER>,
    public IElementBehaviorFactory
{
public:
    CFactory()
    {
    }

DECLARE_REGISTRY_RESOURCEID(IDR_FACTORY)

BEGIN_COM_MAP(CFactory)
    COM_INTERFACE_ENTRY(IElementBehaviorFactory)
    COM_INTERFACE_ENTRY(IObjectSafety)
END_COM_MAP()

// IFactory
public:
    STDMETHOD(FindBehavior)(BSTR bstrBehavior, 
                            BSTR bstrBehaviorUrl,
                            IElementBehaviorSite* pSite,
                            IElementBehavior** ppBehavior);

// IObjectSafety override
    STDMETHOD(SetInterfaceSafetyOptions)(REFIID riid,
        DWORD dwOptionSetMask, DWORD dwEnabledOptions)
    {
         // Set the safety options we have been asked to set.
        m_dwCurrentSafety = m_dwCurrentSafety  & ~dwEnabledOptions | 
                            dwOptionSetMask;
        return S_OK;
    } 
};

#endif //__FACTORY_H_



///////////////////////////////////////////////////////////////////
Figure 5 Sink Object
// DHTMLEvents.h : Declaration of the CDHTMLEvents

#ifndef __DHTMLEVENTS_H_
#define __DHTMLEVENTS_H_

#include "resource.h"  // main symbols
#include <mshtmdid.h>  // DHTML Behavior identifiers
#include <mshtmhst.h>  // DHTML Behavior interfaces
#include <mshtml.h>    // DHTML Object model

/////////////////////////////////////////////////////////////////////////////
// CDHTMLEvents

class CBehavior;

class ATL_NO_VTABLE CDHTMLEvents : 
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CDHTMLEvents, &CLSID_DHTMLEvents>,
    public IDispatchImpl<IDHTMLEvents, &IID_IDHTMLEvents, &LIBID_MYBEHLib>
{
public:
    CDHTMLEvents()
    {
        m_pBehavior = NULL;
    }

DECLARE_REGISTRY_RESOURCEID(IDR_DHTMLEVENTS)
DECLARE_NOT_AGGREGATABLE(CDHTMLEvents)

//DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CDHTMLEvents)
    COM_INTERFACE_ENTRY2(HTMLElementEvents, IDHTMLEvents)
    COM_INTERFACE_ENTRY2(HTMLAnchorEvents, IDHTMLEvents)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(IDHTMLEvents)
END_COM_MAP()

// IDispatchImpl override
    STDMETHOD(Invoke)(DISPID dispidMember,
                      REFIID riid,
                      LCID lcid,
                      WORD wFlags,
                      DISPPARAMS* pdispparams,
                      VARIANT* pvarResult,
                      EXCEPINFO* pexcepinfo,
                      UINT* puArgErr);

// Event Handlers (cfr. <PUBLIC:ATTACH>)
public:
    void OnMouseOver();
    void OnMouseOut();

// data members
    CBehavior *m_pBehavior;
};

#endif //__DHTMLEVENTS_H_
Figure 6 Implementation of the Behavior

Behavior.cpp
// Behavior.cpp : Implementation of CBehavior
#include "stdafx.h"
#include "MyBeh.h"
#include "DHTMLEvents.h"
#include "Behavior.h"

/////////////////////////////////////////////////////////////////////////////
// CBehavior



//////////////////////////////////////////////////////////////////////
// Init()
HRESULT CBehavior::Init(IElementBehaviorSite *pBehaviorSite)
{
    // Cache the IElementBehaviorSite interface pointer
    m_spSite = pBehaviorSite;

   return S_OK;
}

//////////////////////////////////////////////////////////////////////
// Notify()
HRESULT CBehavior::Notify(LONG lEvent, VARIANT *pVar)
{
    // What happens here is equivalent to <PUBLIC:ATTACH> for
    // oncontentready and ondocumentready

    switch(lEvent)
    {
        case BEHAVIOREVENT_CONTENTREADY:
            m_spSite->GetElement(&m_spElem);
            
            // Do something
            break;

        case BEHAVIOREVENT_DOCUMENTREADY:
            m_spSite->GetElement(&m_spElem);
            
            // Do something
            break;
    }
    
    return S_OK;
}
//////////////////////////////////////////////////////////////////////
// Detach()
HRESULT CBehavior::Detach(void)
{
    if (m_spElem)
        m_spElem.Release();

    return S_OK;
}
Factory.cpp
// Factory.cpp : Implementation of CFactory
#include "stdafx.h"
#include "MyBeh.h"
#include "Factory.h"

/////////////////////////////////////////////////////////////////////////////
// CFactory

HRESULT CFactory::FindBehavior(BSTR bstrBehavior, BSTR bstrBehaviorUrl,
        IElementBehaviorSite *pSite, IElementBehavior **ppBehavior)
{
    CComObject<CBehavior>* pBehavior;

    // Create a Behavior object
    HRESULT hr = CComObject<CBehavior>::CreateInstance(&pBehavior);

    if (SUCCEEDED(hr)) 
        hr = pBehavior->QueryInterface(__uuidof(IElementBehavior),
                (void**)ppBehavior);

    return hr;
}
Figure 7 Tags and Their COM Equivalents
HTC Tag
COM Equivalent
<PUBLIC:ATTACH event="oncontentready" />
<PUBLIC:ATTACH event="ondocumentready" />
IElementBehavior::Notify
<PUBLIC:ATTACH event="Any DHTML Event" />
Sink object exposing IDispatch
<PUBLIC:PROPERTY name="Property">
IDispatch on behavior's coclass
<PUBLIC:METHOD name="Method">
IDispatch on behavior's coclass
<PUBLIC:EVENT name="Event">
Methods of IElementBehaviorSiteOM
addBehavior or behavior CSS
IElementBehaviorFactory
removeBehavior
IElementBehavior::Detach
Figure 8 Firing oninitcomplete
if (m_spSiteOM)
{
    LONG cookie;
    
    HRESULT hr;
    hr = m_spSiteOM->GetEventCookie(L"oninitcomplete", &cookie);
        if (SUCCEEDED(hr))
        {
        IHTMLEventObject* pEvent;
        hr = m_spSiteOM->CreateEventObject(&pEvent);
        if (SUCCEEDED(hr))
        {
            m_spSiteOM->FireEvent(cookie, pEvent);
            pEvent->Release();
        }
    }
}
Figure 9 Sinking DHTML Events
// DHTMLEvents.h : Declaration of the CDHTMLEvents

#ifndef __DHTMLEVENTS_H_
#define __DHTMLEVENTS_H_

#include "resource.h"      // main symbols
#include <mshtmdid.h>      // DHTML Behavior identifiers
#include <mshtmhst.h>      // DHTML Behavior interfaces
#include <mshtml.h>        // DHTML Object model

///////////////////////////////////////////////////////////////////////////
// CDHTMLEvents

class CBehavior;

class ATL_NO_VTABLE CDHTMLEvents : 
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CDHTMLEvents, &CLSID_DHTMLEvents>,
    public IDispatchImpl<IDHTMLEvents, &IID_IDHTMLEvents, &LIBID_MYBEHLib>
{
public:
    CDHTMLEvents()
    {
        m_pBehavior = NULL;
    }

DECLARE_REGISTRY_RESOURCEID(IDR_DHTMLEVENTS)
DECLARE_NOT_AGGREGATABLE(CDHTMLEvents)

//DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CDHTMLEvents)
    COM_INTERFACE_ENTRY2(HTMLElementEvents, IDHTMLEvents)
    COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

// IDispatchImpl override
    STDMETHOD(Invoke)(DISPID dispidMember,
                      REFIID riid,
                      LCID lcid,
                      WORD wFlags,
                      DISPPARAMS* pdispparams,
                      VARIANT* pvarResult,
                      EXCEPINFO* pexcepinfo,
                      UINT* puArgErr);

// Event Handlers (cfr. <PUBLIC:ATTACH>)
public:
    void OnMouseOver();
    void OnMouseOut();

// data members
    CBehavior *m_pBehavior;
};

#endif //__DHTMLEVENTS_H_
Figure 10 DHTML Events
// DHTMLEvents.cpp : Implementation of CDHTMLEvents
#include "stdafx.h"
#include "MyBeh.h"
#include "DHTMLEvents.h"
#include "Behavior.h"

/////////////////////////////////////////////////////////////////////////////
// CDHTMLEvents

HRESULT CDHTMLEvents::Invoke(DISPID dispidMember, REFIID riid, LCID lcid,
    WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, 
    EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
    switch (dispidMember)
    {
    case DISPID_HTMLELEMENTEVENTS_ONMOUSEOVER:
        OnMouseOver();
        break;

    case DISPID_HTMLELEMENTEVENTS_ONMOUSEOUT:
            OnMouseOut();
        break;

    default:
        break;
    }

    return S_OK;
}


// OnMouseOver event handler
void CDHTMLEvents::OnMouseOver()
{
    // highlight the text
    if (m_pBehavior)
    {
            CComPtr<IHTMLStyle> spStyle;
            m_pBehavior->m_spElem->get_style(&spStyle);
            spStyle->put_color(CComVariant(L"red"));    
    }
}

// OnMouseOut event handler
void CDHTMLEvents::OnMouseOut()
{
    // restore the text
    if (m_pBehavior)
    {
            CComPtr<IHTMLStyle> spStyle;
            m_pBehavior->m_spElem->get_style(&spStyle);
            spStyle->put_color(m_pBehavior->m_oldColor);    
    }
}
Figure 15 Rendering Methods
Method
Description
Draw
Renders a behavior in the browser's client area.
GetPainterInfo
Provides MSHTML with the information it needs in order to issue proper calls to Draw. In particular, it relates the required z-order and whether DirectX is being used or not.
HitTestPoint
MSHTML calls this method when calls are made to elementFromPoint on the attached element. The implementation must check whether the point is within the behavior's area.
OnResize
Called by MSHTML to allow a behavior to resize when the element to which it is attached gets resized.
Show: