CDHtmlDialog探索----WebBrowser扩展和网页Javascript错误处理
来源:互联网 发布:自动化选型软件 编辑:程序博客网 时间:2024/06/06 02:03
当WebBrowser控件(CDHtmlDialog自动创建了WebBrowser控件)加载的网页中含有错误Javascript代码时默认情况下控件会弹出错误信息提示对话框,相对于用户体验来说这样的提示完全不是开发人员想要的,针对这个问题有两个解决方案,一是完全屏蔽掉错误提示,二是控制错误的提示并且记录错误信息同时也可以控制出现错误后Javascript是否继续执行。
1、屏蔽错误信息提示
1
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,这样就可以得到错误信息了。
01
IOleCommandTarget :
public
IUnknown
02
{
03
public
:
04
virtual
/* [input_sync] */
HRESULT
STDMETHODCALLTYPE QueryStatus(
05
/* [unique][in] */
__RPC__in_opt
const
GUID *pguidCmdGroup,
06
/* [in] */
ULONG
cCmds,
07
/* [out][in][size_is] */
__RPC__inout_ecount_full(cCmds) OLECMD prgCmds[ ],
08
/* [unique][out][in] */
__RPC__inout_opt OLECMDTEXT *pCmdText) = 0;
09
10
virtual
HRESULT
STDMETHODCALLTYPE Exec(
11
/* [unique][in] */
__RPC__in_opt
const
GUID *pguidCmdGroup,
12
/* [in] */
DWORD
nCmdID,
13
/* [in] */
DWORD
nCmdexecopt,
14
/* [unique][in] */
__RPC__in_opt VARIANT *pvaIn,
15
/* [unique][out][in] */
__RPC__inout_opt VARIANT *pvaOut) = 0;
16
17
};
18
现在我们开始实现自定义的COleControlSite
01
class
CMyControlSite :
public
COleControlSite
02
{
03
04
public
:
05
CMyControlSite(COleControlContainer *pCntr):COleControlSite(pCntr) {}
06
07
protected
:
08
09
DECLARE_INTERFACE_MAP()
10
BEGIN_INTERFACE_PART(OleCommandTarget, IOleCommandTarget)
11
STDMETHOD(QueryStatus)(
const
GUID *pguidCmdGroup,
ULONG
cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText);
12
STDMETHOD(Exec)(
const
GUID* pguidCmdGroup,
DWORD
nCmdID,
DWORD
nCmdexecopt, VARIANTARG* pvaIn, VARIANTARG* pvaOut);
13
END_INTERFACE_PART(OleCommandTarget)
1
MFC提供了很多宏用于简化COM相关功能的开发,对COM接口的实现方式在MFC中具体体现方式是内嵌类,背后的设计思想是COM聚合,每个接口都产生一个内嵌类,所有的接口都聚合到外层的类。DECLARE_INTERFACE_MAP() 实际上就是定义一个数组以及查询操作,BEGIN_INTERFACE_PART定义一个命名为XOleCommandTarget的内嵌类(内嵌类的命名规则是XName)并定义IUnknown接口的三个方法AddRef、Release、QueryInterface。END_INTERFACE_PART定义一个m_xOleCommandTarget的成员类型为XOleCommandTarget(定义的成员命名规则就是m_xName),并把XOleCommandTarget类声明为外层类的友元类在示例中外层类指CMyControlSite。
STDMETHOD宏定义为virtual __declspec(nothrow) HRESULT __stdcall,该宏定义函数为虚函数返回值为HRESULT,函数调用约定为__stdcall,并且在此函数上禁止异常。__declspec(nothrow)用定告诉编译器它修饰的函数以及此函数调用的函数不会产生C++异常调用从可以优化代码性能和代码尺寸(默认情况下C++编译器为了进行异常处理会在拥有throw调用的函数中自动生成相关的异常处理代码)。通常情况下HRESULT返回值就表达了错误信息,HRESULT是个32位值,不同的位域用于不同的目的,也可以使用自定义的位域,具体的信息可以参考http://en.wikipedia.org/wiki/HRESULT。由于COM本身的语言中立性所以不应该在COM组件对外公布的信息中掺杂特定语言相关的特性。如果需要提供更详尽的错误信息那么应该实现COM的IErrorInfo接口。言归正传以下是CMyControlSite的类实现代码
01
BEGIN_INTERFACE_MAP(CMyControlSite, COleControlSite)
02
INTERFACE_PART(CMyControlSite, IID_IOleCommandTarget, OleCommandTarget)
03
END_INTERFACE_MAP()
04
05
06
HRESULT
CMyControlSite::XOleCommandTarget::Exec
07
(
const
GUID* pguidCmdGroup,
DWORD
nCmdID,
08
DWORD
nCmdexecopt, VARIANTARG* pvaIn, VARIANTARG* pvaOut )
09
{
10
HRESULT
hr = OLECMDERR_E_NOTSUPPORTED;
11
//return S_OK;
12
if
(pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_DocHostCommandHandler))
13
{
14
15
switch
(nCmdID)
16
{
17
18
case
OLECMDID_SHOWSCRIPTERROR:
19
{
20
IHTMLDocument2* pDoc = NULL;
21
IHTMLWindow2* pWindow = NULL;
22
IHTMLEventObj* pEventObj = NULL;
23
BSTR rgwszNames[5] =
24
{
25
SysAllocString(L
"errLine"
),
26
SysAllocString(L
"errCharacter"
),
27
SysAllocString(L
"errCode"
),
28
SysAllocString(L
"errMsg"
),
29
SysAllocString(L
"errUrl"
)
30
};
31
DISPID rgDispIDs[5];
32
VARIANT rgvaEventInfo[5];
33
DISPPARAMS params;
34
BOOL
fContinueRunningScripts =
true
;
35
36
params.cArgs = 0;
37
params.cNamedArgs = 0;
38
39
hr = pvaIn->punkVal->QueryInterface(IID_IHTMLDocument2, (
void
**) &pDoc);
40
41
hr = pDoc->get_parentWindow(&pWindow);
42
pDoc->Release();
43
44
hr = pWindow->get_event(&pEventObj);
45
46
for
(
int
i = 0; i < 5; i++)
47
{
48
49
hr = pEventObj->GetIDsOfNames(IID_NULL, &rgwszNames[i], 1,
50
LOCALE_SYSTEM_DEFAULT, &rgDispIDs[i]);
51
52
hr = pEventObj->Invoke(rgDispIDs[i], IID_NULL,
53
LOCALE_SYSTEM_DEFAULT,
54
DISPATCH_PROPERTYGET, ¶ms, &rgvaEventInfo[i],
55
NULL, NULL);
56
//可以在此记录错误信息
01
//必须使用SysFreeString来释放SysAllocString分配的内存,SysAllocString在分配的内存中记录了字符的长度
02
SysFreeString(rgwszNames[i]);
03
}
04
05
// At this point, you would normally alert the user with
06
// the information about the error, which is now contained
07
// in rgvaEventInfo[]. Or, you could just exit silently.
08
09
(*pvaOut).vt = VT_BOOL;
10
if
(fContinueRunningScripts)
11
{
12
// 在页面中继续执行脚本
13
(*pvaOut).boolVal = VARIANT_TRUE;
14
}
15
else
16
{
17
// 停止在页面中执行脚本
18
(*pvaOut).boolVal = VARIANT_FALSE;
19
}
20
break
;
21
}
22
default
:
23
hr =OLECMDERR_E_NOTSUPPORTED;
24
break
;
25
}
26
}
27
else
28
{
29
hr = OLECMDERR_E_UNKNOWNGROUP;
30
}
31
return
(hr);
32
}
33
34
35
ULONG
FAR EXPORT CMyControlSite::XOleCommandTarget::AddRef()
36
{
37
METHOD_PROLOGUE(CMyControlSite, OleCommandTarget)
38
return
pThis->ExternalAddRef();
39
}
40
41
42
ULONG
FAR EXPORT CMyControlSite::XOleCommandTarget::Release()
43
{
44
METHOD_PROLOGUE(CMyControlSite, OleCommandTarget)
45
return
pThis->ExternalRelease();
46
}
47
48
HRESULT
FAR EXPORT CMyControlSite::XOleCommandTarget::QueryInterface(REFIID riid,
void
**ppvObj)
49
{
50
METHOD_PROLOGUE(CMyControlSite, OleCommandTarget)
51
HRESULT
hr = (
HRESULT
)pThis->ExternalQueryInterface(&riid, ppvObj);
52
return
hr;
53
}
54
55
STDMETHODIMP CMyControlSite::XOleCommandTarget::QueryStatus(
56
/* [unique][in] */
const
GUID __RPC_FAR *pguidCmdGroup,
57
/* [in] */
ULONG
cCmds,
58
/* [out][in][size_is] */
OLECMD __RPC_FAR prgCmds[ ],
59
/* [unique][out][in] */
OLECMDTEXT __RPC_FAR *pCmdText
60
)
61
{
62
METHOD_PROLOGUE(CMyControlSite, OleCommandTarget)
63
return
OLECMDERR_E_NOTSUPPORTED;
64
}
实现CMyControlSite后需要应用到CDHtmlDialog上,重写CreateControlSite虚函数既可
01
virtual
BOOL
CreateControlSite(COleControlContainer* pContainer,
02
COleControlSite** ppSite,
UINT
nID , REFCLSID clsid )
03
{
04
if
(ppSite == NULL)
05
{
06
ASSERT(FALSE);
07
return
FALSE;
08
}
09
10
CMyControlSite *pBrowserSite =
11
new
CMyControlSite (pContainer,
this
);
12
if
(!pBrowserSite)
13
return
FALSE;
14
15
*ppSite = pBrowserSite;
16
return
TRUE;
17
}
现在就可以去编译测试了。到目前还有一个问题没有考虑,如果这段代码整合到现有的CDHtmlDialog应用中而现有的代码使用了其它默认的设定比如说自定义WebBrowser的右健菜单或使用了GetIDispatch函数等情况下原有的代码就不能正常工作了。这部分功能是在MFC的CBrowserControlSite类中处理的,所以CMyControlSite应该把CBrowserControlSite的功能也实现一遍以使CDHtmlDialog的原有封装性不被破坏。在CMyControlSite中实现IDocHostUIHandler接口既可完成此功能。代码声明如下
1
public
:
1
CMyControlSite(COleControlContainer *pCnt, CDHtmlDialog *pHandler):COleControlSite(pCnt),m_pHandler(pHandler) {}
1
protected
:
1
CDHtmlDialog *m_pHandler;<br>
01
BEGIN_INTERFACE_PART(DocHostUIHandler, IDocHostUIHandler)
02
STDMETHOD(ShowContextMenu)(
DWORD
, LPPOINT, LPUNKNOWN, LPDISPATCH);
03
STDMETHOD(GetHostInfo)(DOCHOSTUIINFO*);
04
STDMETHOD(ShowUI)(
DWORD
, LPOLEINPLACEACTIVEOBJECT,
05
LPOLECOMMANDTARGET, LPOLEINPLACEFRAME, LPOLEINPLACEUIWINDOW);
06
STDMETHOD(HideUI)(
void
);
07
STDMETHOD(UpdateUI)(
void
);
08
STDMETHOD(EnableModeless)(
BOOL
);
09
STDMETHOD(OnDocWindowActivate)(
BOOL
);
10
STDMETHOD(OnFrameWindowActivate)(
BOOL
);
11
STDMETHOD(ResizeBorder)(LPCRECT, LPOLEINPLACEUIWINDOW,
BOOL
);
12
STDMETHOD(TranslateAccelerator)(LPMSG,
const
GUID*,
DWORD
);
13
STDMETHOD(GetOptionKeyPath)(OLECHAR **,
DWORD
);
14
STDMETHOD(GetDropTarget)(LPDROPTARGET, LPDROPTARGET*);
15
STDMETHOD(GetExternal)(LPDISPATCH*);
16
STDMETHOD(TranslateUrl)(
DWORD
, OLECHAR*, OLECHAR **);
17
STDMETHOD(FilterDataObject)(LPDATAOBJECT , LPDATAOBJECT*);
18
END_INTERFACE_PART(DocHostUIHandler)
以下是实现代码
001
BEGIN_INTERFACE_MAP(CMyControlSite, COleControlSite)
002
INTERFACE_PART(CMyControlSite, IID_IDocHostUIHandler, DocHostUIHandler)
003
INTERFACE_PART(CMyControlSite, IID_IOleCommandTarget, OleCommandTarget)
004
END_INTERFACE_MAP()
005
006
STDMETHODIMP CMyControlSite::XDocHostUIHandler::GetExternal(LPDISPATCH *lppDispatch)
007
{
008
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
009
return
pThis->m_pHandler->GetExternal(lppDispatch);
010
}
011
012
013
014
STDMETHODIMP CMyControlSite::XDocHostUIHandler::ShowContextMenu(
015
DWORD
dwID, LPPOINT ppt, LPUNKNOWN pcmdTarget, LPDISPATCH pdispReserved)
016
{
017
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
018
return
pThis->m_pHandler->ShowContextMenu(dwID, ppt, pcmdTarget, pdispReserved);
019
}
020
021
STDMETHODIMP CMyControlSite::XDocHostUIHandler::GetHostInfo(
022
DOCHOSTUIINFO *pInfo)
023
{
024
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
025
return
pThis->m_pHandler->GetHostInfo(pInfo);
026
}
027
028
029
STDMETHODIMP CMyControlSite::XDocHostUIHandler::ShowUI(
030
DWORD
dwID, LPOLEINPLACEACTIVEOBJECT pActiveObject,
031
LPOLECOMMANDTARGET pCommandTarget, LPOLEINPLACEFRAME pFrame,
032
LPOLEINPLACEUIWINDOW pDoc)
033
{
034
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
035
return
pThis->m_pHandler->ShowUI(dwID, pActiveObject, pCommandTarget, pFrame, pDoc);
036
}
037
038
STDMETHODIMP CMyControlSite::XDocHostUIHandler::HideUI(
void
)
039
{
040
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
041
return
pThis->m_pHandler->HideUI();
042
}
043
044
STDMETHODIMP CMyControlSite::XDocHostUIHandler::UpdateUI(
void
)
045
{
046
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
047
return
pThis->m_pHandler->UpdateUI();
048
}
049
050
051
STDMETHODIMP CMyControlSite::XDocHostUIHandler::EnableModeless(
BOOL
fEnable)
052
{
053
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
054
return
pThis->m_pHandler->EnableModeless(fEnable);
055
}
056
057
STDMETHODIMP CMyControlSite::XDocHostUIHandler::OnDocWindowActivate(
BOOL
fActivate)
058
{
059
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
060
return
pThis->m_pHandler->OnDocWindowActivate(fActivate);
061
}
062
063
STDMETHODIMP CMyControlSite::XDocHostUIHandler::OnFrameWindowActivate(
064
BOOL
fActivate)
065
{
066
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
067
return
pThis->m_pHandler->OnFrameWindowActivate(fActivate);
068
}
069
070
STDMETHODIMP CMyControlSite::XDocHostUIHandler::ResizeBorder(
071
LPCRECT prcBorder, LPOLEINPLACEUIWINDOW pUIWindow,
BOOL
fFrameWindow)
072
{
073
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
074
return
pThis->m_pHandler->ResizeBorder(prcBorder, pUIWindow, fFrameWindow);
075
}
076
077
STDMETHODIMP CMyControlSite::XDocHostUIHandler::TranslateAccelerator(
078
LPMSG lpMsg,
const
GUID* pguidCmdGroup,
DWORD
nCmdID)
079
{
080
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
081
return
pThis->m_pHandler->TranslateAccelerator(lpMsg, pguidCmdGroup, nCmdID);
082
}
083
084
085
STDMETHODIMP CMyControlSite::XDocHostUIHandler::GetOptionKeyPath(
086
LPOLESTR* pchKey,
DWORD
dwReserved)
087
{
088
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
089
return
pThis->m_pHandler->GetOptionKeyPath(pchKey, dwReserved);
090
}
091
092
093
STDMETHODIMP CMyControlSite::XDocHostUIHandler::GetDropTarget(
094
LPDROPTARGET pDropTarget, LPDROPTARGET* ppDropTarget)
095
{
096
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
097
return
pThis->m_pHandler->GetDropTarget(pDropTarget, ppDropTarget);
098
}
099
100
STDMETHODIMP CMyControlSite::XDocHostUIHandler::TranslateUrl(
101
DWORD
dwTranslate, OLECHAR* pchURLIn, OLECHAR** ppchURLOut)
102
{
103
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
104
return
pThis->m_pHandler->TranslateUrl(dwTranslate, pchURLIn, ppchURLOut);
105
}
106
107
STDMETHODIMP CMyControlSite::XDocHostUIHandler::FilterDataObject(
108
LPDATAOBJECT pDataObject, LPDATAOBJECT* ppDataObject)
109
{
110
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
111
return
pThis->m_pHandler->FilterDataObject(pDataObject, ppDataObject);
112
}
113
114
115
STDMETHODIMP_(
ULONG
) CMyControlSite::XDocHostUIHandler::AddRef()
116
{
117
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
118
return
pThis->ExternalAddRef();
119
}
120
121
STDMETHODIMP_(
ULONG
) CMyControlSite::XDocHostUIHandler::Release()
122
{
123
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
124
return
pThis->ExternalRelease();
125
}
126
127
STDMETHODIMP CMyControlSite::XDocHostUIHandler::QueryInterface(
128
REFIID iid,
LPVOID
far* ppvObj)
129
{
130
METHOD_PROLOGUE_EX_(CMyControlSite, DocHostUIHandler)
131
return
pThis->ExternalQueryInterface(&iid, ppvObj);
132
}
STDMETHODIMP宏的定义是HRESULT __stdcall,STDMETHODIMP_宏指定了返回值,这两个宏用在cpp实现文件中,对应用于声明时使用的STDMETHOD和STDMETHOD_。
METHOD_PROLOGUE_EX_宏定义了pThis指针来指向外层类。
以上代码基于VS2008,由于不同版本的VS所带的MFC库版本不尽一致所以需要根本具体的版本来处理,目前已知的不同部分主要集中在CreateControlSite上。
- CDHtmlDialog探索----WebBrowser扩展和网页Javascript错误处理
- CDHtmlDialog探索----WebBrowser扩展和网页Javascript错误处理
- CDHtmlDialog探索----WebBrowser扩展和网页Javascript错误处理
- CDHtmlDialog探索----WebBrowser扩展和网页Javascript错误处理
- CDHtmlDialog探索----WebBrowser扩展和网页Javascript错误处理
- CDHtmlDialog探索----Javascript与窗体交互
- CDHtmlDialog探索----Javascript与窗体交互
- CDHtmlDialog探索----Javascript与窗体交互
- CDHtmlDialog探索----Javascript与窗体交互
- WebBrowser和AxWebBrowser屏蔽网页脚本错误
- CDHtmlDialog调用网页内部Javascript的两种方法
- WebBrowser中的脚本错误处理
- CDHtmlDialog 调用javascript
- CDHtmlDialog 与 网页交互技巧
- 获取网页中的内容(CDHtmlDialog)
- CDHtmlDialog 与 网页交互技巧
- CDHtmlDialog 与 网页交互技巧
- CDHtmlDialog屏蔽网页右键菜单
- 软中断与Bottom Half
- 基于mips架构的uboot 启动流程 (1)
- java web笔记(字符编码)
- 在java流中用到的Decorator模式
- Linux驱动的地址空间和硬件地址空间说明——摘自华清远见嵌入式园地 .
- CDHtmlDialog探索----WebBrowser扩展和网页Javascript错误处理
- Android手机软件开发简单计算功能一例
- C# 中DataTable 的copy()方法和clone()方法
- Hibernate学习——Hibernate入门
- ifb
- 基于mips架构的uboot 启动流程 (2)
- C++指针与引用的区别
- table对tr增加删除的操作
- 网上看到的超牛c语言学习论