页面脚本在运行时,如果出现错误,默认情况下会弹出一个对话框,告诉你脚本不正确,要不要继续运行什么的。CHTMLView中没有处理这种情况的默认方法。如果要响应这类事件,需要做2件事,1 创建一个新的类,继承自COleControl或它的派生类,并实现IOleCommandTarget接口。2 替换CHTMLView类中的CreateControlSite函数,以返回刚才创建那个类的实例。
脚本引擎在遇到未处理的错误时,它会查询容器,看该容器是不是已经实现了 IOleCommandTarget 接口。如果是,web 浏览器控件将以参数OLECMDID_SHOWSCRIPTERROR调用IOleCommandTarget::Exec 方法。如果函数返回 S_OK,那么浏览器对象就不会弹出错误对话框了。
CHTMLView 本身并不是这样的容器,所以它无法直接获得这些事件。但CHTMLView有一个函数CreateControlSite,它用来创建所需要的对象容器。如果我们替换这个函数,并返回自己的容器对象,就可以接收这类事件了。
这样的对象容器可以继承自COleControlSite,并实现IOlecommandTaget接口。当脚本出错,它会调用IOleCommandTarget中的Exec来处理这个事件。Exec的申明是这样的
STDMETHODIMP CSiteView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,VARIANT *pvaIn,VARIANT *pvaOut)
其中nCmdID指明是哪种事件。如果其值为OLECMDID_SHOWSCRIPTERROR ,说明发生脚本运行错误,此时令函数返回S_OK,那么就不会弹出对话框了。
简单的代码如下
头文件
- //CSiteControlSite.h
- #include <afxocc.h>
- //CSiteView 继承自CHTMLView
- class CSiteView;
- class CSiteControlSite : public COleControlSite
- {
- public:
- CSiteControlSite(COleControlContainer* pCtrlCont)
- : COleControlSite(pCtrlCont)
- {
- };
- ~CSiteControlSite()
- {
- }
- CSiteView * GetView() const;
- protected:
- //关键的代码在这里
- DECLARE_INTERFACE_MAP()
- BEGIN_INTERFACE_PART(CmdTargetObj, IOleCommandTarget)
- STDMETHOD(QueryStatus)(const GUID*, ULONG, OLECMD[], OLECMDTEXT*);
- STDMETHOD(Exec)(const GUID*, DWORD, DWORD, VARIANTARG*,VARIANTARG*);
- END_INTERFACE_PART(CmdTargetObj)
- friend class CSiteView;
- };
.cpp文件
- BEGIN_INTERFACE_MAP(CSiteControlSite, COleControlSite)
- INTERFACE_PART(CSiteControlSite, IID_IOleCommandTarget, CmdTargetObj)
- END_INTERFACE_MAP()
- CSiteView * CSiteControlSite::GetView() const
- {
- return STATIC_DOWNCAST(CSiteView, m_pCtrlCont->m_pWnd);
- }
- ULONG FAR EXPORT CSiteControlSite::XCmdTargetObj::AddRef()
- {
- METHOD_PROLOGUE(CSiteControlSite, CmdTargetObj)
- return pThis->ExternalAddRef();
- }
- ULONG FAR EXPORT CSiteControlSite::XCmdTargetObj::Release()
- {
- METHOD_PROLOGUE(CSiteControlSite, CmdTargetObj)
- return pThis->ExternalRelease();
- }
- HRESULT FAR EXPORT CSiteControlSite::XCmdTargetObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
- {
- METHOD_PROLOGUE(CSiteControlSite, CmdTargetObj)
- return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
- }
- STDMETHODIMP CSiteControlSite::XCmdTargetObj::QueryStatus(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[],OLECMDTEXT* pcmdtext)
- {
- METHOD_PROLOGUE(CSiteControlSite, CmdTargetObj)
- return S_OK;
- }
- STDMETHODIMP CSiteControlSite::XCmdTargetObj::Exec(const GUID* pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt,VARIANTARG* pvarargIn, VARIANTARG* pvarargOut)
- {
- METHOD_PROLOGUE(CSiteControlSite, CmdTargetObj)
- HRESULT hr = S_OK;
- if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_DocHostCommandHandler))
- {
- switch (nCmdID)
- {
- case OLECMDID_SHOWSCRIPTERROR:
- {
- // pvaOut 设置为TRUE,继续运行此scripts
- (*pvaOut).vt = VT_BOOL;
- (*pvaOut).boolVal = VARIANT_TRUE;
- return S_OK;
- break;
- }
- default:
- hr = OLECMDERR_E_NOTSUPPORTED;
- break;
- }
- }
- else
- {
- hr = OLECMDERR_E_UNKNOWNGROUP;
- }
- return (hr);
- }
IOleCommandTarget基本上就处理完了。再来看看CHTMLView. CHTMLView 的创建过程是这样的 CHTMLView::Create---->CWnd::CreateControl-->COleControlContainer::CreateControl-->CHTMLView::CreateControlSite.而CreateControlSite的定义也比较简单
- BOOL CHtmlView::CreateControlSite(COleControlContainer* pContainer,
- COleControlSite** ppSite, UINT /* nID */, REFCLSID /* clsid */)
- {
- ASSERT(ppSite != NULL);
- *ppSite = new CHtmlControlSite(pContainer);
- return TRUE;
- }
我们在自己的类中重写CreateControlSite并返回刚刚完成的那个类的实例就可以了。
简单的代码如下
- BOOL CSiteView::CreateControlSite(COleControlContainer* pContainer,
- COleControlSite** ppSite, UINT /* nID */, REFCLSID /* clsid */)
- {
- ASSERT(ppSite != NULL);
- *ppSite = new CSiteControlSite(pContainer);
- return TRUE;
- }
到这里,大体的样子就基本完成了。CHTMLView的默认ControlSite是CHTMLControlSite,它被定义在viewhtml.cpp文件中,所以我们没有办法继承它。如果要实现它原有的一些功能,比如ShowContenxtMenu之类的,可以参考CHTMLControlSite的代码来写,没有多少。
参考文档
微软知识库文章 Q261003 How to handle script errors as a WebBrowser control host (http://support.microsoft.com/kb/261003)
CSDN文档 WebBrowser中Script错误调试的对话框 http://topic.csdn.net/t/20061105/02/5133903.html
大牛 蒋晟 的文章 Hook DHMTL Commands http://www.joycode.com/jiangsheng/archive/2005/07/09/58754.joy