How To Set DHTML Event Properties from C++ (253915)
The information in this article applies to:
- Microsoft Internet Explorer (Programming) 4.0
- Microsoft Internet Explorer (Programming) 4.01
- Microsoft Internet Explorer (Programming) 4.01 SP1
- Microsoft Internet Explorer (Programming) 4.01 SP2
- Microsoft Internet Explorer (Programming) 5
- Microsoft Internet Explorer (Programming) 5.01
- Microsoft Internet Explorer (Programming) 5.5
This article was previously published under Q253915 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.
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;
};
Modification Type: | Minor | Last Reviewed: | 7/13/2004 |
---|
Keywords: | kbDHTML kbhowto KB253915 |
---|
|