WebBrowser或CHtmlView中屏蔽脚本错误

WebBrowser或CHtmlView中屏蔽脚本错误



━━━━━━━━━━━━━━━━━━━━━━━━

1、我如今的方法是在void CMyHtmlView::OnInitialUpdate()中添加SetSilent(true);
    而且要设置IE的高级选项,方法以下:
    禁用脚本调试
    若是错误消息是问题的惟一症状,而且网站正在运行,则能够忽略此错误。另外,
    若是此问题仅在一个或两个网页上发生,则多是这些网页的问题。若是您决定忽略该错误,则能够禁用脚本调试。
    注意:若是此问题不仅在一个或两个站点上发生,请不要禁用脚本调试。如今请转到方法 2。
    要在 Internet Explorer 6 中关闭脚本调试程序,请按照下列步骤操做:
    1.在“工具”菜单上,单击“Internet 选项”。
    2.在“高级”选项卡上,单击以选中“禁用脚本调试”复选框,而后单击“肯定”。
    注:请参考HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Internet   Explorer/AdvancedOptions/BROWSE/SCRIPT_DEBUGGER
━━━━━━━━━━━━━━━━━━━━━━━━
2、如下方法来自网络:

转自:http://www.cnblogs.com/zhangqingping/archive/2009/06/16/1504260.html

WebBrowser或CHtmlView中轻松屏蔽脚本错误(JavaScript)

 
1.什么是javascript脚本错误
1.1    概述
    JavaScript脚本错误包含“运行时错误”和“语法错误”。
1.2    JavaScript“语法错误”
    JavaScript语法错误是指当 JavaScript语句违反了 JavaScript脚本语言的一条或多条语法规则时致使的错误。JavaScript语法错误发生在程序编译阶段,在开始运行该程序以前。
1.3    JavaScript“运行时错误”
    JavaScript运行时错误是指当 JavaScript脚本试图执行一个系统不能运行的动做时致使的错误。当正在运行脚本、计算变量表达式、或者正在动态分配内存时出现 JavaScript运行时错误时。
2.    为何要屏蔽javascript脚本错误?
    因为开发海纳产品时,使用WebBrowser和CHtmlView来展现页面,进行填表等操做;可是因为打开的页面大可能是其余用户的CMS页面,因此不免有些有脚本错误,因而决定要来屏蔽脚本错误,提高产品的易用性和友好性。
3.    怎么去屏蔽javascript脚本错误?
3.1    使用SetSilent函数
    使用WebBrowser或CHtmlView的SetSilent函数能够达到屏蔽脚本错误的目的,不过这种状况,其它提示信息也都不显示了,例如使用alert进行的错误提示。
    若是你以为这样能知足你,那么推荐使用这种方法,简单啊!
3.2    重载IOleCommandTarget的Exec函数

网上比较多资料都是说重载IOleCommandTarget中的Exec函数来进行屏蔽脚本错,定义以下:

HRESULT  Exec( const GUID* pguidCmdGroup, DWORD nCmdID,

      DWORD nCmdexecopt, VARIANTARG* pvaIn, VARIANTARG* pvaOut )

  而后经过判断nCmdID是否等于OLECMDID_SHOWSCRIPTERROR(即报javascript脚本错误)来进行屏蔽;因为本人对COM 和OLE的知识有限,琢磨了半天也没有想到怎么实现IOleCommandTarget接口中的Exec函数,而后跟个人WebBrowser或是 HtmlView挂钩起来,因而决定放弃这种方法,有兴趣的朋友能够查看参考资料的文章继续尝试一下。
3.3    另外一种方法

不死心,继续在网上找,忽然发现了一篇文章,介绍在html页面中,可使用javascript的事件来进行javascript脚本错误的屏蔽,因而拷贝下来尝试,果真有用(即便IE浏览器设置了脚本调试,也不会进行提示),经改造的代码以下:

 javascript


<html>
<head>
<script type="text/javascript" >

function fnObjNotDefine(){
    domethod();
}

function fnOnError(msg,url,lineno){
    <!--
    alert("window.onerror/n/n" +
    "Error: " + msg + "/n" +
    "URL:  " + url + "/n" +
    "Line:  " + lineno);
    return true; -->
}
window.onerror = fnOnError;
MethodName.badcommand();

