ATL C++ BHO 中的 Javascript 发布消息事件处理程序 [英] Javascript post message event handler in ATL C++ BHO

查看:34
本文介绍了ATL C++ BHO 中的 Javascript 发布消息事件处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在网页上,我有一个带有 JavaScript 帖子消息的按钮.在我的 BHO IE 附加组件中,我需要一个用于此消息事件的事件侦听器.任何线索如何做到这一点?我的 OnDocumentComplete 如下.您能否提供更多指示,我们可以在哪些地方编写处理此事件的代码.我想从此消息处理程序进行 REST API 调用.

On a webpage I have a button with JavaScript post message. In my BHO IE add-on I need an event listener for this message event. Any clue how this can be done? My OnDocumentComplete is as below. Can you give some more pointers where we can write code for handling this event. I want to make a REST API call from this message handler.

TestScript.h:

TestScript.h:

// TestScript.h : Declaration of the CTestScript

#pragma once
#include "resource.h"       // main symbols
#include "TestBHO_i.h"
#include <mshtml.h>         // DOM interfaces

#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
#endif

// CTestScript

class ATL_NO_VTABLE CTestScript :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CTestScript, &CLSID_TestScript>,
    public IObjectWithSiteImpl<CTestScript>,
    public IDispatchImpl<ITestScript, &IID_ITestScript, &LIBID_TestBHOLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
    public IDispEventImpl<1, CTestScript, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>,
    //public IPersistPropertyBagImpl<CTestScript>,
    public IObjectSafetyImpl<CTestScript, INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA>
{
public:
    CTestScript()
    {
    }

DECLARE_REGISTRY_RESOURCEID(IDR_TESTSCRIPT)

DECLARE_NOT_AGGREGATABLE(CTestScript)

BEGIN_COM_MAP(CTestScript)
    COM_INTERFACE_ENTRY(ITestScript)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(IObjectWithSite)
END_COM_MAP()

DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease()
    {
    }

public:
    BEGIN_SINK_MAP(CTestScript)
        SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
        //SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, OnNavigationComplete)
    END_SINK_MAP()

    void STDMETHODCALLTYPE OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL);
    //void STDMETHODCALLTYPE OnNavigationComplete(IDispatch *pDisp, VARIANT *pvarURL);

    STDMETHOD(SetSite)(IUnknown *pUnkSite);

    HRESULT STDMETHODCALLTYPE DoSomething(){
        ::MessageBox(NULL, L"Hello", L"World", MB_OK);
        return S_OK;
    }
public:

//private:
    // InstallBHOMethod();
private:
    void EnableOpenOnDesktopButton(IHTMLDocument2 *pDocument);

private:
    void AddPostMessage(IHTMLDocument2 *pDocument); 

private:
    CComPtr<IWebBrowser2>  m_spWebBrowser;
    BOOL m_fAdvised;
};

OBJECT_ENTRY_AUTO(__uuidof(TestScript), CTestScript)

TestScript.cpp:

TestScript.cpp:

// TestScript.cpp : Implementation of CTestScript

#include "stdafx.h"
#include "TestScript.h"

// CTestScript

void debug(LPWSTR msg)
{
    ::MessageBox(NULL,msg,L"Debug",MB_OK);;
}

STDMETHODIMP CTestScript::SetSite(IUnknown* pUnkSite)
{
    if (pUnkSite != NULL)
    {
        // Cache the pointer to IWebBrowser2.
        HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser);
        if (SUCCEEDED(hr))
        {
            // Register to sink events from DWebBrowserEvents2.
            hr = DispEventAdvise(m_spWebBrowser);
            if (SUCCEEDED(hr))
            {
                m_fAdvised = TRUE;
            }
        }
    }
    else
    {
        // Unregister event sink.
        if (m_fAdvised)
        {
            DispEventUnadvise(m_spWebBrowser);
            m_fAdvised = FALSE;
        }

        // Release cached pointers and other resources here.
        m_spWebBrowser.Release();
    }

    // Call base class implementation.
    return IObjectWithSiteImpl<CTestScript>::SetSite(pUnkSite);
}

void STDMETHODCALLTYPE CTestScript::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
{
    HRESULT hr = S_OK;

    // Query for the IWebBrowser2 interface.
    CComQIPtr<IWebBrowser2> spTempWebBrowser = pDisp;
    //CComPtr<IEventTarget> spIEventTarget;
    // Is this event associated with the top-level browser?
    if (spTempWebBrowser && m_spWebBrowser &&
        m_spWebBrowser.IsEqualObject(spTempWebBrowser))
    {
        // Get the current document object from browser...
        CComPtr<IDispatch> spDispDoc;
        hr = m_spWebBrowser->get_Document(&spDispDoc);
        if (SUCCEEDED(hr))
        {
            // ...and query for an HTML document.
            CComQIPtr<IHTMLDocument2> spHTMLDoc = spDispDoc;
            if (spHTMLDoc != NULL)
            {
              EnableOpenOnDesktopButton(spHTMLDoc);
              AddPostMessage(spHTMLDoc) ;
            }
        }
    }
}


