IE对网页截图,最原始的activex。

时间:2021-03-09 21:05:38

现在要在应用程序创建ACITVEX控件,用ATL现成的就可以了,非常简单。但之前我在没有ATL的环境下需要实现一个IE控件去访问网页,并对网页截图,非常头痛,网上资料很少。后来经过多次实验,终于搞定。贴代码。

snapshotmaker.h

#ifndef __NG_SNAPSHOMAKER_H__
#define __NG_SNAPSHOMAKER_H__

#include <string>
#include "conn.h"
#include "method/method.h"
enum
{
	E_SANPSHOT_OK = 0,
	E_SANPSHOT_ERR,
};



class CSnapshotMaker : public IBrowserConnCallBack
{
public:
	CSnapshotMaker(std::wstring& strURL, std::wstring& strFilePath,  HWND hMsgWnd) ;


	~CSnapshotMaker();

	static void SetMsgWnd(HWND hMsgWnd);

	bool StartMake();

	void SetCallback(Method<void(CSnapshotMaker*, int)> fnCallBack);


	static LONG APIENTRY MsgWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );

	bool CreateMessageWindow();

	virtual void OnDocumentComplete(BSTR pURL);
	virtual void OnNavigateError();
	virtual CComPtr<IWebBrowser2> GetWebBrowser();

	std::wstring& GetURL() { return m_strURL;}
	std::wstring& GetFilePath(){return m_strFilePath;}
	HWND GetMsgWnd(){return m_hMsgWnd;}

	int GetDebugRef();

public:
	std::wstring m_strURL;
	std::wstring m_strFilePath;
	HWND m_hMsgWnd;
	HWND m_hWindow;

	CComPtr<IWebBrowser2> m_pWebBrowse ;
	CComPtr<IOleObject> iOleObject;
	CCon m_conn;

	Method<void(CSnapshotMaker*, int)> m_fnCallBack;
	long m_lScrollWidth ;
	long m_lScrollHeight ;

	int m_debugRef;

};

#endif

snapshotmaker.cpp

#include "stdafx.h"
#include "ngsnapshotmaker.h"
#include <windows.h>
#include "Image\Include\ximage.h"
#include <mshtmdid.h >
#define CHECK_HR_RET_IF_FALSE(x) \
	if (FAILED(x)) {return false;}

#define TIMER_ID 1

#if 0
#define CHECK_REF(x, T) \
	{ T* pUnkown = (T*)x; \
	pUnkown->AddRef(); \
	m_debugRef = pUnkown->Release(); \
}
#else
#define CHECK_REF(x,T)
#endif


