Handling an OnClick event of a checkbox

2

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?

c++
com
atl
bho
mshtml
asked on Stack Overflow Jan 13, 2014 by Paul • edited Jan 14, 2014 by Roman R.

1 Answer

2

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).

enter image description here

answered on Stack Overflow Jan 14, 2014 by Roman R.

User contributions licensed under CC BY-SA 3.0