void CTestScript::EnableOpenOnDesktopButton(IHTMLDocument2* pDocument)
{
    CComPtr<IHTMLElement> bodypt;
    CComPtr<IHTMLElement> html;
    pDocument->get_body(&bodypt);
    bodypt->get_parentElement(&html);
    //TODO: concatinate old class and new class and apply toht
    BSTR className = L" my-browser-extension";
    html->put_className(className);
}


void CTestScript::AddPostMessage(IHTMLDocument2* pDocument)
{
    HRESULT hr = S_OK;
    CComPtr<IHTMLWindow2>  _spWindow;
    hr = pDocument->get_parentWindow(reinterpret_cast<IHTMLWindow2 **>(&_spWindow));
    if (SUCCEEDED(hr) && _spWindow)
    {
        CComPtr<IEventTarget> spIEventTarget;
        hr = _spWindow->QueryInterface(IID_IEventTarget, reinterpret_cast<void **>(&spIEventTarget));
        if (SUCCEEDED(hr) && spIEventTarget)
        {
            _pIEUIEventListener = new CIEUIEventListener(); // This class derives from IDispatch
            hr = spIEventTarget->addEventListener(_bstr_t("message"), _pIEUIEventListener,  VARIANT_TRUE);
            if (SUCCEEDED(hr))
            {
                debug(L"HEREE");
            }
        }
    }
}

IEUIEventListener.h:

IEUIEventListener.h:

#pragma once

class CIEUIEventListener : public IDispatchEx 
{
public:
    CIEUIEventListener(void);
    ~CIEUIEventListener(void);

    HRESULT STDMETHODCALLTYPE Invoke(       
    DISPID dispIdMember,
    REFIID riid,
    LCID lcid,
    WORD wFlags,
    DISPPARAMS *pDispParams,
    VARIANT *pVarResult,
    EXCEPINFO *pExcepInfo,
    UINT *puArgErr);
};

IEUIEventListener.cpp:

IEUIEventListener.cpp:

#include "StdAfx.h"
#include "IEUIEventListener.h"

CIEUIEventListener::CIEUIEventListener(void)
{
}

CIEUIEventListener::~CIEUIEventListener(void)
{
}
HRESULT STDMETHODCALLTYPE CIEUIEventListener::Invoke(   
    DISPID dispIdMember,
    REFIID riid,
    LCID lcid,
    WORD wFlags,
    DISPPARAMS *pDispParams,
    VARIANT *pVarResult,
    EXCEPINFO *pExcepInfo,
    UINT *puArgErr)
{       
    ::MessageBox(NULL,L"FYYYYYYYY",L"Debug",MB_OK);;
    return S_OK;
}

推荐答案

如果你的意思是 window.postMessage,你需要为 DOM window 对象上的 message 事件添加一个监听器(window.addEventListener("message")) 来自您的 BHO.要获取window 对象,请使用IWebBrowser2::get_DocumentIHTMLDocument2::get_parentWindow,然后查询windowIEventTarget 并调用 addEventListener.给它一个 IDispatch 的实现作为 listener 参数.发布消息时,它将作为 IDispatch::Invoke(DISPID_VALUE) 回调.

If you mean window.postMessage, you'd need to add a listener for message event on DOM window object (window.addEventListener("message")) from your BHO. To get the window object, use IWebBrowser2::get_Document, IHTMLDocument2::get_parentWindow, then query the window for IEventTarget and call addEventListener. Give it an implementation of IDispatch as listener parameter. It will be called back as IDispatch::Invoke(DISPID_VALUE) when a message is posted.

[已编辑] 此更新基于您发布的更新代码.我不知道为什么 IEventTarget 仍未为您定义(也许,您的 Visual Studio 包含路径配置有问题).所以,只需从这里获取定义:

This update is based upon the updated code you posted. I can't tell why IEventTarget is still undefined for you (perhaps, there's a problem with your Visual Studio include path configuration). So, just grab the definitions from here:

