【问题标题】:Handling an OnClick event of a checkbox处理复选框的 OnClick 事件
【发布时间】:2014-02-01 02:18:48
【问题描述】:

我正在尝试处理来自 BHO 的复选框控件的单击事件。

这是我的代码:

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
    }
}

头文件:

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 失败,hr = 0x80040200。我做错了什么?

另外,我应该什么时候打电话给DispEventUnadvise

【问题讨论】:

  • HTML 元素没有实现连接点,所以你有CONNECT_E_NOCONNECTION 失败。相反,您需要在对象上实现IDispatch,并将接口指针分配给HTML 元素的onclick 属性。您将在活动中收到IDispatch::Invoke 电话。
  • @RomanR.,感谢您的评论。我对 BHO 和/或 ATL 不是很有经验。如果您可以提供一个最小的示例或包含更多信息的链接,那将非常有帮助。提前致谢。
  • @RomanR。 HTML 元素也实现了连接点。但是它们使用起来有些不方便,因为不同类型的元素接受不同的源接口:没有一个单一的接收器可以建议所有它们。例如。 &lt;input type="checkbox"&gt; 由支持以下源接口的HTMLInputElement coclass 表示:HTMLInputTextElementEventsHTMLInputTextElementEvents2HTMLOptionButtonElementEventsHTMLButtonElementEvents - 但 不是 HTMLElementEvents2 OP 正在尝试水槽。
  • @IgorTandetnik:谢谢,我在这里更正了。
  • @Paul 将建议的元素存储在向量或列表中。通过计时器轮询时,您可以使用 IsSameObject 检查元素是否在列表中。通过定时器轮询很有用,即使在没有刷新的情况下也是如此。很多页面在“随机”时刻对 DOM 做了一些奇怪的事情。

标签: c++ com atl bho mshtml


【解决方案1】:

您没有请求的连接点,因此CONNECT_E_NOCONNECTION 失败。

您可能更喜欢备用路由并在事件接收器对象上实现 IDispatch,然后将接口指针分配给 HTML 元素的 onclick 属性,而不是为具有大量接口的 HTML 元素实现连接点客户端。您将在活动中收到IDispatch::Invoke 电话。

这里有一段代码 sn-p,用于创建合适的 IDispatch 实现实例,并通过 C++ 代码设置 onresize 属性:

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 类是here,您还可以在那里找到完整的示例项目(还有SVN 链接)。

【讨论】:

  • 感谢您的回答。 1. 我最终实施了@IgorTandetnik 的建议,使用HTMLInputTextElementEvents2,它按预期工作。 2. 您指定的示例与我遇到的限制相同:它不处理页面刷新。刷新时,onresize 挂钩丢失,因为 OnExplorer2DocumentComplete 未被调用。
  • 您可能会在 Web 浏览器事件中看到页面刷新(代码中的 DIID_DWebBrowserEvents2 附近)。我会放置跟踪代码来查看所有事件,看看那里是否有任何有用的东西。
  • 我试过了,但想不出任何相关的东西。如此基本的东西没有一个简单的解决方案真是令人沮丧。就我而言,知道复选框何时消失(可能与页面一起消失)就足够了。我已经为此创建了a new question
  • 危险,威尔罗宾逊。当您分配给onclick 属性(或onresize,或类似的)时,您正在与页面上的脚本进行斗争。您的分配可能会覆盖脚本安装的处理程序,从而破坏页面。或者脚本可能会稍后分配其处理程序并覆盖您的处理程序,从而破坏您的 BHO。如果你想走这条路,请使用attachEventaddEventListener 方法——它们可以为同一事件添加多个处理程序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-29
  • 2017-03-31
  • 1970-01-01
相关资源
最近更新 更多