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 : 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 : 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:
#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:
#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;
}