现在要在应用程序创建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; }