CDHtmlDialog 拦截证书错误

最近碰到一个需求,要嵌入IE浏览器到应用程序中。在开发的过程中,碰到了需要加载HTTPS网站,而该网站的证书无效的问题。

如果是直接用IE浏览器打开的话,虽然也会报错,但至少可以通过“转到此网页(不推荐)”继续访问,而CDHtmlDialog提供的嵌入式IE浏览器,则没有这个操作。

当然,这是一个安全设置,正常来说不应该继续访问,要么提供有效的证书以继续访问。但是我的需求是加载一个已知的站点,需要能正常访问,那这个时候就需要拦截安全报警,忽略掉然后继续访问了。

微软的官方文档翻了一遍,由于英格利希不大行,只找到了需要处理 IHttpSecurity 接口,但是苦于COM和ATL都没学好,根本不知道怎么用,不得不继续bing,最后搜到了蒋晟大佬的一篇文章:Howto: Ignoring web browser certificate errors in a webbrowser host

才有了眉目,当然,大佬的文章用的.NET程序作为例子,我尝试过,确实可以,但我还是想用C++来实现,还好文章后面用C++举了个例,并且说的很清楚了,要实现 IHttpSecurity 接口和暴露INewWindowManager接口是一样的,最终我尝试了一下,完成了这个功能:

可以看到页面上方有一个安全提示,但是已经可以直接打开网页了。

要实现这个功能,就需要重载CDHtmlDialog的CreateControlSite接口,传入自定义的COleControlSite,然后在这个类里,实现 IHttpSecurity 接口,就可以处理 OnSecurityProblem 函数了。

首先是改写 CreateControlSite :

BOOL CWebBrowser::CreateControlSite(COleControlContainer* pContainer, COleControlSite** ppSite, UINT , REFCLSID )
{
	CMyBrowserControlSite *pBrowserSite =
		new CMyBrowserControlSite(pContainer, this);
	if (!pBrowserSite)
		return FALSE;  
	*ppSite = pBrowserSite;
	return TRUE;
}

 这个 CMyBrowserControlSite 就是继承自 COleControlSite ,然后我们需要处理 QueryService 接口,因为WebBrowser插件在创建的过程中,会回调这个接口,其中就包括 IHttpSecurity,接下来就是定义 CMyBrowserControlSite:

class CMyBrowserControlSite : public COleControlSite
{
public:
	CMyBrowserControlSite(COleControlContainer* pCtrlCont, CWebBrowser *pHandler);
	virtual ~CMyBrowserControlSite(void);

protected:
	DECLARE_INTERFACE_MAP()
	BEGIN_INTERFACE_PART(ServiceProvider, IServiceProvider)
		STDMETHOD(QueryService) ( 
		/* [in] */ REFGUID guidService,
		/* [in] */ REFIID riid,
		/* [out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
	END_INTERFACE_PART(ServiceProvider)

	BEGIN_INTERFACE_PART(HttpSecurity, IHttpSecurity)
		STDMETHOD(GetWindow)(
			/* [in] */ REFGUID rguidReason,
			/* [out] */ HWND *phwnd);
		STDMETHOD(OnSecurityProblem)(/* [in] */ DWORD dwProblem);
	END_INTERFACE_PART(HttpSecurity)

protected:
	CWebBrowser* m_pView;
};

由于 IHttpSecurity 继承自 IWindowForBindingUI,而 IWindowForBindingUI 里又有一个虚函数

GetWindow,所以你必须在你的实现里把这些虚函数统统实现。

    IHttpSecurity : public IWindowForBindingUI
    {
    public:
        virtual HRESULT STDMETHODCALLTYPE OnSecurityProblem( 
            /* [in] */ DWORD dwProblem) = 0;
        
    };


    IWindowForBindingUI : public IUnknown
    {
    public:
        virtual HRESULT STDMETHODCALLTYPE GetWindow( 
            /* [in] */ REFGUID rguidReason,
            /* [out] */ HWND *phwnd) = 0;
        
    };

根据微软官方文档所述,这个 GetWindow 就是获取一个窗口句柄给WebBrowser用来作为容器窗口的,说白了就是 CDHtmlDialog 那个窗口,到此就很简单了,直接上代码,把所有接口实现就行了:

BEGIN_INTERFACE_MAP(CMyBrowserControlSite, COleControlSite)
	INTERFACE_PART(CMyBrowserControlSite, IID_IServiceProvider, ServiceProvider)
	INTERFACE_PART(CMyBrowserControlSite, IID_IHttpSecurity, HttpSecurity)
END_INTERFACE_MAP()

CMyBrowserControlSite::CMyBrowserControlSite(COleControlContainer* pCtrlCont, CWebBrowser *pHandler)
	: COleControlSite(pCtrlCont), m_pView(pHandler)
{
}


CMyBrowserControlSite::~CMyBrowserControlSite(void)
{
}

ULONG CMyBrowserControlSite::XServiceProvider::AddRef()
{
	METHOD_PROLOGUE(CMyBrowserControlSite, ServiceProvider);
	return pThis->ExternalAddRef();
}

ULONG CMyBrowserControlSite::XServiceProvider::Release()
{
	METHOD_PROLOGUE(CMyBrowserControlSite, ServiceProvider);
	return pThis->ExternalRelease();
}

HRESULT CMyBrowserControlSite::XServiceProvider::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
	METHOD_PROLOGUE(CMyBrowserControlSite, ServiceProvider);

	return pThis->ExternalQueryInterface(&iid, ppvObj);
}

ULONG CMyBrowserControlSite::XHttpSecurity::AddRef()
{
	METHOD_PROLOGUE(CMyBrowserControlSite, HttpSecurity);
	return pThis->ExternalAddRef();
}

ULONG CMyBrowserControlSite::XHttpSecurity::Release()
{
	METHOD_PROLOGUE(CMyBrowserControlSite, HttpSecurity);
	return pThis->ExternalRelease();
}

HRESULT CMyBrowserControlSite::XHttpSecurity::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
	METHOD_PROLOGUE(CMyBrowserControlSite, HttpSecurity);
	return pThis->ExternalQueryInterface(&iid, ppvObj);
}

HRESULT CMyBrowserControlSite::XHttpSecurity::GetWindow(REFGUID rguidReason, HWND *phwnd)
{
	METHOD_PROLOGUE(CMyBrowserControlSite, HttpSecurity);
	if (rguidReason == IID_IHttpSecurity || rguidReason == IID_IWindowForBindingUI)
	{
		*phwnd = pThis->m_pView->m_hWnd;
		return S_OK;
	}
	else
	{
		*phwnd = nullptr;
		return S_FALSE;
	}
}

HRESULT CMyBrowserControlSite::XHttpSecurity::OnSecurityProblem(DWORD dwProblem)
{
	return S_OK;
}

HRESULT CMyBrowserControlSite::XServiceProvider::QueryService(REFGUID guidService, REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
{
	if (riid == IID_IHttpSecurity || riid == IID_IWindowForBindingUI)
	{
		METHOD_PROLOGUE(CMyBrowserControlSite, ServiceProvider);
		return (HRESULT)pThis->ExternalQueryInterface(&riid, ppvObject);
	}
	ppvObject = nullptr;
	return E_NOINTERFACE;
}

说来惭愧,学了多年的C++,一直没认真学,下回得静下心来好好深入学习学习了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值