分享

WebBrowser或CHtmlView中屏蔽脚本错误

 quasiceo 2014-08-01

WebBrowser或CHtmlView中屏蔽脚本错误

444人阅读 评论(0) 收藏 举报
WebBrowser或CHtmlView中屏蔽脚本错误
━━━━━━━━━━━━━━━━━━━━━━━━

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

转自: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浏览器设置了脚本调试,也不会进行提示),经改造的代码如下:

 

<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 onload="fnOnLoad();">
<input type="button" value="function not defined" onclick="badcommand();">
<input type="button" value="object not defined" onclick="fnObjNotDefine();">
</body>
</html>

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

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.onerror=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操作即可。

最终代码为:

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.onerror=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


三、另外一个资料

━━━━━━━━━━━━━━━━━━━━━━━━
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.


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) 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多