class CControlContainer:public IOleClientSite,public IOleInPlaceSite, public IServiceProvider,
	public IOleContainer,
	public IOleControlSite,
	public IDocHostUIHandler,
	public IDispatch
{
public:
	HWND m_hWnd;
	ULONG m_refCnt;
public:
	STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
	{
		if(iid == IID_IUnknown)
		{
			*ppv = static_cast<IOleInPlaceSite*>(this);
		}
		else if(iid == IID_IOleClientSite)
		{
			*ppv = static_cast<IOleClientSite*>(this);
		}
		else if(iid == IID_IOleWindow)
		{
			*ppv = static_cast<IOleWindow*>(this);
		}
		else if(iid == IID_IOleInPlaceSite)
		{
			*ppv = static_cast<IOleInPlaceSite*>(this);
		}
		else if(iid == IID_IDocHostUIHandler)
		{
			*ppv = static_cast<IDocHostUIHandler*>(this);
		}
		else if(iid == IID_IDispatch)
		{
			*ppv = static_cast<IDispatch*>(this);
		}
		else
		{
			*ppv = NULL;
			return E_NOINTERFACE;

		}
		AddRef();
		return S_OK;

	}

	virtual /* [local] */ HRESULT STDMETHODCALLTYPE QueryService( 
		/* [in] */ REFGUID guidService,
		/* [in] */ REFIID riid,
		/* [out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
	{
		return S_FALSE;
	}
	STDMETHODIMP_(ULONG) AddRef()
	{

		return ++m_refCnt;
	}
	STDMETHODIMP_(ULONG) Release()
	{ 
		--m_refCnt;
		int nTmp = m_refCnt;
		if(m_refCnt == 0)		// 因为在对象已经销毁后再引用这个对象的数据将是非法的
			delete this;
		return nTmp;

	}

	CControlContainer(HWND hWnd)
	{
		m_hWnd = hWnd;
		m_refCnt = 1;
	}
	~CControlContainer()
	{
	}

	STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
	{

		return S_OK;
	}
	STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
	{
		return S_OK;	
	}
	STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
		LCID lcid, DISPID* rgdispid)
	{
		return S_OK;
	}
	STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
		LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
		EXCEPINFO* pexcepinfo, UINT* puArgErr)
	{

		switch (dispidMember)
		{
		case DISPID_AMBIENT_DLCONTROL:

			pvarResult->vt = VT_I4;

			// 不准弹框,只要图像,不下ACTIVEX,不运行ACTX,不要JAVAAPPLET,不要JS
			pvarResult->lVal = DLCTL_SILENT|DLCTL_DLIMAGES| DLCTL_NO_DLACTIVEXCTLS | DLCTL_NO_RUNACTIVEXCTLS 
				|DLCTL_NO_JAVA|DLCTL_NO_SCRIPTS;

			break;

		default:
			return DISP_E_MEMBERNOTFOUND;
		}

		return S_OK;
	}

	//IOleControlSite 
	STDMETHOD(SaveObject()) 
	{ 
		return E_NOTIMPL; 
	} 
	STDMETHOD(GetMoniker(DWORD,DWORD,IMoniker**)) 
	{ 
		return E_NOTIMPL; 
	} 
	STDMETHOD(GetContainer(IOleContainer **ppContainer)) 
	{ 
		return E_NOINTERFACE; 
	} 
	STDMETHOD(ShowObject()) 
	{ 
		return S_OK; 
	} 
	STDMETHOD(OnShowWindow(BOOL bShow)) 
	{ 
		return S_OK; 
	} 
	STDMETHOD(RequestNewObjectLayout()) 
	{ 
		return E_NOTIMPL; 
	} 
	//IOleWindow 
	STDMETHOD(GetWindow(HWND * pHwnd)) 
	{ 
		*pHwnd = m_hWnd; 
		return S_OK; 
	} 
	STDMETHOD(ContextSensitiveHelp(BOOL bEnterMode)) 
	{ 
		return S_OK; 
	} 
	//IOleInPlaceSite 
	STDMETHOD(CanInPlaceActivate()) 
	{ 
		return S_OK; 
	} 
	STDMETHOD(OnInPlaceActivate()) 
	{ 
		return S_OK; 
	} 
	STDMETHOD(OnUIActivate()) 
	{ 
		return S_OK; 
	} 
	STDMETHOD(GetWindowContext(/* [out] */ IOleInPlaceFrame **ppFrame,
		/* [out] */ IOleInPlaceUIWindow **ppDoc,
		/* [out] */ LPRECT lprcPosRect,
		/* [out] */ LPRECT lprcClipRect,
		/* [out][in] */ LPOLEINPLACEFRAMEINFO lpFrameInfo))
	{
		return E_NOTIMPL;
	}
	STDMETHOD(Scroll(SIZE scrollSize))
	{
		return S_OK;
	}
	STDMETHOD(OnUIDeactivate(BOOL bUndoable))
	{
		return S_OK;
	}
	STDMETHOD(OnInPlaceDeactivate())
	{
		return S_OK;
	}
	STDMETHOD(DiscardUndoState())
	{
		return S_OK;
	}
	STDMETHOD(DeactivateAndUndo())
	{
		return S_OK;
	}
	STDMETHOD(OnPosRectChange(LPCRECT lprcPosRect))
	{
		return S_OK;


	}


	//IOleContainer
	virtual HRESULT __stdcall ParseDisplayName(IBindCtx *pbc,LPOLESTR pszDisplayName,ULONG *pchEaten,IMoniker **ppmkOut)
	{
		return E_NOTIMPL;
	}

	virtual HRESULT __stdcall EnumObjects(DWORD grfFlags, IEnumUnknown **ppenum)
	{
		return E_NOTIMPL;
	}

	virtual HRESULT __stdcall LockContainer(BOOL flock)
	{
		return E_NOTIMPL;
	}


	//IOleControlSite
	virtual HRESULT __stdcall OnControlInfoChanged(void)
	{
		return S_OK;
	}
	virtual HRESULT __stdcall LockInPlaceActive(BOOL fLock)
	{
		return E_NOTIMPL;
	}
	virtual HRESULT __stdcall GetExtendedControl(IDispatch** ppDisp)
	{
		return E_NOTIMPL;
	}
	virtual HRESULT __stdcall TransformCoords(POINTL* pPtlHimetric ,POINTF* pPtfContainer ,DWORD dwFlags)
	{
		return S_OK;
	}
	virtual HRESULT __stdcall TranslateAccelerator(LPMSG pMsg ,DWORD grfModifiers)
	{
		return S_OK;
	}
	virtual HRESULT __stdcall OnFocus(BOOL fGotFocus)
	{
		return S_OK;
	}
	virtual HRESULT __stdcall ShowPropertyFrame(void)
	{
		return E_NOTIMPL;
	}


	STDMETHOD(ShowContextMenu)(/* [in] */ DWORD dwID,
		/* [in] */ POINT __RPC_FAR *ppt,
		/* [in] */ IUnknown __RPC_FAR *pcmdtReserved,
		/* [in] */ IDispatch __RPC_FAR *pdispReserved)
	{
		return S_OK;
	}
	STDMETHOD(GetHostInfo)( 
		/* [out][in] */ DOCHOSTUIINFO __RPC_FAR *pInfo)
	{
		pInfo->cbSize = sizeof(DOCHOSTUIINFO);  
		pInfo->dwFlags = DOCHOSTUIFLAG_DIALOG |   
			DOCHOSTUIFLAG_THEME  |   
			DOCHOSTUIFLAG_NO3DBORDER |   
			DOCHOSTUIFLAG_SCROLL_NO;  
		return S_OK; 
	}

	STDMETHOD(ShowUI)( 
		/* [in] */ DWORD dwID,
		/* [in] */ IOleInPlaceActiveObject __RPC_FAR *pActiveObject,
		/* [in] */ IOleCommandTarget __RPC_FAR *pCommandTarget,
		/* [in] */ IOleInPlaceFrame __RPC_FAR *pFrame,
		/* [in] */ IOleInPlaceUIWindow __RPC_FAR *pDoc)
	{
		return S_OK;
	}

	STDMETHOD(HideUI)(void)
	{
		return S_OK;
	}

	STDMETHOD(UpdateUI)(void)
	{
		return S_OK;
	}

	STDMETHOD(EnableModeless)(/* [in] */ BOOL fEnable)
	{
		return E_NOTIMPL;
	}

	STDMETHOD(OnDocWindowActivate)(/* [in] */ BOOL fEnable)
	{
		return E_NOTIMPL;
	}

	STDMETHOD(OnFrameWindowActivate)(/* [in] */ BOOL fEnable)
	{
		return E_NOTIMPL;
	}

	STDMETHOD(ResizeBorder)( 
		/* [in] */ LPCRECT prcBorder,
		/* [in] */ IOleInPlaceUIWindow __RPC_FAR *pUIWindow,
		/* [in] */ BOOL fRameWindow)
	{
		return E_NOTIMPL;
	}

	STDMETHOD(TranslateAccelerator)( 
		/* [in] */ LPMSG lpMsg,
		/* [in] */ const GUID __RPC_FAR *pguidCmdGroup,
		/* [in] */ DWORD nCmdID)
	{
		return S_FALSE;
	}


	STDMETHOD(GetOptionKeyPath)( 
		/* [out] */ LPOLESTR __RPC_FAR *pchKey,
		/* [in] */ DWORD dw)
	{

		return E_NOTIMPL;
	}

	STDMETHOD(GetDropTarget)(
		/* [in] */ IDropTarget __RPC_FAR *pDropTarget,
		/* [out] */ IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget)
	{

		return E_NOTIMPL;
	}

	STDMETHOD(GetExternal)( 
		/* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
	{
		return S_OK;
	}

	STDMETHOD(TranslateUrl)( 
		/* [in] */ DWORD dwTranslate,
		/* [in] */ OLECHAR __RPC_FAR *pchURLIn,
		/* [out] */ OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut)
	{

		return E_NOTIMPL;
	}


	STDMETHOD(FilterDataObject)( 
		/* [in] */ IDataObject __RPC_FAR *pDO,
		/* [out] */ IDataObject __RPC_FAR *__RPC_FAR *ppDORet)
	{

		return E_NOTIMPL;
	}

};



