在CHtmlView中判断页面加载完成

22 篇文章 0 订阅

首先想想这个问题如果是在JS里面是如何实现的。 

JS里面最简单的方式就是利用onload事件让一段JS在页面加载完成后启动。 

使用onload事件的好处是,能够保证页面上的image图片都已经加载完成。 

 

比如: 

 

window.onload = function() 

// do something 

 

// 或者 

window.attachEvent( "onload", function(){ 

// do something 

); 

这两种写法稍有不同。 

对于前者,是直接替换了onload的处理句柄,也就是说,如果页面已经有onload了,那么执行这句后会导致原本的onload处理会被替换掉(当然,必须保证这句代码在onload前执行)。 

而后者attachEvent,它能够为onload事件添加多个处理句柄。 

 

插一句, 多个attachEvent上去的事件执行顺序是不确定的。 以前有人比较过attachEvent和W3C的addEventListener。 

发现attachEvent上去的多个句柄的执行顺序完全不可控。这也是为什么在一些JS框架中,如Ext,引入自己的事件处理流,来实现多浏览器的一致性。所以,如果页面已经attachEvent了, 而你又attachEvent,那么结果是很难预测了,尽量避免。 

 

前面都是废话,言归正传,如何在CHtmlView里面来实现? 

在CHtmlView中,有下面2个接口函数对应上面的2种JS写法。 

 

IHTMLWindow2::put_onload(VARIANT v); 

 

// 或者 

 

IHTMLWindow3::attachEvent( BSTR event, 

IDispatch *pDisp, 

VARIANT_BOOL *pfResult 

); 

 

看到了吧,在MSHTML中,完全有接口函数来实现JS中同样的功能。 

首先看看 第一种JS写法对应的 C++ 代码 

 

 

void CTestHtmlViewView::OnDocumentComplete(LPCTSTR lpszURL) 

IHTMLDocument * pDoc = (IHTMLDocument *)GetHtmlDocument(); 

CComQIPtr<IHTMLDocument2> pDoc2(pDoc); 

 

if( pDoc2 ) 

CComPtr<IHTMLWindow2> pWnd2; 

pDoc2->get_parentWindow(&pWnd2); 

if( pWnd2 ) 

VARIANT vEvent = CDOMEventHandler::CreateEventHandlerVariant( &CTestHtmlViewView::OnLoad, (LONG_PTR)this); 

pWnd2->put_onload( vEvent ); 

 

 

CHtmlView::OnDocumentComplete(lpszURL); 

 

再看看 第2种JS对应的C++代码。 

 

void CTestHtmlViewView::OnDocumentComplete(LPCTSTR lpszURL) 

IHTMLDocument * pDoc = (IHTMLDocument *)GetHtmlDocument(); 

CComQIPtr<IHTMLDocument2> pDoc2(pDoc); 

 

if( pDoc2 ) 

CComPtr<IHTMLWindow2> pWnd2; 

pDoc2->get_parentWindow(&pWnd2); 

CComQIPtr<IHTMLWindow3> pWnd3(pWnd2); 

if( pWnd3 ) 

VARIANT_BOOL vbSuccess = VARIANT_FALSE; 

pWnd3->attachEvent( _bstr_t(_T("onload")) 

, CDOMEventHandler::CreateEventHandler( &CTestHtmlViewView::OnLoad, (LONG_PTR)this) 

, &vbSuccess 

); 

具体使用哪种写法,依据你自己的实际情况而定。 

细心的你一定发现了, CDOMEventHandler是什么? 

CTestHtmlViewView::OnLoad是什么? 

 

CTestHtmlViewView::OnLoad是onload事件的响应函数,它在这里作为函数指针传递,函数指针原型为: 

 

typedef void (*PFN_DOM_EVENT_CALLBACK)(VARIANT* pVarResult, LONG_PTR lpUserData); 

CDOMEventHandler是一个派生自IDispatch的类。好了,不说那么多了。你应该具体怎么做呢? 

 

第一步,将CDOMEventHandler类加入到你的工程 

 

#pragma once 

// DOMEventHandler.h 

//------------------------------------------------------------------------- 

// Created :2009-1-2 WangJia 

//------------------------------------------------------------------------- 

 

typedef void (*PFN_DOM_EVENT_CALLBACK)(VARIANT* pVarResult, LONG_PTR lpUserData); 

 

class CDOMEventHandler : public IDispatch 

public: 

CDOMEventHandler(PFN_DOM_EVENT_CALLBACK pfnCallback, LONG_PTR lpUserData); 

~CDOMEventHandler(void); 

 

HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject); 

DWORD __stdcall AddRef(); 

DWORD __stdcall Release(); 

 