function fnOnLoad(){
    alert("on load!");
}
</script>
</head>
<body οnlοad="fnOnLoad();">
<input type="button" value="function not defined" οnclick="badcommand();">
<input type="button" value="object not defined" οnclick="fnObjNotDefine();">
</body>
</html>


经过查看javascript代码,发现是“重载”了window.onerror这个事件,只要它返回true,脚本错误就不显示了,估计这个就是 Microsoft本身实现的截取javascript脚本错误信息的接口,因而就想怎么把它插入到页面当中,其中有篇文章介绍说在 OnDocumentComplete时来实现javascript的插入,经实践,这种方法是不行的;通过本人的不断尝试,发如今 OnNavigateComplete2或OnNavigateComplete里实现javascript的注入是可行的,这两个函数只要实现一个就行,就看你用的是Navigate2仍是Navigate来打开页面了。这里使用Navigate2来作例子,具体代码以下:
 
注:记得包含头文件#include <Atlbase.h>不然编译通不过
php

void CMyWebBrowser::OnNavigateComplete2(LPCTSTR strURL)
{
    CComPtr<IDispatch>   spDisp   =   GetHtmlDocument();
    if(spDisp   !=   NULL)
    {
        CComPtr<IHTMLDocument2> doc;
        spDisp->QueryInterface(IID_IHTMLDocument2, reinterpret_cast<void**>(&doc));
        if(doc != NULL)
        {  
            IHTMLWindow2 * pIhtmlwindow2 = NULL;
            doc->get_parentWindow(&pIhtmlwindow2);
            if(pIhtmlwindow2 != NULL)
            {
                //屏蔽javascript脚本错误的javascript脚本
                CString strJavaScriptCode = "function fnOnError(msg,url,lineno){alert('script error://n//nURL:'+url+'//n//nMSG:'+msg +'//n//nLine:'+lineno);return true;}window.οnerrοr=fnOnError;";
                BSTR bstrScript = strJavaScriptCode.AllocSysString();
                CString strLanguage("JavaScript");
                BSTR bstrLanguage = strLanguage.AllocSysString();
                long lTime = 1 * 1000;
                long lTimeID = 0;
                VARIANT varLanguage;
                varLanguage.vt = VT_BSTR;
                varLanguage.bstrVal = bstrLanguage;
                VARIANT pRet;
                //把window.onerror函数插入入当前页面中去
                pIhtmlwindow2->execScript(bstrScript, bstrLanguage, &pRet);
                ::SysFreeString(bstrScript);
                ::SysFreeString(bstrLanguage);
                pIhtmlwindow2->Release();
            }
        }
    }
}



其中,CMyWebBrowser是我本身继承了CHtmlView类的一个实现类,这个函数能够在你的WebBrowser2或继承了CHtmlView类中实现,编写一个带有脚本错误的页面,打开进行浏览,是否是发现脚本错误被屏蔽了? 哈哈,实现起来也不麻烦。因而就把这个方法贴出来,供你们参考。
另:经测试,发现若是存在iframe嵌套的时候,嵌套的iframe中包含脚本错误,以上方法是不能屏蔽iframe中的脚本错误的,由于 window.onerror只针对当前页面有效,所以须要在OnNavigateComplete2函数里加上对当前页面进行递归全部子页面,而后重复执行execScript操做便可。

最终代码为:
html

