关于MFC项目中使用WebBrowser控件禁止脚本错误的方法
最近一个项目中要在对话框上使用WebBrowser控件进行页面浏览,但在开发过程中发现WebBrowser控件会在浏览一些页面的时候出现JavaScript脚本错误,严重影响用户体验,而在IE和其他第三方浏览器中均没有这个现象。于是搜索一下发现原来可以通过下面的代码禁止这个错误提示:
- m_WebBrowser.put_Silent(TRUE);//禁止脚本错误提示
效果非常好,可以说立竿见影。但是随之问题又来了,在登录银行网站时会出现无法打开网页的错误,原来这个Silent把银行的选择证书窗口也给禁止了.
翻了翻MSDN,发现原来这个参数要么都不禁止,要么都禁止……这显然不符合要求
搜索引擎真是个好东西,就在准备放弃的时候发现这么一篇文章 CDHtmlDialog探索----WebBrowser扩展和网页Javascript错误处理 作者:thinkingfor
这会儿真想对着thinkingfor鞠一个大大的躬,真的。
因为一直都搞不懂COM这个东西,所以就抱着试试看的想法把thinkingfor的代码加进工程一编译,除了少数头文件等改动以外,完美运行。
为了备忘也希望能给遇到相同问题的人一点帮助,故将编译通过的代码列出,环境vs2008 + xp
代码如下:
- CMyControlSite.h
- #pragma once
- #include "afxocc.h"
- #include "Mshtml.h"//应该加入这个头文件
- #include "Mshtmhst.h"//这个也是
- class CMyControlSite :public COleControlSite
- {
- public:
- CMyControlSite(COleControlContainer *pCntr):COleControlSite(pCntr) {}
- ~CMyControlSite(void);
- protected:
- DECLARE_INTERFACE_MAP()
- BEGIN_INTERFACE_PART(OleCommandTarget, IOleCommandTarget)
- STDMETHOD(QueryStatus)(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText);
- STDMETHOD(Exec)(const GUID* pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG* pvaIn, VARIANTARG* pvaOut);
- END_INTERFACE_PART(OleCommandTarget)
- };
- CMyControlSite.cpp
- #include "StdAfx.h"
- #include "MyControlSite.h"
- BEGIN_INTERFACE_MAP(CMyControlSite, COleControlSite)
- INTERFACE_PART(CMyControlSite, IID_IOleCommandTarget, OleCommandTarget)
- END_INTERFACE_MAP()
- CMyControlSite::~CMyControlSite(void)
- {
- }
- HRESULT CMyControlSite::XOleCommandTarget::Exec
- (const GUID* pguidCmdGroup, DWORD nCmdID,
- DWORD nCmdexecopt, VARIANTARG* pvaIn, VARIANTARG* pvaOut )
- {
- HRESULT hr = OLECMDERR_E_NOTSUPPORTED;
- //return S_OK;
- if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_DocHostCommandHandler))
- {
- switch (nCmdID)
- {
- case OLECMDID_SHOWSCRIPTERROR:
- {
- IHTMLDocument2* pDoc = NULL;
- IHTMLWindow2* pWindow = NULL;
- IHTMLEventObj* pEventObj = NULL;
- BSTR rgwszNames[5] =
- {
- SysAllocString(L"errLine"),
- SysAllocString(L"errCharacter"),
- SysAllocString(L"errCode"),
- SysAllocString(L"errMsg"),
- SysAllocString(L"errUrl")
- };
- DISPID rgDispIDs[5];
- VARIANT rgvaEventInfo[5];
- DISPPARAMS params;
- BOOL fContinueRunningScripts = false; //修改此处为false禁止脚本错误提示
- params.cArgs = 0;
- params.cNamedArgs = 0;
- hr = pvaIn->punkVal->QueryInterface(IID_IHTMLDocument2, (void **) &pDoc);
- hr = pDoc->get_parentWindow(&pWindow);
- pDoc->Release();
- hr = pWindow->get_event(&pEventObj);
- for (int i = 0; i < 5; i++)
- {
- hr = pEventObj->GetIDsOfNames(IID_NULL, &rgwszNames[i], 1,
- LOCALE_SYSTEM_DEFAULT, &rgDispIDs[i]);
- hr = pEventObj->Invoke(rgDispIDs[i], IID_NULL,
- LOCALE_SYSTEM_DEFAULT,
- DISPATCH_PROPERTYGET, ¶ms, &rgvaEventInfo[i],
- NULL, NULL);
- //可以在此记录错误信息 //必须使用SysFreeString来释放SysAllocString分配的内存,SysAllocString在分配的内存中记录了字符的长度
- SysFreeString(rgwszNames[i]);
- }
- // At this point, you would normally alert the user with
- // the information about the error, which is now contained
- // in rgvaEventInfo[]. Or, you could just exit silently.
- (*pvaOut).vt = VT_BOOL;
- if (fContinueRunningScripts)
- {
- // 在页面中继续执行脚本
- (*pvaOut).boolVal = VARIANT_TRUE;
- }
- else
- {
- // 停止在页面中执行脚本
- (*pvaOut).boolVal = VARIANT_FALSE;
- }
- break;
- }
- default:
- hr =OLECMDERR_E_NOTSUPPORTED;
- break;
- }
- }
- else
- {
- hr = OLECMDERR_E_UNKNOWNGROUP;
- }
- return (hr);
- }
- ULONG FAR EXPORT CMyControlSite::XOleCommandTarget::AddRef()
- {
- METHOD_PROLOGUE(CMyControlSite, OleCommandTarget)
- return pThis->ExternalAddRef();
- }
- ULONG FAR EXPORT CMyControlSite::XOleCommandTarget::Release()
- {
- METHOD_PROLOGUE(CMyControlSite, OleCommandTarget)
- return pThis->ExternalRelease();
- }
- HRESULT FAR EXPORT CMyControlSite::XOleCommandTarget::QueryInterface(REFIID riid, void **ppvObj)
- {
- METHOD_PROLOGUE(CMyControlSite, OleCommandTarget)
- HRESULT hr = (HRESULT)pThis->ExternalQueryInterface(&riid, ppvObj);
- return hr;
- }
- STDMETHODIMP CMyControlSite::XOleCommandTarget::QueryStatus(
- /* [unique][in] */ const GUID __RPC_FAR *pguidCmdGroup,
- /* [in] */ ULONG cCmds,
- /* [out][in][size_is] */ OLECMD __RPC_FAR prgCmds[ ],
- /* [unique][out][in] */ OLECMDTEXT __RPC_FAR *pCmdText
- )
- {
- METHOD_PROLOGUE(CMyControlSite, OleCommandTarget)
- return OLECMDERR_E_NOTSUPPORTED;
- }
对话框头文件加入声明:
- virtual BOOL CreateControlSite(COleControlContainer* pContainer,
- COleControlSite** ppSite, UINT nID , REFCLSID clsid );
对应源文件:
- BOOL CXDlg::CreateControlSite(COleControlContainer* pContainer,
- COleControlSite** ppSite, UINT nID , REFCLSID clsid )
- {
- if(ppSite == NULL)
- {
- ASSERT(FALSE);
- return FALSE;
- }
- CMyControlSite *pBrowserSite =
- new CMyControlSite (pContainer);//
- if (!pBrowserSite)
- return FALSE;
- *ppSite = pBrowserSite;
- return TRUE;
- }
此外,thinkingfor原文中为CDHtmlDialog,同样适用于CDialog.
再次感谢thinkingfor