CSnapshotMaker::CSnapshotMaker( std::wstring& strURL, std::wstring& strFilePath, HWND hMsgWnd ):
m_strURL(strURL),
m_strFilePath(strFilePath),
m_hMsgWnd(hMsgWnd),
m_hWindow(0),
m_lScrollWidth(0),
m_lScrollHeight(0),
m_debugRef(0)
{

}

CSnapshotMaker::~CSnapshotMaker()
{
	// 消毁窗口
	CHECK_REF(iOleObject, IOleObject);
	DestroyWindow(m_hWindow);
	if (iOleObject != NULL)
	{
		iOleObject->Close(0);
	}
	CHECK_REF(iOleObject, IOleObject);

	CoUninitialize();
}

bool CSnapshotMaker::StartMake()
{	
	CoInitialize(NULL);
	if (!CreateMessageWindow())
	{
		return false;
	}

	// 设置一个二十秒到期的定时器
	SetTimer(m_hWindow, reinterpret_cast<UINT_PTR>(this), 20000, NULL );

	SetWindowPos(m_hWindow, HWND_TOP, 0, 0, 100, 130, SWP_HIDEWINDOW);

	HRESULT hr = S_FALSE;
	CComPtr<IUnknown> iUnknown = NULL;
	hr = ::CoCreateInstance(CLSID_WebBrowser,
		NULL,
		CLSCTX_INPROC_SERVER ,
		IID_IUnknown,
		(void**)(&iUnknown));

	CHECK_HR_RET_IF_FALSE(hr);


	hr = iUnknown->QueryInterface(IID_IOleObject, (void**)(&iOleObject));
	CHECK_HR_RET_IF_FALSE(hr);

	//CControlContainer是实现了IOleClientSite和IOleInPlaceSite接口的类 
	CControlContainer* pContainer = new CControlContainer(m_hWindow); 

	//调用IOleObject::SetClientSite,传入容器指针 
	CHECK_HR_RET_IF_FALSE(iOleObject->SetClientSite(pContainer)); 
	CHECK_REF(iOleObject, IOleObject)
	if (pContainer)
	{
		pContainer->Release();
	}

	RECT rect ;
	::GetClientRect(m_hWindow, &rect);

	hr = iOleObject->DoVerb(OLEIVERB_SHOW, NULL, pContainer, 0, m_hWindow, &rect);
	CHECK_HR_RET_IF_FALSE(hr);

	CHECK_REF(iOleObject, IOleObject)

	CComPtr<IOleInPlaceObject> pInPlaceObject;

	hr = iOleObject->QueryInterface(IID_IOleInPlaceObject,(void**)&pInPlaceObject);
	CHECK_HR_RET_IF_FALSE(hr);
	CHECK_HR_RET_IF_FALSE(pInPlaceObject->SetObjectRects(&rect,&rect));
	
	CHECK_REF(iOleObject, IOleObject)
	hr = iOleObject->QueryInterface(IID_IWebBrowser2, (void**)&m_pWebBrowse);
	CHECK_HR_RET_IF_FALSE(hr);
	CHECK_REF(iOleObject, IOleObject)
	m_conn.ConnectEvents(this);

	VARIANT vUrl;
	vUrl.vt = VT_BSTR;
	vUrl.bstrVal = ::SysAllocString(m_strURL.c_str());

	VARIANT vFlags, vNull;
	vFlags.vt = VT_I4;
	vFlags.lVal = long(navNoHistory | navNoReadFromCache | navNoWriteToCache);

	vNull.vt = VT_BSTR;
	vNull.bstrVal = NULL;

	VARIANT vPostData;
	memset(&vPostData, 0, sizeof(vPostData));
	vPostData.vt = VT_ARRAY;

	VARIANT_BOOL varSli;
	varSli =  VARIANT_TRUE;
	m_pWebBrowse->put_Silent(varSli);
	hr = m_pWebBrowse->Navigate2(&vUrl, &vFlags, &vNull, &vPostData, &vNull);
	::SysFreeString(vUrl.bstrVal);
	CHECK_HR_RET_IF_FALSE(hr);
	CHECK_REF(iOleObject, IOleObject);


	return true;
}


