JavaScript在ATL C ++ BHO中发布消息事件处理程序 [英] Javascript post message event handler in 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屋!