zoukankan      html  css  js  c++  java
  • VC与JavaScript交互(四) --- 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浏览器设置了脚本调试,也不会进行提示),经改造的代码如下:

    复制代码
     1<html>
     2<head>
     3<script type="text/javascript" >
     4
     5function fnObjNotDefine(){
     6    domethod();
     7}
     8
     9function fnOnError(msg,url,lineno){
    10    <!--
    11    alert("window.onerror " +
    12    "Error: " + msg + " " +
    13    "URL:  " + url + " " +
    14    "Line:  " + lineno);
    15    return true; -->
    16}
    17window.onerror = fnOnError;
    18MethodName.badcommand();
    19
    20function fnOnLoad(){
    21    alert("on load!");
    22}
    23</script>
    24</head>
    25<body onload="fnOnLoad();">
    26<input type="button" value="function not defined" onclick="badcommand();">
    27<input type="button" value="object not defined" onclick="fnObjNotDefine();">
    28</body>
    29</html>
    30
    复制代码
    通过查看javascript代码,发现是“重载”了window.onerror这个事件,只要它返回true,脚本错误就不显示了,估计这个就是Microsoft自己实现的截取javascript脚本错误信息的接口

    ,于是就想怎么把它插入到页面当中,其中有篇文章介绍说在OnDocumentComplete时来实现javascript的插入,经实践,这种方法是不行的;经过本人的不断尝试,发现在OnNavigateComplete2或OnNavigateComplete里实现javascript的注入是可行的,这两个函数只要实现一个就行,就看你用的是Navigate2还是Navigate来打开页面了。这里使用Navigate2来做例子,具体代码如下:
    复制代码
     1void CMyWebBrowser::OnNavigateComplete2(LPCTSTR strURL)
     2
     3{
     4
     5       CComPtr<IDispatch>   spDisp   =   GetHtmlDocument(); 
     6
     7       if(spDisp   !=   NULL) 
     8
     9       
    10
    11              CComPtr<IHTMLDocument2> doc;
    12
    13              spDisp->QueryInterface(IID_IHTMLDocument2, reinterpret_cast<void**>(&doc));
    14
    15              if(doc != NULL)
    16
    17              {   
    18
    19                     IHTMLWindow2 * pIhtmlwindow2 = NULL;
    20
    21                     doc->get_parentWindow(&pIhtmlwindow2);
    22
    23                     if(pIhtmlwindow2 != NULL)
    24
    25                     {
    26
    27                            //屏蔽javascript脚本错误的javascript脚本
    28
    29                            CString strJavaScriptCode = "function fnOnError(msg,url,lineno){alert('script error:\n\nURL:'+url+'\n\nMSG:'+msg +'\n\nLine:'+lineno);return true;}window.onerror=fnOnError;";
    30
    31                            BSTR bstrScript = strJavaScriptCode.AllocSysString();
    32
    33                            CString strLanguage("JavaScript");
    34
    35                            BSTR bstrLanguage = strLanguage.AllocSysString();
    36
    37                            long lTime = 1 * 1000;
    38
    39                            long lTimeID = 0;
    40
    41                            VARIANT varLanguage;
    42
    43                            varLanguage.vt = VT_BSTR;
    44
    45                            varLanguage.bstrVal = bstrLanguage;
    46
    47                            VARIANT pRet;
    48
    49                            //把window.onerror函数插入入当前页面中去
    50
    51                            pIhtmlwindow2->execScript(bstrScript, bstrLanguage, &pRet);
    52
    53                            ::SysFreeString(bstrScript);
    54
    55                            ::SysFreeString(bstrLanguage);
    56
    57 
    58
    59                            pIhtmlwindow2->Release();
    60
    61                     }
    62
    63              }
    64
    65       }
    66
    67}
    复制代码

    其中,CMyWebBrowser是我自己继承了CHtmlView类的一个实现类, 这个函数可以在你的WebBrowser2或继承了CHtmlView类中实现,编写一个带有脚本错误的页面,打开进行浏览,是不是发现脚本错误被屏蔽了? 哈哈,实现起来也不麻烦。于是就把这个方法贴出来,供大家参考

    另: 经测试,发现如果存在iframe嵌套的时候,嵌套的iframe中包含脚本错误,以上方法是不能屏蔽iframe中的脚本错误的,因为window.onerror只针对当前页面有效,因此需要在OnNavigateComplete2函数里加上对当前页面进行递归所有子页面,然后重复执行execScript操作即可。

    最终代码为:

    复制代码
      1void CMyWebBrowser::OnNavigateComplete2(LPCTSTR strURL)
      2
      3{
      4
      5       CComPtr<IDispatch>   spDisp   =   GetHtmlDocument(); 
      6
      7       if(spDisp   !=   NULL) 
      8
      9       
     10
     11              CComPtr<IHTMLDocument2> doc;
     12
     13              spDisp->QueryInterface(IID_IHTMLDocument2, reinterpret_cast<void**>(&doc));
     14
     15              if(doc != NULL)
     16
     17              {   
     18
     19                     CScriptErrHandler scriptHandler;
     20
     21                     scriptHandler.ShieldCurrPage(doc);
     22
     23                     scriptHandler.ShieldAllChildPages(doc);
     24
     25              }
     26
     27       }
     28
     29}
     30
     31ScriptErrHandler.cpp文件:
     32
     33#include "StdAfx.h"
     34
     35#include "ScriptErrHandler.h"
     36
     37CScriptErrHandler::CScriptErrHandler(void)
     38
     39{
     40
     41       CString strJavaScriptCode = "function fnOnError(msg,url,lineno){alert('script error:\n\nURL:'+url"
     42
     43              "+'\n\nMSG:'+msg +'\n\nLine:'+lineno+'\n\nframes:' + window.frames.length);return true;}window.onerror=fnOnError;";
     44
     45 
     46
     47       //屏蔽的脚本,可以改进为从文本里读取
     48
     49       m_bstrScript = strJavaScriptCode.AllocSysString();
     50
     51}
     52
     53 
     54
     55CScriptErrHandler::~CScriptErrHandler(void)
     56
     57{
     58
     59       SysFreeString(m_bstrScript);
     60
     61}
     62
     63 
     64
     65 
     66
     67void CScriptErrHandler::ShieldCurrPage(CComPtr<IHTMLDocument2> &doc)
     68
     69{
     70
     71       CComPtr<IHTMLWindow2>  spIhtmlwindow2;
     72
     73       doc->get_parentWindow(reinterpret_cast<IHTMLWindow2**>(&spIhtmlwindow2));
     74
     75       if(spIhtmlwindow2 != NULL)
     76
     77       {
     78
     79              CString strLanguage("JavaScript");
     80
     81              BSTR bstrLanguage = strLanguage.AllocSysString();
     82
     83              long lTime = 1 * 1000;
     84
     85              long lTimeID = 0;
     86
     87              VARIANT varLanguage;
     88
     89              varLanguage.vt = VT_BSTR;
     90
     91              varLanguage.bstrVal = bstrLanguage;
     92
     93              VARIANT pRet;
     94
     95              //把window.onerror函数插入入当前页面中去
     96
     97              spIhtmlwindow2->execScript(m_bstrScript, bstrLanguage, &pRet);
     98
     99              ::SysFreeString(bstrLanguage);
    100
    101       }
    102
    103}
    104
    105 
    106
    107void CScriptErrHandler::ShieldAllChildPages(CComPtr<IHTMLDocument2> &parentDoc)
    108
    109{
    110
    111       WalkAllChildPages(parentDoc);
    112
    113}
    114
    115 
    116
    117void CScriptErrHandler::WalkAllChildPages(CComPtr<IHTMLDocument2> &parentDoc)
    118
    119{
    120
    121       CComPtr<IHTMLFramesCollection2> spFramesCol;
    122
    123       HRESULT hr = parentDoc->get_frames(&spFramesCol);
    124
    125       if(SUCCEEDED(hr) && spFramesCol != NULL)
    126
    127       {
    128
    129              long lSize = 0;
    130
    131              hr = spFramesCol->get_length(&lSize);
    132
    133              if (SUCCEEDED(hr))
    134
    135              {
    136
    137                     for(int i=0; i<lSize; i++)
    138
    139                     {
    140
    141                            VARIANT frameRequested;
    142
    143                            VARIANT frameOut;
    144
    145                            frameRequested.vt = VT_UI4;
    146
    147                            frameRequested.lVal = i;
    148
    149                            hr = spFramesCol->item(&frameRequested, &frameOut);
    150
    151                            if(SUCCEEDED(hr) && frameOut.pdispVal != NULL)
    152
    153                            {
    154
    155                                   CComPtr<IHTMLWindow2> spChildWindow;
    156
    157                                  
    158
    159                                   hr = frameOut.pdispVal->QueryInterface(IID_IHTMLWindow2,reinterpret_cast<void**>(&spChildWindow));
    160
    161                                   if(SUCCEEDED(hr) && spChildWindow != NULL)
    162
    163                                   {
    164
    165                                          CComPtr<IHTMLDocument2> spChildDocument;
    166
    167                                          hr = spChildWindow->get_document(reinterpret_cast<IHTMLDocument2**>(&spChildDocument));
    168
    169                                          if(SUCCEEDED(hr) && spChildDocument != NULL)
    170
    171                                          {
    172
    173                                                 ShieldCurrPage(spChildDocument);
    174
    175                                                 WalkAllChildPages(spChildDocument);
    176
    177                                          }
    178
    179                                   }
    180
    181                                   frameOut.pdispVal->Release();
    182
    183                            }
    184
    185                     }
    186
    187              }
    188
    189       }
    190
    191}
    复制代码

    目前存在的一个缺陷是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

    2011-12-08 13:35:02 Angela doudou

    这个是成功代码 
    void CZCSoftView::OnNavigateComplete2(LPCTSTR strURL) 

    // TODO: Add your specialized code here and/or call the base class 
    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) 
    {//"function fnOnError(msg,url,lineno){alert('script error:\n\nURL:'+url+'\n\nMSG:'+msg +'\n\nLine:'+lineno);return true;}window.onerror=fnOnError;"; 
    //屏蔽javascript脚本错误的javascript脚本 
    CString strJavaScriptCode = "function fnOnError(){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(); 




    CHtmlView::OnNavigateComplete2(strURL); 


     
     
    Angela doudou
    2011-12-08 13:35:36 Angela doudou

    禁止弹出窗口 给你的从CHtmlView派生而来的类加一个成员变量BOOL m_bPop; 
      在构造函数里给m_bPop初始化为:m_bPop = TRUE; 
      重载OnDownloadBegin虚函数,在其中加入:m_bPop = FALSE; 
      重载OnDownloadComplete虚函数,在其中加入:m_bPop = TRUE; 
      重载OnNewWindow2虚函数,在其中加入: 
      Cancel = m_bPop; 
    禁止脚本错误 在初始化的时候设置 SetSilent(TRUE);

  • 相关阅读:
    ASP.NET AJAX Beta 1 发布 (转载)
    ASP.NET里常用的JS (转贴)
    让您的Ajax应用加载数据时界面友好 (转贴)
    模态窗口 javascript html
    最亲密接触Dhtml&JScript开发细节 (转贴)
    Hashtable的使用
    2009年全国年节及纪念日放假办法
    详解.NET中的动态编译
    CSS2.0样式手册_说明_SDK下载chm
    [转]DISTINCT 和 ORDER BY 使用第三个字段进行排序
  • 原文地址:https://www.cnblogs.com/MrYuan/p/5019305.html
Copyright © 2011-2022 走看看