#define NGSNAPSHOT_FAILED (WM_USER + 0x01)
#define NGSNAPSHOT_OK (WM_USER + 0x02)
#define NGSNAPSHOT_ADJUSTSCREEN (WM_USER + 0x03)



LONG APIENTRY CSnapshotMaker::MsgWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	LONG lRet = 0;

	switch(message)
	{
	case NGSNAPSHOT_FAILED:
		{
			CSnapshotMaker* pThis = reinterpret_cast<CSnapshotMaker*>(wParam);
			if (pThis ==NULL )
			{
				break;
			}
		
			pThis->m_fnCallBack(pThis, E_SANPSHOT_ERR);
		}
		break;

	case NGSNAPSHOT_OK:
		{

		}
		break;

	case WM_TIMER:
		{
			CSnapshotMaker* pThis = reinterpret_cast<CSnapshotMaker*>(wParam);
			if (pThis ==NULL )
			{
				break;
			}
			KillTimer(hWnd, wParam);
			pThis->m_fnCallBack(pThis, E_SANPSHOT_ERR);
			
		}
		break;

	case NGSNAPSHOT_ADJUSTSCREEN:
		{
			CSnapshotMaker* pThis = reinterpret_cast<CSnapshotMaker*>(wParam);
			if (pThis ==NULL )
			{
				break;
			}


			long lScrollWidth = pThis->m_lScrollWidth;
			long lScrollHeight = pThis->m_lScrollHeight;

			//调整WebBrowser大小和网页大小一致  
			RECT rc = { 0,0,lScrollWidth , lScrollHeight };  


			if (lScrollHeight >= 768)
			{
				lScrollHeight = 768;
			}

			HDC hWndDC =  GetDC(hWnd);
			HBITMAP hBitmap = ::CreateCompatibleBitmap(hWndDC, lScrollWidth, lScrollHeight);  
			HDC hBitmapDC = ::CreateCompatibleDC(hWndDC);  
			::SelectObject( hBitmapDC , hBitmap );  

			RECTL rctl = { rc.left , rc.top , rc.right , rc.bottom };  
			//绘画WebBrowser中的网页内容  
			//GetHWND()返回WebBrowser容器窗口句柄  
			DVASPECTINFO info;
			info.cb = sizeof(info);
			info.dwFlags = DVASPECTINFOFLAG_CANOPTIMIZE;

			CComPtr<IViewObject> pViewObject2 ;  
			HRESULT hr = pThis->m_pWebBrowse->QueryInterface( IID_IViewObject , (void**)&pViewObject2 ) ;  
			if (FAILED(hr))
			{
				ReleaseDC(hWnd, hWndDC);
				DeleteDC(hBitmapDC);
				DeleteObject(hBitmap);
				pThis->m_fnCallBack(pThis, E_SANPSHOT_ERR);

				break;
			}
			// draw screen snapshot.
			hr = pViewObject2->Draw(DVASPECT_CONTENT, 1, &info, 
				NULL, hWndDC, hBitmapDC, &rctl, NULL, NULL, 0) ;  
			if (FAILED(hr))
			{
				ReleaseDC(hWnd, hWndDC);
				DeleteDC(hBitmapDC);
				DeleteObject(hBitmap);
				pThis->m_fnCallBack(pThis, E_SANPSHOT_ERR);

				break;
			}

			CxImage xImage;
			bool bRet = xImage.CreateFromHBITMAP(hBitmap);
			if (bRet)
			{
				// 必须整点高斯模糊的效果,否则很JER丑
				xImage.Resample2(208, 130, CxImage::IM_GAUSSIAN);

				// 判断图像是不是全黑全白的,如果是,那就不用这个图。
				// 因为有可能是全FLASH的页面,此时由于ACTX被梦用,所以FLASH渲染失败,是黑色页
				// 先把图像用双线性缩小采样为3*3,如果这九个像素都是黑色,那么认为该页是黑页
				CxImage xImageDownSample(xImage);
				xImageDownSample.Resample2(3, 3, CxImage::IM_BILINEAR);

				BOOL bAllWhite = TRUE;
				BOOL bAllBlack = TRUE;
				for (DWORD dwWith = 0; dwWith < xImageDownSample.GetWidth(); ++dwWith)
				{
					for (DWORD dwHeight = 0; dwHeight < xImageDownSample.GetHeight(); ++dwHeight)
					{
						RGBQUAD clr = xImageDownSample.GetPixelColor(dwHeight, dwWith);
						if (clr.rgbBlue != 0 || clr.rgbGreen != 0 || clr.rgbRed != 0)
						{
							bAllBlack = FALSE;
						}

						if (clr.rgbBlue != 255 || clr.rgbGreen != 255 || clr.rgbRed != 255)
						{
							bAllWhite = FALSE;
						}
					}
				}

				if (!bAllBlack && !bAllWhite)
				{
					if(xImage.Save(pThis->m_strFilePath.c_str(), CXIMAGE_FORMAT_PNG) )
					{
						pThis->m_fnCallBack(pThis, E_SANPSHOT_OK);
						ReleaseDC(hWnd, hWndDC);
						DeleteDC(hBitmapDC);
						DeleteObject(hBitmap);
						break;
					}
				}
			}		
			ReleaseDC(hWnd, hWndDC);
			DeleteDC(hBitmapDC);
			DeleteObject(hBitmap);
			pThis->m_fnCallBack(pThis, E_SANPSHOT_ERR);

		}
		break;
	default:
		lRet = ::DefWindowProc(hWnd,message,wParam,lParam);
		break;
	}
	return lRet;
}



