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

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

问题描述

在网页上,我有一个带有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.addEventListener(message ))。要获取窗口对象,请使用 IWebBrowser2 :: get_Document IHTMLDocument2 :: get_parentWindow 然后查询并调用 addEventListener 。给它一个 IDispatch 作为监听器参数的实现。当邮件发布时,它将作为 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对象的实现。我没有看到任何 IUnknown IDispatch 方法,也许你没有显示。您不必从 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;
    }
};

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

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