您的位置:首页 > Web前端 > HTML

关于MFC项目中使用CDHtmlDialog禁止脚本错误的方法

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

1、屏蔽错误信息提示

?

view
plain

m_pBrowserApp->put_Silent(VARIANT_TRUE);//禁止脚本错误提示

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

2、控制错误提示并进行记录

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

?
现在我们开始实现自定义的COleControlSite,代码如下:

view
plain

CMyControlSite.h

view
plain

#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

view
plain

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

}

对话框头文件加入声明:

view
plain

virtual
BOOL CreateControlSite(COleControlContainer* pContainer,

COleControlSite** ppSite,

UINT nID , REFCLSID clsid );

对应源文件:

view
plain

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;

}

thinkingfor原文中为CDHtmlDialog,同样适用于CDialog.

参考文章
CDHtmlDialog探索----WebBrowser扩展和网页Javascript错误处理 作者:thinkingfor
/article/8899261.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: