View头文件WebView.h:
#ifndef __WEBVIEW_H__
#define __WEBVIEW_H__
#pragma once
class CWebView : public CHtmlView
{
public: // 仅从序列化创建
CWebView();
virtual ~CWebView();
DECLARE_DYNCREATE(CWebView)
// 操作
public:
int GetScrollHeight(); // 返回滚动条的高度
// 对于有多个iframe的网页,所有页面加载完成,调用该方法,只调用一次
static void OnLoad(VARIANT *pVarResult, LONG_PTR lpUserData);
// 重写
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual void OnInitialUpdate(); // 构造后第一次调用
// 页面加载完成调用,对于有多个iframe的网页,可能会调用多次
virtual void OnDocumentComplete(LPCTSTR lpszURL);
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
// 生成的消息映射函数
protected:
DECLARE_MESSAGE_MAP()
};
#endif // __WEBVIEW_H__
实现WebView.c:
// WebView.cpp : implementation file
//
#include "stdafx.h"
#include "WebView.h"
#include "DOMEventHandler.h"
#include <afxctl.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CWebView
IMPLEMENT_DYNCREATE(CWebView, CHtmlView)
BEGIN_MESSAGE_MAP(CWebView, CHtmlView)
// 标准打印命令
ON_COMMAND(ID_FILE_PRINT, &CHtmlView::OnFilePrint)
END_MESSAGE_MAP()
// CBENBEN_IEView 构造/析构
CWebView::CWebView()
{
}
CWebView::~CWebView()
{
}
BOOL CWebView::PreCreateWindow(CREATESTRUCT& cs)
{
return CHtmlView::PreCreateWindow(cs);
}
// 构造后第一次调用
void CWebView::OnInitialUpdate()
{
CHtmlView::OnInitialUpdate();
}
// 获取滚动条的高度
int CWebView::GetScrollHeight()
{
CWebView *pView = (CWebView *)this;
HRESULT hr;
CComPtr<IDispatch> spDisp;
// 获取COM组件的IDispatch的接口
spDisp = pView->GetHtmlDocument();
if (!spDisp)
return 0;
// 查询IID为IID_IHTMLDocument2的接口
IHTMLDocument2 *pHtmlDoc = NULL;
hr = spDisp->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc);
ASSERT(SUCCEEDED(hr));
if (!pHtmlDoc)
return 0;
// 取得IHTMLElement类型的body接口
IHTMLElement *pHtmlElement = NULL;
hr = pHtmlDoc->get_body(&pHtmlElement);
ASSERT(SUCCEEDED(hr));
if (!pHtmlElement)
return 0;
// 查询IID为IID_IHTMLElement2的接口
IHTMLElement2 *pHtmlElement2 = NULL;
hr = pHtmlElement->QueryInterface(IID_IHTMLElement2, (void **)&pHtmlElement2);
ASSERT(SUCCEEDED(hr));
if (!pHtmlElement2)
return 0;
// 取得网页中滚动条的滚动范围
long lScrollHeight;
pHtmlElement2->get_scrollHeight(&lScrollHeight);
return lScrollHeight;
}
// 页面加载完成调用,对于有多个iframe的网页,可能会调用多次
void CWebView::OnDocumentComplete( LPCTSTR lpszURL )
{
IHTMLDocument *pHtmlDoc = (IHTMLDocument *)GetHtmlDocument();
CComQIPtr<IHTMLDocument2> pHtmlDoc2(pHtmlDoc);
if(pHtmlDoc2)
{
CComPtr<IHTMLWindow2> pHtmlWnd2;
pHtmlDoc2->get_parentWindow(&pHtmlWnd2);
if(pHtmlWnd2)
{
VARIANT vEvent = CDOMEventHandler::CreateEventHandlerVariant(&CWebView::OnLoad, (LONG_PTR)this);
pHtmlWnd2->put_onload(vEvent);
}
}
CHtmlView::OnDocumentComplete(lpszURL);
}
// 对于有多个iframe的网页,所有页面加载完成,调用该方法,只调用一次
void CWebView::OnLoad( VARIANT *pVarResult, LONG_PTR lpUserData )
{
CWebView *pWebView = reinterpret_cast<CWebView *>(lpUserData);
}
DOMEventHandler.h 为判断网页是否加载完成而添加的类
#ifndef __DOMEVENTHANDLER_H__
#define __DOMEVENTHANDLER_H__
#pragma once
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;
};
#endif // __DOMEVENTHANDLER_H__
// DOMEventHandler.cpp : implementation file
//
#include "StdAfx.h"
#include "DOMEventHandler.h"
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;
}
最后在CMyDialog::OnInitDialog()中添加:
// 创建并加载网页视图
m_pWebView = new CWebView;
m_pWebView->Create(NULL, NULL, WS_CHILD | WS_VISIBLE, rcWebView, this, 2009);
m_pWebView->ShowWindow(SW_HIDE);
Navigate2("www.baidu.com",NULL,NULL);