I'm trying to handle click events of a checkbox control from a BHO.
Here is my code:
void STDMETHODCALLTYPE CMyBHO::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
{
// ...
InitPage(pDocument);
}
void CMyBHO::InitPage(IHTMLDocument2 *pDocument)
{
CComQIPtr<IHTMLDocument3> document3 = pDocument;
CComPtr<IHTMLElement> elementCheckbox;
document3->getElementById(CComBSTR(L"checkbox_id_here"), &elementCheckbox);
if(!elementCheckbox)
return;
if(!m_fCheckboxAdvised)
{
// Register to sink events from HTMLDocumentEvents2.
hr = IHTMLElementEvents2Impl::DispEventAdvise(elementCheckbox);
if(SUCCEEDED(hr))
m_fCheckboxAdvised = TRUE;
else
ATLASSERT(0); // FAILS HERE, hr = 0x80040200
}
}
Header file:
class ATL_NO_VTABLE CMyBHO :
/*...*/
public IDispEventImpl<1, CMyBHO, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>,
public IDispEventImpl<2, CMyBHO, &DIID_HTMLElementEvents2, &LIBID_MSHTML, 4, 0>
{
typedef IDispEventImpl<1, CMyBHO, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1> IDWebBrowserEvents2Impl;
typedef IDispEventImpl<2, CMyBHO, &DIID_HTMLElementEvents2, &LIBID_MSHTML, 4, 0> IHTMLElementEvents2Impl;
public:
/*...*/
BEGIN_SINK_MAP(CMyBHO)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
SINK_ENTRY_EX(2, DIID_HTMLElementEvents2, DISPID_HTMLELEMENTEVENTS2_ONCLICK, OnMouseClick)
END_SINK_MAP()
public:
STDMETHOD(SetSite)(IUnknown *pUnkSite);
// DWebBrowserEvents2
void STDMETHODCALLTYPE OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL);
// HTMLDocumentEvents2
void STDMETHODCALLTYPE OnMouseClick(IHTMLEventObj *eventObj);
/*...*/
};
DispEventAdvise
fails with hr = 0x80040200
. What am I doing wrong?
Also, when should I call DispEventUnadvise
?
You don't have the connection point you request, hence the CONNECT_E_NOCONNECTION
failure.
Instead of implementing a connection point client for HTML elements with a multitude of interfaces, you might prefer an alternate route and implement IDispatch on your event sink object, and then assign the interface pointer to onclick
property of the HTML element. You will get IDispatch::Invoke
call on the event.
Here is a code snippet for you for creating an instance of suitable IDispatch
implemetnation, and setting onresize
property via C++ code:
CComPtr<IHTMLElement> pBodyElementA;
ATLENSURE_SUCCEEDED(pDocument->get_body(&pBodyElementA));
CComPtr<IDispatch> pSinkDispatch;
ATLENSURE_SUCCEEDED(CDispatchEventSink::CreateInstance(&pSinkDispatch));
CComVariant vValue = pSinkDispatch;
ATLENSURE_SUCCEEDED(reinterpret_cast<CComPtr<IDispatch>&>(pBodyElementA).
PutPropertyByName(L"onresize", &vValue));
CDispatchEventSink
class is here, and you will find full sample project there as well (also, SVN link).
User contributions licensed under CC BY-SA 3.0