bool CSnapshotMaker::CreateMessageWindow()
{
	const TCHAR aszWindowName[] = _T("CSnapshotMaker-B4A4C9A8-DB30-4f0b-9172-773BC69E808B");

	WNDCLASSEX wc    = {sizeof(wc)};
	wc.hInstance     = GetModuleHandle(0);
	wc.lpszClassName = aszWindowName;
	wc.lpfnWndProc   = &CSnapshotMaker::MsgWindowProc;
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.cbWndExtra    = sizeof(void*);
	RegisterClassEx(&wc);

	m_hWindow = CreateWindowEx (0, aszWindowName,
		aszWindowName,
		WS_POPUP,
		0, 0, 0, 0, 
		NULL, 
		NULL, 
		wc.hInstance, 
		NULL
		);

	return (NULL != m_hWindow);
	
}


#define CHECK_HR_RET_IF_FAILED(hr) \
	if (FAILED(hr)){::PostMessage(m_hWindow, NGSNAPSHOT_FAILED, (WPARAM)((void*)this), NULL ); return;  }

void CSnapshotMaker::OnDocumentComplete( BSTR pURL )
{
	CHECK_REF(iOleObject, IOleObject);
	{
		CComPtr<IHTMLElement> pBodyElem;  
		CComPtr<IHTMLDocument2> pDoc = NULL;
		HRESULT	hr = m_pWebBrowse->get_Document((IDispatch**)&pDoc);
		CHECK_HR_RET_IF_FAILED(hr);

		if (pDoc == NULL)
		{
			::PostMessage(m_hWindow, NGSNAPSHOT_FAILED, (WPARAM)((void*)this), NULL );
			return;
		}

		CHECK_HR_RET_IF_FAILED(pDoc->get_body(&pBodyElem));  

		CHECK_REF(iOleObject, IOleObject);


		CComPtr<IHTMLBodyElement> pBody ;

		CHECK_HR_RET_IF_FAILED(pBodyElem->QueryInterface(IID_IHTMLBodyElement, (void**)&pBody));

		CHECK_REF(iOleObject, IOleObject);


		CComPtr<IViewObject> pViewObject2 ;  
		CHECK_HR_RET_IF_FAILED((m_pWebBrowse->QueryInterface( IID_IViewObject , (void**)&pViewObject2 ) ));  

		CHECK_REF(iOleObject, IOleObject);


		// resize the browser component to the size of the HTML content  
		CComPtr<IHTMLElement2> pBodyElement2;  
		CHECK_HR_RET_IF_FAILED( pBodyElem->QueryInterface(IID_IHTMLElement2, (void**)&pBodyElement2) );  

		CHECK_REF(iOleObject, IOleObject);


		CHECK_HR_RET_IF_FAILED( pBodyElement2->get_scrollWidth(&m_lScrollWidth) );  

		CHECK_HR_RET_IF_FAILED( pBodyElement2->get_scrollHeight(&m_lScrollHeight) );  


		// 判断是否是正常网页
		if (m_lScrollWidth < 200 && m_lScrollHeight < 200)
		{
			// 非正常网页,通知失败
			CHECK_HR_RET_IF_FAILED(S_FALSE);
		}

		SetWindowPos(m_hWindow, HWND_TOP, 0, 0, m_lScrollWidth, m_lScrollHeight, SWP_HIDEWINDOW);
		::UpdateWindow(m_hWindow);

		CComPtr<IOleInPlaceObject> pInPlace;
		CHECK_HR_RET_IF_FAILED((m_pWebBrowse->QueryInterface( IID_IOleInPlaceObject , (void**)&pInPlace ) ));  

		CHECK_REF(iOleObject, IOleObject);

		RECT rect ;
		::GetClientRect(m_hWindow, &rect);
		pInPlace->SetObjectRects(&rect, &rect);
		BSTR bsScrollStyle = ::SysAllocString(L"no");
		pBody->put_scroll(bsScrollStyle);
		SysFreeString(bsScrollStyle);

		CComPtr<IHTMLStyle> pStyle;  
		pBodyElem->get_style(&pStyle) ;  

		CHECK_REF(iOleObject, IOleObject);


		BSTR bsBorderStyle = ::SysAllocString(L"no");
		pStyle->put_borderStyle( bsBorderStyle);
		SysFreeString(bsBorderStyle);
		::PostMessage(m_hWindow, NGSNAPSHOT_ADJUSTSCREEN, WPARAM(this), NULL );
	}
	CHECK_REF(iOleObject, IOleObject);

}