void CMyWebBrowser::OnNavigateComplete2(LPCTSTR strURL)
{
       CComPtr<IDispatch>   spDisp   =   GetHtmlDocument();
       if(spDisp   !=   NULL)
       {
              CComPtr<IHTMLDocument2> doc;
              spDisp->QueryInterface(IID_IHTMLDocument2, reinterpret_cast<void**>(&doc));
              if(doc != NULL)
              {  
                     CScriptErrHandler scriptHandler;
                     scriptHandler.ShieldCurrPage(doc);
                     scriptHandler.ShieldAllChildPages(doc);
              }
       }
}
ScriptErrHandler.cpp文件:
#include "StdAfx.h"
#include "ScriptErrHandler.h"
CScriptErrHandler::CScriptErrHandler(void)
{
       CString strJavaScriptCode = "function fnOnError(msg,url,lineno){alert('script error://n//nURL:'+url"
              "+'//n//nMSG:'+msg +'//n//nLine:'+lineno+'//n//nframes:' + window.frames.length);return true;}window.οnerrοr=fnOnError;";
       //屏蔽的脚本,能够改进为从文本里读取
       m_bstrScript = strJavaScriptCode.AllocSysString();
}
CScriptErrHandler::~CScriptErrHandler(void)
{
       SysFreeString(m_bstrScript);
}
void CScriptErrHandler::ShieldCurrPage(CComPtr<IHTMLDocument2> &doc)
{
       CComPtr<IHTMLWindow2>  spIhtmlwindow2;
       doc->get_parentWindow(reinterpret_cast<IHTMLWindow2**>(&spIhtmlwindow2));
       if(spIhtmlwindow2 != NULL)
       {
              CString strLanguage("JavaScript");
              BSTR bstrLanguage = strLanguage.AllocSysString();
              long lTime = 1 * 1000;
              long lTimeID = 0;
              VARIANT varLanguage;
              varLanguage.vt = VT_BSTR;
              varLanguage.bstrVal = bstrLanguage;
              VARIANT pRet;
              //把window.onerror函数插入入当前页面中去
              spIhtmlwindow2->execScript(m_bstrScript, bstrLanguage, &pRet);
              ::SysFreeString(bstrLanguage);
       }
}
void CScriptErrHandler::ShieldAllChildPages(CComPtr<IHTMLDocument2> &parentDoc)
{
       WalkAllChildPages(parentDoc);
}
void CScriptErrHandler::WalkAllChildPages(CComPtr<IHTMLDocument2> &parentDoc)
{
       CComPtr<IHTMLFramesCollection2> spFramesCol;
       HRESULT hr = parentDoc->get_frames(&spFramesCol);
       if(SUCCEEDED(hr) && spFramesCol != NULL)
       {
              long lSize = 0;
              hr = spFramesCol->get_length(&lSize);
              if (SUCCEEDED(hr))
              {
                     for(int i=0; i<lSize; i++)
                     {
                            VARIANT frameRequested;
                            VARIANT frameOut;
                            frameRequested.vt = VT_UI4;
                            frameRequested.lVal = i;
                            hr = spFramesCol->item(&frameRequested, &frameOut);
                            if(SUCCEEDED(hr) && frameOut.pdispVal != NULL)
                            {
                                   CComPtr<IHTMLWindow2> spChildWindow;
                                   hr = frameOut.pdispVal->QueryInterface(IID_IHTMLWindow2,reinterpret_cast<void**>(&spChildWindow));
                                   if(SUCCEEDED(hr) && spChildWindow != NULL)
                                   {
                                          CComPtr<IHTMLDocument2> spChildDocument;
                                          hr = spChildWindow->get_document(reinterpret_cast<IHTMLDocument2**>(&spChildDocument));
                                          if(SUCCEEDED(hr) && spChildDocument != NULL)
                                          {
                                                 ShieldCurrPage(spChildDocument);
                                                 WalkAllChildPages(spChildDocument);
                                          }
                                   }
                                   frameOut.pdispVal->Release();
                            }
                     }
              }
       }
}

 
目前存在的一个缺陷是OnNavigateComplete2会被调用屡次,那么嵌入javascript的操做也会被执行屡次(不知道会产生什么反作用,目前还没有发现);CMyWebBrowser从CHtmlView类继承,代码在VC2008和VC6.0下调试经过;若须要工程代码,请发送邮件到 zhangqingping@hylanda.com 。

4.    参考资料
4.1   How to handle script errors as a WebBrowser control host
http://support.microsoft.com/default.aspx?scid=kb;en-us;261003
4.2   Script error notification is not sent to Exec method of WebBrowser Host
http://support.microsoft.com/kb/317024/en-us#top
4.3   How to Trap JScript Errors in Internet Explorer 4.01 and Earlier
http://support.microsoft.com/kb/183616/en-us


3、另一个资料

━━━━━━━━━━━━━━━━━━━━━━━━
How to handle script errors as a WebBrowser control host

