MFC使用CDHtmlDialog禁止脚本错误的方法

原文地址: https://blog.csdn.net/zhongbin104/article/details/7555695

当WebBrowser控件(CDHtmlDialog自动创建了WebBrowser控件)加载的网页中含有错误Javascript代码时默认情况下控件会弹出错误信息提示对话框,相对于用户体验来说这样的提示完全不是开发人员想要的,针对这个问题有两个解决方案,一是完全屏蔽掉错误提示,二是控制错误的提示并且记录错误信息同时也可以控制出现错误后Javascript是否继续执行。

1. 错误全禁止

//禁止脚本错误提示
m_WebBrowser.put_Silent(TRUE);

在CDHtmlDialog::OnInitDialog()的代码中首先了创建WebBrowser控件,然后把控件的Browser对象赋值给m_pBrowserApp(这是CDHtmlDialog完成的不需要自己处理)。WebBrowser的put_Silent函数在官方给出的说明是禁用所有的对话框,但例外情况是它不会影响SSL安全认证需要的进示对话框。绝大多数情况下这就可以解决问题了,记得很久以前我遇到过一种情况就是虽然调用了put_Silent但是还是有极个别的js错误是无法屏蔽掉的依然会显示出来(在网页含有嵌套页面时会错误无法屏蔽,不知道是否还有其它情况),现在找不到这样的网页了,如果谁遇到这种情况了建议给我发上个URL让我也重温一下当年阳光灿烂的时刻。

2. 控制错误的提示并且记录错误信息同时也可以控制出现错误后Javascript是否继续执行。

这要比第一种方法复杂上许多,简短的来说就是自定义COleControlSite类并实现IOleCommandTarget接口,IOleCommandTarget接口是错误控制的关健,错误发生时会触发此接口的Exec函数并为nCmdID参数赋值为OLECMDID_SHOWSCRIPTERROR,这样就可以得到错误信息了。

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;
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

  • 本书是作者以自传体形式,将自己在国际象棋与太极竞技领域上经历与心得的分享。纵观作者的成长历程,不难看出他对成功的渴...
    鑫泽阅读 880评论 0 18
  • 今天白天跟姨姨玩,下午游泳,晚上又去给小朋友庆祝生日,于是九点爸比发威了,学习去! 两父子先一起看了两本小蓝本,又...
    优雅黑鸟阅读 187评论 0 0
  • 当年在部队的伙房工作时,一位在民间当大厨的老士官曾跟我们新进弟兄说过这样的话: "做菜让家人朋友都说好的叫家庭主妇...
    Arthur亚瑟阅读 574评论 1 0