void CSnapshotMaker::OnNavigateError()
{
	::PostMessage(m_hWindow, NGSNAPSHOT_FAILED, WPARAM(this), 0 );
}

CComPtr<IWebBrowser2> CSnapshotMaker::GetWebBrowser()
{
	return m_pWebBrowse;
}

int CSnapshotMaker::GetDebugRef()
{
	CHECK_REF(iOleObject, IOleObject);
	return m_debugRef;
}

void CSnapshotMaker::SetCallback( Method<void(CSnapshotMaker*, int)> pCallBack )
{
	m_fnCallBack = pCallBack;
}

conn.h

#pragma once
#include <Unknwn.h>

class IBrowserConnCallBack
{
public:
	virtual void OnDocumentComplete(BSTR pURL) =  0;
	virtual void OnNavigateError() =  0;
	virtual CComPtr<IWebBrowser2> GetWebBrowser() =  0;

};

class CCon:public IDispatch
{
public:
	CCon();
	~CCon(void);
	ULONG m_refCnt;
	IID m_iid;
	CComPtr<IWebBrowser2> m_pIE;
	IBrowserConnCallBack* m_pCallBack;
	DWORD m_dwCookie;

	CComPtr<IConnectionPoint> m_pConnectionPoint;
	void ConnectEvents(IBrowserConnCallBack* pCallBack);
	void Exit();
	STDMETHOD_(ULONG,AddRef())
	{
		return ++m_refCnt;
	}
	STDMETHOD_(ULONG,Release())
	{
		if (--m_refCnt == 0)
		{
			delete this;
			return 0;
		}
		return m_refCnt;
	}
	STDMETHOD(QueryInterface(REFIID riid,void **ppvObject))
	{
		*ppvObject = NULL;
		if ( IID_IUnknown == riid)
		{
			*ppvObject = (IUnknown*)this;
		}
		else if (IID_IDispatch == riid || m_iid == riid)
		{
			*ppvObject = (IDispatch*)this;
		}
		else
		{
			return E_NOINTERFACE;
		}
		AddRef();
		return S_OK;
	}
	//IDispatch
	//IDispatch
	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 E_NOTIMPL;
	}
	STDMETHOD(Invoke( 
		DISPID  dispIdMember,
		REFIID  riid,              
		LCID  lcid,                
		WORD  wFlags,              
		DISPPARAMS FAR*  pDispParams,  
		VARIANT FAR*  pVarResult,  
		EXCEPINFO FAR*  pExcepInfo,  
		unsigned int FAR*  puArgErr  
		));
};