STDMETHOD(GetTypeInfoCount)(unsigned int FAR* pctinfo) { return E_NOTIMPL; } 

STDMETHOD(GetTypeInfo)(unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo) { return E_NOTIMPL; } 

 

STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgDispId) { return S_OK; } 

 

STDMETHOD(Invoke)(DISPID dispIdMember 

, REFIID riid 

, LCID lcid 

, WORD wFlags 

, DISPPARAMS* pDispParams 

, VARIANT* pVarResult 

, EXCEPINFO * pExcepInfo 

, UINT * puArgErr 

); 

 

static LPDISPATCH CreateEventHandler(PFN_DOM_EVENT_CALLBACK pfnCallback, LONG_PTR lpUserData); 

static VARIANT CreateEventHandlerVariant(PFN_DOM_EVENT_CALLBACK pfnCallback, LONG_PTR lpUserData); 

 

private: 

PFN_DOM_EVENT_CALLBACK m_pfCallback; 

long m_lRefCount; 

LONG_PTR m_lpUserData; 

}; 

 

 

 

#include "StdAfx.h" 

#include "DOMEventHandler.h" 

 

// DOMEventHandler.cpp 

//------------------------------------------------------------------------- 

// Created :2009-1-2 WangJia 

//-------------------------------------------------------------------------

 

CDOMEventHandler::CDOMEventHandler(PFN_DOM_EVENT_CALLBACK pfnCallback, LONG_PTR lpUserData) 

: m_lRefCount(0) 

, m_pfCallback(pfnCallback) 

, m_lpUserData(lpUserData) 

 

CDOMEventHandler::~CDOMEventHandler(void) 

 

 

HRESULT __stdcall CDOMEventHandler::QueryInterface(REFIID riid, void** ppvObject) 

*ppvObject = NULL; 

 

if (IsEqualGUID(riid, IID_IUnknown)) 

*ppvObject = reinterpret_cast<void**>(this); 

 

if (IsEqualGUID(riid, IID_IDispatch)) 

*ppvObject = reinterpret_cast<void**>(this); 

 

if (*ppvObject) 

((IUnknown*)*ppvObject)->AddRef(); 

return S_OK; 

else 

return E_NOINTERFACE; 

 

DWORD __stdcall CDOMEventHandler::AddRef() 

return InterlockedIncrement(&m_lRefCount); 

 

DWORD __stdcall CDOMEventHandler::Release() 

if (InterlockedDecrement(&m_lRefCount) == 0) 

delete this; 

return 0; 

return m_lRefCount; 

 

HRESULT CDOMEventHandler::Invoke(DISPID dispIdMember, 

REFIID riid, 

LCID lcid, 

WORD wFlags, 

DISPPARAMS* pDispParams, 

VARIANT* pVarResult, 

EXCEPINFO * pExcepInfo, 

UINT * puArgErr) 

if (dispIdMember == DISPID_VALUE) 

if( m_pfCallback ) 

(*m_pfCallback)(pVarResult, m_lpUserData); 

 

return S_OK; 

 

LPDISPATCH CDOMEventHandler::CreateEventHandler(PFN_DOM_EVENT_CALLBACK pfnCallback, LONG_PTR lpUserData) 

CDOMEventHandler * pHandler = new CDOMEventHandler( pfnCallback, lpUserData); 

return reinterpret_cast<LPDISPATCH>(pHandler); 

 

VARIANT CDOMEventHandler::CreateEventHandlerVariant(PFN_DOM_EVENT_CALLBACK pfnCallback, LONG_PTR lpUserData) 

VARIANT variant; 

variant.vt = VT_DISPATCH; 

variant.pdispVal = CDOMEventHandler::CreateEventHandler( pfnCallback, lpUserData); 

return variant; 

 

 

 

第2步,添加你自己的回调函数。这里只是举例。 

 

class CTestHtmlViewView : public CHtmlView 

static void OnLoad(VARIANT* pVarResult, LONG_PTR lpUserData); 

}; 

void CTestHtmlViewView::OnLoad(VARIANT* pVarResult, LONG_PTR lpUserData) 

CTestHtmlViewView * pThis = reinterpret_cast<CTestHtmlViewView*>(lpUserData); 

::MessageBox( NULL, _T("OnLoad"), NULL, MB_OK); 

第3步,根据你自己的情况,挂接onload, 代码参考上面。 

 

基本就这样,如果你的页面有框架,iframe中的window也是能够挂接onload的哦, 反正一切都和JS的一致。JS能够怎么实现,VC就能如何实现。


原文链接:http://hi.baidu.com/jakisou/item/24ee96161e0cc5721109b56f

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值