MIDL_INTERFACE("305104b9-98b5-11cf-bb82-00aa00bdce0b")
IEventTarget : public IDispatch
{
public:
    virtual /* [id] */ HRESULT STDMETHODCALLTYPE addEventListener( 
        /* [in] */ __RPC__in BSTR type,
        /* [in] */ __RPC__in_opt IDispatch *listener,
        /* [in] */ VARIANT_BOOL useCapture) = 0;

    virtual /* [id] */ HRESULT STDMETHODCALLTYPE removeEventListener( 
        /* [in] */ __RPC__in BSTR type,
        /* [in] */ __RPC__in_opt IDispatch *listener,
        /* [in] */ VARIANT_BOOL useCapture) = 0;

    virtual /* [id] */ HRESULT STDMETHODCALLTYPE dispatchEvent( 
        /* [in] */ __RPC__in_opt IDOMEvent *evt,
        /* [out][retval] */ __RPC__out VARIANT_BOOL *pfResult) = 0;

};

MIDL_INTERFACE("305104ba-98b5-11cf-bb82-00aa00bdce0b")
IDOMEvent : public IDispatch
{
public:
    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_bubbles( 
        /* [out][retval] */ __RPC__out VARIANT_BOOL *p) = 0;

    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_cancelable( 
        /* [out][retval] */ __RPC__out VARIANT_BOOL *p) = 0;

    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_currentTarget( 
        /* [out][retval] */ __RPC__deref_out_opt IEventTarget **p) = 0;

    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_defaultPrevented( 
        /* [out][retval] */ __RPC__out VARIANT_BOOL *p) = 0;

    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_eventPhase( 
        /* [out][retval] */ __RPC__out USHORT *p) = 0;

    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_target( 
        /* [out][retval] */ __RPC__deref_out_opt IEventTarget **p) = 0;

    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_timeStamp( 
        /* [out][retval] */ __RPC__out ULONGLONG *p) = 0;

    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_type( 
        /* [out][retval] */ __RPC__deref_out_opt BSTR *p) = 0;

    virtual /* [id] */ HRESULT STDMETHODCALLTYPE initEvent( 
        /* [in] */ __RPC__in BSTR eventType,
        /* [in] */ VARIANT_BOOL canBubble,
        /* [in] */ VARIANT_BOOL cancelable) = 0;

    virtual /* [id] */ HRESULT STDMETHODCALLTYPE preventDefault( void) = 0;

    virtual /* [id] */ HRESULT STDMETHODCALLTYPE stopPropagation( void) = 0;

    virtual /* [id] */ HRESULT STDMETHODCALLTYPE stopImmediatePropagation( void) = 0;

    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_isTrusted( 
        /* [out][retval] */ __RPC__out VARIANT_BOOL *p) = 0;

    virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_cancelBubble( 
        /* [in] */ VARIANT_BOOL v) = 0;

    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_cancelBubble( 
        /* [out][retval] */ __RPC__out VARIANT_BOOL *p) = 0;

    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_srcElement( 
        /* [out][retval] */ __RPC__deref_out_opt IHTMLElement **p) = 0;

};

接下来,您的 CIEUIEventListener 看起来不像 COM 对象实现.我没有看到任何 IUnknownIDispatch 方法,也许你只是没有显示它.您也不必从 IDispatchEx 派生,IDispatch 就足够了.我建议您以 DOM 事件接收器的以下实现为基础,这是不言自明的:

Next, your CIEUIEventListener doesn't look a like a COM object implementation. I don't see any IUnknown and IDispatch methods, perhaps you just didn't show it. You don't have to derive from IDispatchEx either, IDispatch is enough. I suggest you take the following implementation of DOM event sink as a base, it's self-explanatory:

// Usage:
//
// CComPtr<CEventSink> eventSink;
// CEventSink::Create(pTestScript, &eventSink); // pass eventSink where IDispatch* is expected
//

class CEventSink: 
    public CComObjectRoot,
    public IDispatch
{
protected:
    CTestScript* m_pParent;

    CEventSink() { m_pParent = NULL; }

public:
    BEGIN_COM_MAP(CEventSink)
        COM_INTERFACE_ENTRY(IDispatch)
    END_COM_MAP()

    // create and initialize
    static HRESULT Create(CTestScript* pParent, CEventSink** pp)
    {
        CComObject<CEventSink>* pThis = NULL;
        CComObject<CEventSink>::CreateInstance(&pThis);
        if (!pThis) 
            return E_OUTOFMEMORY;

        pThis->m_pParent = pParent;

        (*pp = pThis)->AddRef();
        return S_OK;
    }

    // IDispatch
    STDMETHODIMP GetTypeInfoCount(UINT* pctinfo)
    {
        return E_NOTIMPL; 
    }

    STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
    {
        return E_NOTIMPL; 
    }

    STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
    {
        return DISP_E_UNKNOWNNAME;
    }

    STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
    {
        if ( dispidMember == DISPID_VALUE )
        {
            // handle the event
            // for example, call some method on m_pParent
        }
        return DISP_E_MEMBERNOTFOUND;
    }
};

这篇关于ATL C++ BHO 中的 Javascript 发布消息事件处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