conn.cpp

#include "StdAfx.h"
#include "Conn.h"
#include <ExDisp.h>
#include <ExDispid.h>
#include "oaidl.h"
CCon::CCon():m_pCallBack(0)
{
}

CCon::~CCon(void)
{
	Exit();
}

void CCon::ConnectEvents(IBrowserConnCallBack* pCallBack)
{
	if (!pCallBack)
	{
		return;
	}

	m_pCallBack = pCallBack;
	m_pIE = m_pCallBack->GetWebBrowser();

	CComPtr<IConnectionPointContainer> pCPContainer;

	// Step 1: 获取连接点的指针.
	//
	HRESULT hr = m_pIE->QueryInterface(IID_IConnectionPointContainer, 
		(void**)&pCPContainer);
	if (SUCCEEDED(hr))
	{
		// m_pConnectionPoint is defined like this:
		// IConnectionPoint* m_pConnectionPoint;

		// Step 2: 选找连接点.
		//
		hr = pCPContainer->FindConnectionPoint(DIID_DWebBrowserEvents2, 
			&m_pConnectionPoint);

		if (SUCCEEDED(hr))
		{
			// Step 3: 实现连接点地事件接收
			//
			hr = m_pConnectionPoint->Advise(this, &m_dwCookie);
			if (FAILED(hr))
			{

			}
		}
	}
}