The WebBrowser control notifies its host of an unhandled script error through the IOleCommandTarget interface. The host can then retrieve the information about the error, display (or suppress) an error message to the user, and choose whether to run scripts on the page.

MORE INFORMATION
When one of the script engines encounters an unhandled error, it forwards the er...

When one of the script engines encounters an unhandled error, it forwards the error to the WebBrowser control, which then queries its container to see if the container has implemented IOleCommandTarget. If the container has implemented IOleCommandTarget, the WebBrowser control calls the IOleCommandTarget::Exec method with the command group ID of CGID_DocHostCommandHandler (which is defined in the Mshtmhst.h file) and a command ID of OLECMDID_SHOWSCRIPTERROR. If the host does not return S_OK, MSHTML displays the default "An error has occurred on this page" error message.

The following code illustrates how to implement a handler for this command ID that retrieves the error information from the document object model. This code does not illustrate error handling.

NOTE: This method will not be invoked if the user has cleared the Disable Script Debugging check box in the Advanced tab under Internet Options.

java

 STDMETHODIMP CMyBrowser::Exec( const GUID* pguidCmdGroup, DWORD nCmdID,
DWORD nCmdexecopt, VARIANTARG* pvaIn, VARIANTARG* pvaOut )
{

HRESULT hr = 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"errorLine"),
SysAllocString(L"errorCharacter"),
SysAllocString(L"errorCode"),
SysAllocString(L"errorMessage"),
SysAllocString(L"errorUrl")
};
DISPID rgDispIDs[5];
VARIANT rgvaEventInfo[5];
DISPPARAMS params;
BOOL fContinueRunningScripts = true;
int i;

params.cArgs = 0;
params.cNamedArgs = 0;

// Get the document that is currently being viewed.
hr = pvaIn->punkVal->QueryInterface(IID_IHTMLDocument2, (void **) &pDoc);
// Get document.parentWindow.
hr = pDoc->get_parentWindow(&pWindow);
pDoc->Release();
// Get the window.event object.
hr = pWindow->get_event(&pEventObj);
// Get the error info from the window.event object.
for (i = 0; i < 5; i++)
{
// Get the property's dispID.
hr = pEventObj->GetIDsOfNames(IID_NULL, &rgwszNames[i], 1,
LOCALE_SYSTEM_DEFAULT, &rgDispIDs[i]);
// Get the value of the property.
hr = pEventObj->Invoke(rgDispIDs[i], IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET, &params, &rgvaEventInfo[i],
NULL, NULL);
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)
{
// Continue running scripts on the page.
(*pvaOut).boolVal = VARIANT_TRUE;
}
else
{
// Stop running scripts on the page.
(*pvaOut).boolVal = VARIANT_FALSE;
}
break;
}
default:
hr = OLECMDERR_E_NOTSUPPORTED;
break;
}
}
else
{
hr = OLECMDERR_E_UNKNOWNGROUP;
}
return (hr);
}

REFERENCES
For additional information on implementing the IOleCommandTarget interface, please see the following Microsoft Developer Network (MSDN) Web site:
http://msdn.microsoft.com/library/default.asp?URL=/library/psdk/com/oin_oc_9bg4.htm (http://msdn.microsoft.com/library/default.asp?URL=/library/psdk/com/oin_oc_9bg4.htm)
For more information about developing Web-based solutions for Microsoft Internet Explorer, visit the following Microsoft Web sites:
http://msdn.microsoft.com/ie/ (http://msdn.microsoft.com/ie/)
http://support.microsoft.com/iep (http://support.microsoft.com/iep)





━━━━━━━━━━━━━━━━━━━━━━━━vim

推荐:浏览器

谈老师的BLOG (佛教大德)
狮姐的博客(狮子窝,学佛与灵魂之探究)
大方广(学习传统文化)
慈善点击(轻松一点,行善积德,何乐不为)
电影《地球公民》(揭示鲜为人知的一面)  
心向光明 远离邪淫(现世警钟,不可不看)
戒淫(上篇)(正淫节欲,戒除邪淫)
戒淫(中篇)(纵欲之乐,忧患随之)
公民教育——命由我造网络