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 为判断网页是否加载完成而添加的类
// 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);