void CCon::Exit()
{
	// Step 5: Unadvise. 注意m_pConnectionPoint 应当在CCon的析构函数中释放
	//
	if (m_pConnectionPoint)
	{
		HRESULT hr = m_pConnectionPoint->Unadvise(m_dwCookie);
		if (FAILED(hr))
		{

		}
	}
}

extern void OnCallBack(IDispatch* pDispatch,  BSTR val);

HRESULT __stdcall CCon::Invoke( 
	DISPID  dispIdMember,
	REFIID  riid,              
	LCID  lcid,                
	WORD  wFlags,              
	DISPPARAMS FAR*  pDispParams,  
	VARIANT FAR*  pVarResult,  
	EXCEPINFO FAR*  pExcepInfo,  
	unsigned int FAR*  puArgErr  
	)
{
	USES_CONVERSION;


	if (!pDispParams)
		return E_INVALIDARG;

	switch (dispIdMember)
	{
		// The parameters for this DISPID:
		// [0]: URL navigated to - VT_BYREF|VT_VARIANT
		// [1]: An object that evaluates to the top-level or frame
		// WebBrowser object corresponding to the event. 
		//
	case DISPID_DOCUMENTCOMPLETE:
		// Check the argument's type.
		if (pDispParams->rgvarg[0].vt == (VT_BYREF|VT_VARIANT))
		{
			CComVariant varURL(*pDispParams->rgvarg[0].pvarVal);
			varURL.ChangeType(VT_BSTR);

			//if (varURL.bstrVal == std::wstring(L""))
			//{
			//	break;
			//}

			if (pDispParams->rgvarg[1].vt == VT_DISPATCH)
			{
				CComPtr<IDispatch> pDispatch = pDispParams->rgvarg[1].pdispVal;
				if (pDispatch )
				{
					CComPtr<IWebBrowser2> pWebBrowseDisp ;
					pDispatch->QueryInterface(IID_IWebBrowser2,(void**)&pWebBrowseDisp);
					if (pWebBrowseDisp == m_pIE)
					{
						m_pCallBack->OnDocumentComplete(varURL.bstrVal);
					}
				}
			}

			// strEventInfo is an object of type strstream.


		}
		break;

	case DISPID_NAVIGATEERROR:
		{
			if ((pDispParams->rgvarg[4].vt == VT_DISPATCH) && (pDispParams->rgvarg[1].vt == (VT_VARIANT|VT_BYREF)))
			{
				//VARIANT* n = pDispParams->rgvarg[1].pvarVal;
				//int k = n->intVal;
				//k++;

				CComPtr<IDispatch> pDispatch = pDispParams->rgvarg[4].pdispVal;
				if (pDispatch )
				{
					CComPtr<IWebBrowser2> pWebBrowseDisp ;
					pDispatch->QueryInterface(IID_IWebBrowser2,(void**)&pWebBrowseDisp);
					if (pWebBrowseDisp == m_pIE)
					{
						// error
						//return;
						m_pCallBack->OnNavigateError();
					}
				}
			}
		}
		break;

		//拦截弹出窗口
	case DISPID_NEWWINDOW2:
		{
			if (pDispParams->rgvarg[0].vt == (VT_BOOL|VT_BYREF))
			{
				*pDispParams->rgvarg[0].pboolVal = VARIANT_TRUE;				
			}
		}
		break;


		// 要是遇上跳转!!!
	case DISPID_BEFORENAVIGATE2:
		{
			//*pDispParams->rgvarg[0].pboolVal = VARIANT_TRUE;
			//break;
			if (pDispParams->rgvarg[5].vt == (VT_VARIANT|VT_BYREF))
			{
				CComVariant varURL(*pDispParams->rgvarg[5].pvarVal);
				varURL.ChangeType(VT_BSTR);

				OutputDebugString(varURL.bstrVal);
				IDispatch* pDispatch = pDispParams->rgvarg[6].pdispVal;
				if (pDispatch )
				{
					CComPtr<IWebBrowser2> pWebBrowseDisp;
					pDispatch->QueryInterface(IID_IWebBrowser2,(void**)&pWebBrowseDisp);
					if (m_pIE != pWebBrowseDisp)
					{
						// 取消不成功的跳转
						//*pDispParams->rgvarg[0].pboolVal = VARIANT_TRUE;

						break;
					}
					// 这是成功的跳转					
				}
			}
		}
		break;

	default:
		break;
	}

	return S_OK;
}