关于MFC项目中使用WebBrowser控件禁止脚本错误的方法 .
最近一个项目中要在对话框上使用WebBrowser控件进行页面浏览,但在开发过程中发现WebBrowser控件会在浏览一些页面的时候出现JavaScript脚本错误,严重影响用户体验,而在IE和其他第三方浏览器中均没有这个现象。于是搜索一下发现原来可以通过下面的代码禁止这个错误提示:
- m_WebBrowser.put_Silent(TRUE);//禁止脚本错误提示
m_WebBrowser.put_Silent(TRUE);//禁止脚本错误提示
效果非常好,可以说立竿见影。但是随之问题又来了,在登录银行网站时会出现无法打开网页的错误,原来这个Silent把银行的选择证书窗口也给禁止了.
翻了翻MSDN,发现原来这个参数要么都不禁止,要么都禁止……这显然不符合要求
搜索引擎真是个好东西,就在准备放弃的时候发现这么一篇文章 CDHtmlDialog探索----WebBrowser扩展和网页Javascript错误处理 作者:thinkingfor
这会儿真想对着thinkingfor鞠一个大大的躬,真的。
因为一直都搞不懂COM这个东西,所以就抱着试试看的想法把thinkingfor的代码加进工程一编译,除了少数头文件等改动以外,完美运行。
为了备忘也希望能给遇到相同问题的人一点帮助,故将编译通过的代码列出,环境vs2008 + xp
代码如下:
01.CMyControlSite.h CMyControlSite.h[cpp] view plaincopyprint? 01.#pragma once 02.#include "afxocc.h" 03.#include "Mshtml.h"//应该加入这个头文件 04.#include "Mshtmhst.h"//这个也是 05.class CMyControlSite :public COleControlSite 06.{ 07.public: 08. CMyControlSite(COleControlContainer *pCntr):COleControlSite(pCntr) {} 09. ~CMyControlSite(void); 10.protected: 11. DECLARE_INTERFACE_MAP() 12. BEGIN_INTERFACE_PART(OleCommandTarget, IOleCommandTarget) 13. STDMETHOD(QueryStatus)(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText); 14. STDMETHOD(Exec)(const GUID* pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG* pvaIn, VARIANTARG* pvaOut); 15. END_INTERFACE_PART(OleCommandTarget) 16.};
01.CMyControlSite.cpp CMyControlSite.cpp[cpp] view plaincopyprint? 01.#include "StdAfx.h" 02.#include "MyControlSite.h" 03. 04. 05.BEGIN_INTERFACE_MAP(CMyControlSite, COleControlSite) 06. INTERFACE_PART(CMyControlSite, IID_IOleCommandTarget, OleCommandTarget) 07.END_INTERFACE_MAP() 08. 09. 10. 11.CMyControlSite::~CMyControlSite(void) 12.{ 13.} 14. 15.HRESULT CMyControlSite::XOleCommandTarget::Exec 16.(const GUID* pguidCmdGroup, DWORD nCmdID, 17. DWORD nCmdexecopt, VARIANTARG* pvaIn, VARIANTARG* pvaOut ) 18.{ 19. HRESULT hr = OLECMDERR_E_NOTSUPPORTED; 20. //return S_OK; 21. if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_DocHostCommandHandler)) 22. { 23. 24. switch (nCmdID) 25. { 26. 27. case OLECMDID_SHOWSCRIPTERROR: 28. { 29. IHTMLDocument2* pDoc = NULL; 30. IHTMLWindow2* pWindow = NULL; 31. IHTMLEventObj* pEventObj = NULL; 32. BSTR rgwszNames[5] = 33. { 34. SysAllocString(L"errLine"), 35. SysAllocString(L"errCharacter"), 36. SysAllocString(L"errCode"), 37. SysAllocString(L"errMsg"), 38. SysAllocString(L"errUrl") 39. }; 40. DISPID rgDispIDs[5]; 41. VARIANT rgvaEventInfo[5]; 42. DISPPARAMS params; 43. BOOL fContinueRunningScripts = false; //修改此处为false禁止脚本错误提示 44. 45. params.cArgs = 0; 46. params.cNamedArgs = 0; 47. 48. hr = pvaIn->punkVal->QueryInterface(IID_IHTMLDocument2, (void **) &pDoc); 49. 50. hr = pDoc->get_parentWindow(&pWindow); 51. pDoc->Release(); 52. 53. hr = pWindow->get_event(&pEventObj); 54. 55. for (int i = 0; i < 5; i++) 56. { 57. 58. hr = pEventObj->GetIDsOfNames(IID_NULL, &rgwszNames[i], 1, 59. LOCALE_SYSTEM_DEFAULT, &rgDispIDs[i]); 60. 61. hr = pEventObj->Invoke(rgDispIDs[i], IID_NULL, 62. LOCALE_SYSTEM_DEFAULT, 63. DISPATCH_PROPERTYGET, ¶ms, &rgvaEventInfo[i], 64. NULL, NULL); 65. //可以在此记录错误信息 //必须使用SysFreeString来释放SysAllocString分配的内存,SysAllocString在分配的内存中记录了字符的长度 66. SysFreeString(rgwszNames[i]); 67. } 68. 69. // At this point, you would normally alert the user with 70. // the information about the error, which is now contained 71. // in rgvaEventInfo[]. Or, you could just exit silently. 72. 73. (*pvaOut).vt = VT_BOOL; 74. if (fContinueRunningScripts) 75. { 76. // 在页面中继续执行脚本 77. (*pvaOut).boolVal = VARIANT_TRUE; 78. } 79. else 80. { 81. // 停止在页面中执行脚本 82. (*pvaOut).boolVal = VARIANT_FALSE; 83. } 84. break; 85. } 86. default: 87. hr =OLECMDERR_E_NOTSUPPORTED; 88. break; 89. } 90. } 91. else 92. { 93. hr = OLECMDERR_E_UNKNOWNGROUP; 94. } 95. return (hr); 96.} 97. 98. 99.ULONG FAR EXPORT CMyControlSite::XOleCommandTarget::AddRef() 100.{ 101. METHOD_PROLOGUE(CMyControlSite, OleCommandTarget) 102. return pThis->ExternalAddRef(); 103.} 104. 105. 106.ULONG FAR EXPORT CMyControlSite::XOleCommandTarget::Release() 107.{ 108. METHOD_PROLOGUE(CMyControlSite, OleCommandTarget) 109. return pThis->ExternalRelease(); 110.} 111. 112.HRESULT FAR EXPORT CMyControlSite::XOleCommandTarget::QueryInterface(REFIID riid, void **ppvObj) 113.{ 114. METHOD_PROLOGUE(CMyControlSite, OleCommandTarget) 115. HRESULT hr = (HRESULT)pThis->ExternalQueryInterface(&riid, ppvObj); 116. return hr; 117.} 118. 119.STDMETHODIMP CMyControlSite::XOleCommandTarget::QueryStatus( 120. /* [unique][in] */ const GUID __RPC_FAR *pguidCmdGroup, 121. /* [in] */ ULONG cCmds, 122. /* [out][in][size_is] */ OLECMD __RPC_FAR prgCmds[ ], 123. /* [unique][out][in] */ OLECMDTEXT __RPC_FAR *pCmdText 124. ) 125.{ 126. METHOD_PROLOGUE(CMyControlSite, OleCommandTarget) 127. return OLECMDERR_E_NOTSUPPORTED; 128.}
对话框头文件加入声明
01.virtual BOOL CreateControlSite(COleControlContainer* pContainer, 02. COleControlSite** ppSite, UINT nID , REFCLSID clsid );
对应源文件
01.BOOL CXDlg::CreateControlSite(COleControlContainer* pContainer, 02. COleControlSite** ppSite, UINT nID , REFCLSID clsid ) 03.{ 04. if(ppSite == NULL) 05. { 06. ASSERT(FALSE); 07. return FALSE; 08. } 09. 10. CMyControlSite *pBrowserSite = 11. new CMyControlSite (pContainer);// 12. if (!pBrowserSite) 13. return FALSE; 14. 15. *ppSite = pBrowserSite; 16. return TRUE; 17.}
CDhtmlDialog同样也适用于CDialog