I'm writing a BHO using ATL and I'm using DispEventUnadvise
as part of my SetSite
function to disconnect from Internet Explorer.
This is my code:
STDMETHODIMP FooBho::SetSite(IUnknown* site)
{
if (site != nullptr)
{
if( this->webBrowser != nullptr )
{
this->webBrowser.Release();
}
// Cache the pointer to IWebBrowser2.
HRESULT hr = site->QueryInterface(IID_IWebBrowser2, (void**) &this->webBrowser);
ATLENSURE_SUCCEEDED(hr);
// Register event-handler.
hr = DispEventAdvise(this->webBrowser);
ATLENSURE_SUCCEEDED(hr);
this->isAdvised = true;
}
else
{
// Release cached pointers and other resources here.
if( this->isAdvised )
{
HRESULT hr = DispEventUnadvise( this->webBrowser );
ATLENSURE_SUCCEEDED(hr); // This assertion often fails when hr == 0x80040200
this->isAdvised = false;
}
this->webBrowser.Release();
}
// Return the base class implementation
return IObjectWithSiteImpl<FooBho>::SetSite(site);
}
Many times DispEventUnadvise
returns0x80040200
which corresponds to a number of different HRESULTs, but I think it's corresponding to EVENT_E_FIRST
but I'm not sure, the documentation for DispEventUnadvise
doesn't document its error codes.
The failing assert in ATLENSURE_SUCCEEDED
causes my BHO to crash, so I need to remove it, but is it safe to completely disregard the return value from DispEventUnadvise
or should I check for 0x80040200
and otherwise still call ATLENSURE_SUCCEEDED
?
This is my class' header, it includes the Sink Map:
// FooBho.h : Declaration of the CFooBho
#pragma once
#include "resource.h" // main symbols
#include <ShlGuid.h> // IID_IWebBrowser2, DIID_DWebBrowserEvents2, etc.
#include <exdispid.h> // DISPID_DOCUMENTCOMPLETE, etc.
#include <MsHTML.h>
#include "Bho_i.h"
using namespace ATL;
const int DispatchInterface1 = 1;
class ATL_NO_VTABLE FooBho :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<FooBho, &CLSID_FooBho>,
public IObjectWithSiteImpl<FooBho>,
public IDispatchImpl<IFooBho, &IID_IFooBho, &LIBID_BhoLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IDispEventImpl<DispatchInterface1, FooBho, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>
{
private:
CComPtr<IWebBrowser2> webBrowser;
bool isAdvised;
public:
FooBho()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_FOOBHO)
DECLARE_NOT_AGGREGATABLE(FooBho)
BEGIN_COM_MAP(FooBho)
COM_INTERFACE_ENTRY(IFooBho)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IObjectWithSite)
END_COM_MAP()
STDMETHOD(SetSite)(IUnknown *site) override;
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
#pragma region DIID_DWebBrowserEvents2
BEGIN_SINK_MAP(FooBho)
SINK_ENTRY_EX(DispatchInterface1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
END_SINK_MAP()
void STDMETHODCALLTYPE OnDocumentComplete(IDispatch* dispatch, VARIANT* uri);
#pragma endregion
private:
long RemoveImages(IHTMLDocument2* document);
};
OBJECT_ENTRY_AUTO(__uuidof(FooBho), FooBho)
The error code stands for CONNECT_E_NOCONNECTION
, which is presumably returned by internal IConnectionPointContainer::FindConnectionPoint
call. That is, there is no connection point, something is wrong with the sink map, which you did not include.
There are other things wrong in your code snippet. Use of ATLENSURE_SUCCEEDED
is incorrect. It throws exception which you are supposed to catch before returning from COM method.
STDMETHODIMP FooBho::SetSite(IUnknown* site)
{
_ATLTRY
{
// ...
ATLENSURE_SUCCEEDED(...);
// ...
}
_ATLCATCH(Exception)
{
return Exception;
}
return S_OK;
}
Error code safe to ignore would be code telling "you were not advised to Unadvise
".
Try to provide second parameter to DispEventUnadvise pointing to uuid of 'Events' interface, like
HRESULT hr = DispEventUnadvise(this->webBrowser, &DIID_DWebBrowserEvents2);
This way I solved the same problem (with same error code) in CANoe application
User contributions licensed under CC BY-SA 3.0