Notice: This website is an unofficial Microsoft Knowledge Base (hereinafter KB) archive and is intended to provide a reliable access to deleted content from Microsoft KB. All KB articles are owned by Microsoft Corporation. Read full disclaimer for more details.

How To Set DHTML Event Properties from C++


View products that this article applies to.

Summary

This article describes how to set C++ event handlers on the DHTML event properties, such as put_onmousedown, from a WebBrowser control host, ActiveX control, or other C++ object.

↑ Back to the top


More information

The Dynamic HTML object model allows script to assign functions directly to event handlers using event properties:
<SCRIPT LANGUAGE="jscript">
function mousedownhandler()
{
   // do stuff;
}

function afterPageLoads()
{
   someElement.onmousedown = mousedownhandler;
}
</SCRIPT>
				
To duplicate this form of event handling from C++, implement a simple COM object for each function object that implements only the IUnknown and IDispatch interfaces. Pass a reference to this object inside a variant to the appropriate event property. When the event fires, the IDispatch::Invoke function will be executed with a DISPID of 0 to signal the event.

The following example header file implements a template class that can be used to easily create these "function objects" in C++.

FUNCTIONOBJECT.H:
// FunctionObject.h: interface for the CFunctionObject class.
// 
// USAGE:
// The user of this class is a C++ class (CYourClass) that must:
//		
// 1. Implement a member function on CYourClass of the form:
//				
// void MyEventCallback(DISPID id, VARIANT* pVarResult);
// 
// This function will be called with the dispid set in
// CreateEventFunctionObject. One event handler function can service
// multiple event function objects.
// 
// 2. When setting function object event handlers on MSHTML, use code of
// this form:
// 
// _variant_t varFO =
//    CFunctionObject<CYourClass>::CreateEventFunctionObject(this,
//       MyEventCallback, DISPID_MOUSEDOWN);
// [HTML object interface]->put_onmousedown(varFO);
// 
// This syntax requires VC++ COM compiler support for the _variant_t class. 
// Otherwise, pass into the put_mousedown (or other MSHTML event prop)
// a VARIANT containing the LPDISPATCH returned from
// CreateEventFunctionObject.
// 
// 3. Set all MSHTML function object event handlers to NULL before the
// MSHTML document is destroyed:
// 
//   VARIANT varNull; varNull.vt = VT_NULL;
//   [HTML object interface]->put_onmousedown(varNull);
// 
// At minimum, do this in an event handler for the HTML window object's 
// "onbeforeunload" event or WebBrowser control BeforeNavigate2. The 
// function objects will be stranded in memory if this isn't done before
// the HTML document is unloaded.If you set the handlers to NULL in 
// BeforeNavigate2 then you should also account for the last case when 
// the application is being shutdown since BeforeNavigate2 will not be
// called at that time. 


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

template <class T> class CFunctionObject : public IDispatch  
{
typedef void (T::*EVENTFUNCTIONCALLBACK)(DISPID id, VARIANT* pVarResult);

public:
   CFunctionObject() { m_cRef = 0; }
	
   ~CFunctionObject() {}

   HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject)
   {
      *ppvObject = NULL;

      if (IsEqualGUID(riid, IID_IUnknown))
         *ppvObject = reinterpret_cast<void **> (this);

      if (IsEqualGUID(riid, IID_IDispatch))
         *ppvObject = reinterpret_cast<void **> (this);

      if (*ppvObject)
      {
         ((IUnknown*)*ppvObject)->AddRef();
         return S_OK;
      }
      else return E_NOINTERFACE;
   }

   DWORD __stdcall AddRef()
   {
      return InterlockedIncrement(&m_cRef);
   }

   DWORD __stdcall Release()
   {
      if (InterlockedDecrement(&m_cRef) == 0)
      {
         delete this;
         return 0;
      }
      return m_cRef;
   }

   STDMETHOD(GetTypeInfoCount)(unsigned int FAR* pctinfo)
   { return E_NOTIMPL; }
   STDMETHOD(GetTypeInfo)(unsigned int iTInfo, LCID  lcid,
      ITypeInfo FAR* FAR*  ppTInfo)
   { return E_NOTIMPL; }
   STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames,
      unsigned int cNames, LCID lcid, DISPID FAR* rgDispId)
   { return S_OK; }
   STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid,
      WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
      EXCEPINFO * pExcepInfo, UINT * puArgErr)
   {
      if (DISPID_VALUE == dispIdMember)
         (m_pT->*m_pFunc)(m_id, pVarResult);
      else
         TRACE(_T("CFO Invoke dispid = %d\n"), dispIdMember);
	
      return S_OK;
   }

public:
   static LPDISPATCH CreateEventFunctionObject(T* pT,
                        EVENTFUNCTIONCALLBACK pFunc, DISPID id)
   {
      CFunctionObject<T>* pFO = new CFunctionObject<T>;
      pFO->m_pT = pT;
      pFO->m_pFunc = pFunc;
      pFO->m_id = id;
      return reinterpret_cast<LPDISPATCH> (pFO);
   }

protected:
   T* m_pT;
   EVENTFUNCTIONCALLBACK m_pFunc;
   DISPID m_id;
   long m_cRef;
	};
				

↑ Back to the top


Properties

Retired KB Content Disclaimer
This article was written about products for which Microsoft no longer offers support. Therefore, this article is offered "as is" and will no longer be updated.

↑ Back to the top


Keywords: KB253915, kbhowto, kbdhtml

↑ Back to the top

Article Info
Article ID : 253915
Revision : 3
Created on : 7/13/2004
Published on : 7/13/2004
Exists online : False
Views : 355