VC操作Web Browser的若干技巧

♀ 获取文档的总高度和宽度以及页面当前显示的文档位置
    以下代码用于获取页面当前显示的文档位置,如需获取文档的总高度和宽度,只需将函数get_scrollLeft()和get_scrollTop()换为get_scrollWidth()和get_scrollHeight()即可(注意,获取高度和宽度只有当收到WebBrowser的DocumentComplete事件后才有效)。其中m_pUiWeb为指向WebBrowser控件的指针。
  1. BOOL GetDocPos(LONG &nPosX, LONG &nPosY)  
  2. {  
  3.     nPosX = 0;  
  4.     nPosY = 0;  
  5.     IHTMLDocument2 *pWebDoc = (IHTMLDocument2*)m_pUiWeb->get_Document();  
  6.     IHTMLDocument3 *pWebDoc3 = NULL;  
  7.     HRESULT hRes = pWebDoc->QueryInterface(IID_IHTMLDocument3,  
  8.         (void**)&pWebDoc3);  
  9.     if( FAILED(hRes) || NULL == pWebDoc3 )  
  10.     {  
  11.         return FALSE;  
  12.     }  
  13.     IHTMLElement *pHtmlBody = NULL;  
  14.     hRes = pWebDoc3->get_documentElement(&pHtmlBody);  
  15.     if( FAILED(hRes) || NULL == pHtmlBody )  
  16.     {  
  17.         return FALSE;  
  18.     }  
  19.     IHTMLElement2 *pHtmlElement = NULL;  
  20.     hRes = pHtmlBody->QueryInterface(IID_IHTMLElement2, (void**)&pHtmlElement);  
  21.     if( FAILED(hRes) || NULL == pHtmlElement )  
  22.     {  
  23.         return FALSE;  
  24.     }  
  25.     hRes = pHtmlElement->get_scrollLeft(&nPosX);  
  26.     if( FAILED(hRes) )  
  27.     {  
  28.         nPosX = 0;  
  29.         return FALSE;  
  30.     }  
  31.     hRes = pHtmlElement->get_scrollTop(&nPosY);  
  32.     if( FAILED(hRes) )  
  33.     {  
  34.         nPosX = 0;  
  35.         nPosY = 0;  
  36.         return FALSE;  
  37.     }  
  38.     return TRUE;  
  39. }  
♀ 屏蔽或者修改鼠标右键菜单
    因为在WebBrowser中右键菜单是由Docment对象管理的,所以要屏蔽或者修改右键菜单,必须从Docment对象入手,WebBrowser向我们提供了IDocHostUIHandler接口以完成对Docment对象UI的相关操作,在该接口包含有一个ShowContextMenu()函数,通过对该函数的重载我们就可完成屏蔽或者修改右键菜单的任务。那么,我们只剩下了如何将Docment对象原有的UIHandler替换为我们自定义的UIHandler的任务,请参考下面的例子。其中,CDocHostUIHandler为自定义的UIHandler类。
  1. void NavigateComplete2(LPDISPATCH pDisp, VARIANT* URL)  
  2. {  
  3.     // 判断事件通知对象  
  4.     LPUNKNOWN pUnknown = m_pUiWeb->GetControlUnknown();  
  5.     if( NULL == pUnknown )  
  6.     {  
  7.         return;  
  8.     }  
  9.     LPUNKNOWN pUnknownWeb = NULL;  
  10.     LPUNKNOWN pUnknownDisp = NULL;  
  11.     HRESULT hr = pUnknown->QueryInterface(IID_IUnknown, (LPVOID*)&pUnknownWeb);  
  12.     if( FAILED(hr) )  
  13.     {  
  14.         return;  
  15.     }  
  16.     hr = pDisp->QueryInterface(IID_IUnknown, (LPVOID*)&pUnknownDisp);  
  17.     if( FAILED(hr) || pUnknownWeb != pUnknownDisp)  
  18.     {  
  19.         pUnknownWeb->Release();  
  20.         return;  
  21.     }  
  22.     pUnknownWeb->Release();  
  23.     pUnknownDisp->Release();  
  24.     // 修改Document对象  
  25.     if( NULL == m_pDocHostUiHandler )  
  26.     {  
  27.         m_pDocHostUiHandler = new CDocHostUIHandler();  
  28.     }  
  29.     IHTMLDocument2 *pHtmlDoc2 = (IHTMLDocument2*)m_pUiWeb->get_Document();  
  30.     ICustomDoc *pCustomDoc = NULL;  
  31.     hr = pHtmlDoc2->QueryInterface(IID_ICustomDoc,  
  32.         reinterpret_cast(&pCustomDoc));  
  33.     if( FAILED(hr) )  
  34.     {  
  35.         return;  
  36.     }  
  37.     pCustomDoc->SetUIHandler(m_pDocHostUiHandler);  
  38.     pCustomDoc->Release();  
  39. }  
    以下代码演示了如何屏蔽右键菜单:
  1. STDMETHODIMP CDocHostUIHandler::QueryInterface(REFIID riid, PVOID* pInterface)  
  2. {  
  3.     *pInterface = NULL;  
  4.     if (riid==IID_IUnknown)  
  5.     {  
  6.         *pInterface=this;  
  7.     }  
  8.     else if (riid==IID_IDocHostUIHandler)  
  9.     {  
  10.         *pInterface=this;  
  11.     }  
  12.     if(*pInterface)  
  13.     {  
  14.         AddRef();  
  15.         return S_OK;  
  16.     }  
  17.     return E_NOINTERFACE;  
  18. }  
  19.                              
  20. STDMETHODIMP CDocHostUIHandler::ShowContextMenu(DWORD dwID, POINT* pPt,  
  21.     IUnknown* pcmdtReserved, IDispatch* pdispreserved)  
  22. {  
  23.     return S_OK;  
  24. }  
    注意,由于微软提供的IDocHostUIHandler接口是继承自IUnknown的虚拟结构,所以如果要实现该接口,则必须实现该结构下的所有函数,对于不必做修改,只需保持原有功能的函数直接返回“E_NOTIMPL”即可。
♀ 加载内存中的页面(来自网络,未验证)
    或者因为网页保密的考虑;或者因为软件分发的考虑,有的时候就需要让IE或IE浏览器控件显示内存或资源中的HTML网页。在 MFC 中,CHtmlView::LoadFromResource() 可以显示程序资源中的 HTML 内容。我们都知道MFC的CHtmlView其实是对IWebBrowser2的一个包装,但是在 IWebBrowser2 中却没有类似的方法。那么它是如何实现的呢?步骤如下:
    1、首先通过IWebBrowser2::Navigate2()显示一个网页,其目的是产生有效的对象,从而得到IHTMLDocument2接口;
    2、IWebBrowser2::get_Document() 得到 IHTMLDocument2 接口指针;
    3、IHTMLDocument2::QueryInterface() 得到 IPersistStreamInit 接口指针;
    4、IPersistStreamInit::InitNew() 初始化接口对象;
    5、IPersistStreamInit::Load() 装载内存中的 HTML 数据流(IStream *);
        内存指针转换为流的方法是:
        I、  GlobalAlloc() 申请内存;
        II、 复制 HTML 字符串内容到上述的内存中;
        III、CreateStreamFromHGlobal() 转换内存为 IStream 指针;
    原理性代码如下:
  1. // 显示一个空白网页  
  2. m_ie.Navigate2( &CComVariant(_T("about:blank")),NULL,NULL,NULL,NULL);  
  3.    
  4. // 得到 IHTMLDocument2 指针  
  5. CComPtr< IDispatch > spDoc(m_ie.GetDocument());  
  6.    
  7. // 得到 IPersistStreamInit 指针  
  8. CComQIPtr< IPersistStreamInit, &IID_IPersistStreamInit > spPSI( spDoc );  
  9.    
  10. // 申请内存,复制 HTML 字符串  
  11. LPTSTR lpMem = (LPTSTR)::GlobalAlloc( GPTR, ::lstrlen( lpHtml )+1 );  
  12. lstrcpy( lpMem, "xxx xxx" );  
  13.    
  14. // 转换内存为流对象指针  
  15. CComPtr< IStream > spStream;  
  16. CreateStreamOnHGlobal( lpMem, TRUE, &spStream );  
  17.    
  18. // 初始化后,装载显示  
  19. spPSI->InitNew();  
  20. spPSI->Load( spStream );  
    IE 所能支持的数据传输协议,除了大家所熟悉的 http、ftp、file......还有一个协议是 res ,它表示浏览显示文件中的 HTML 资源。你可以在 IE 的地址栏上直接输入这样格式的 URL:"res://文件名/资源名"。
    把 HTML 文件加入到程序资源的方法比较简单,在资源卡片中,鼠标右键弹出菜单,执行 Import...(引入),选择指定的 HTML 文件,然后给一个资源名称即可。(在这里,最方便的资源名称用字符串比较好,如果使用整数ID,那么将来在使用的时候是这样的格式:res://文件名/#101,这里假设 101 是资源的ID号。真麻烦!我不太喜欢这样的方式。)对于图片文件等其它的附件,则需要手工编辑资源 RC 文件(用 IDE 环境引入,它会试图用文本方式打开一个2进制文件,多数情况下会“死机”)。
    手工编辑 RC 文件的部分是:
  1. ......  
  2. /  
  3. //  
  4. // HTML  
  5. //  
  6. // 这两个是HTML文件,可以引入  
  7. HTML_TOWORD      HTML DISCARDABLE  "res\\ToWord.htm"  
  8. HTML_DLG     HTML DISCARDABLE  "res\\html_dlg.htm"  
  9. // 下面的是GIF文件,需要手工加入  
  10. ~SEND_R1_C1.GIF  HTML DISCARDABLE  "res\\~Send_r1_c1.gif"  
  11. ~SEND_R1_C2.GIF  HTML DISCARDABLE  "res\\~Send_r1_c2.gif"  
  12. LOGO.GIF         HTML DISCARDABLE  "res\\Logo.gif"  
  13. SEND_R1_C1.GIF   HTML DISCARDABLE  "res\\Send_r1_c1.gif"  
  14. SEND_R1_C2.GIF   HTML DISCARDABLE  "res\\Send_r1_c2.gif"  
  15. SPACER.GIF       HTML DISCARDABLE  "res\\spacer.gif"  
  16. #endif  // Chinese (P.R.C.) resources  
  17. /  
♀ 响应事件
    WebBrowser的事件主要包括Control事件、Window事件及Docment事件三大类,微软分别提供了三个虚拟Event结构表示相关事件,分别是:DWebBrowserEvents、HTMLWindowEvents、HTMLDocumentEvents。使用时只需继承、实现相关Event结构,并安装相关事件即可。以下代码演示了如何继承、实现Docment事件。
  1. // 事件类定义class  
  2. CHtmlDocEvents : public HTMLDocumentEvents  
  3. {  
  4. public:  
  5.     CHtmlDocEvents();  
  6.     ~CHtmlDocEvents();  
  7.     DWORD m_dwCount;  
  8. protected:  
  9.     virtual STDMETHODIMP QueryInterface(REFIID,void**);  
  10.     virtual STDMETHODIMP_(DWORD) AddRef();  
  11.     virtual STDMETHODIMP_(DWORD) Release();  
  12.     virtual STDMETHODIMP GetTypeInfoCount(UINT*);   
  13.     virtual STDMETHODIMP GetTypeInfo(UINT,LCID,ITypeInfo**);  
  14.     virtual STDMETHODIMP GetIDsOfNames(REFIID,LPOLESTR*,UINT,LCID,DISPID*);  
  15.     virtual STDMETHODIMP Invoke(DISPID,REFIID,LCID,WORD,DISPPARAMS*,  
  16.         VARIANT*,EXCEPINFO*,UINT*);  
  17. };  
  18.                
  19. // 事件类实现  
  20. STDMETHODIMP CHtmlDocEvents::QueryInterface(REFIID riid, PVOID* ppInterface)  
  21. {  
  22.     *ppInterface = 0;  
  23.     if (riid==IID_IUnknown)  
  24.     {  
  25.         *ppInterface = this;  
  26.     }  
  27.     else if (riid==IID_IDispatch)  
  28.     {  
  29.         *ppInterface = this;  
  30.     }  
  31.     else if (riid==DIID_HTMLDocumentEvents)  
  32.     {  
  33.         *ppInterface = this;  
  34.     }  
  35.                
  36.     if (*ppInterface)  
  37.     {  
  38.         (*reinterpret_cast(ppInterface))->AddRef();  
  39.         return S_OK;  
  40.     }  
  41.                
  42.     return E_NOINTERFACE;  
  43. }  
  44.                
  45. STDMETHODIMP_(DWORD) CHtmlDocEvents::AddRef()  
  46. {  
  47.     m_dwCount++;  
  48.     return m_dwCount;  
  49. }  
  50.                
  51. STDMETHODIMP_(DWORD) CHtmlDocEvents::Release()  
  52. {  
  53.     m_dwCount--;  
  54.     return m_dwCount;  
  55. }  
  56.                
  57. STDMETHODIMP CHtmlDocEvents::GetIDsOfNames(REFIID, LPOLESTR*, UINT,  
  58.     LCID, DISPID*)  
  59. {  
  60.     return E_NOTIMPL;  
  61. }  
  62.                
  63. // ……  
  64. // ……  
  65.                
  66. STDMETHODIMP CHtmlDocEvents::Invoke(DISPID dispidMember, REFIID riid,  
  67.     LCID lcid, WORD wFlags, DISPPARAMS* pdispparams,  
  68.     VARIANT* pvarResult, EXCEPINFO* pexcepinfo,  
  69.     UINT* puArgErr)  
  70. {  
  71.     switch (dispidMember)  
  72.     {  
  73.         case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEMOVE:  
  74.         case DISPID_HTMLDOCUMENTEVENTS_ONHELP:  
  75.         case DISPID_HTMLDOCUMENTEVENTS_ONCLICK:  
  76.         case DISPID_HTMLDOCUMENTEVENTS_ONDBLCLICK:  
  77.         case DISPID_HTMLDOCUMENTEVENTS_ONKEYDOWN:  
  78.         case DISPID_HTMLDOCUMENTEVENTS_ONKEYUP:  
  79.         case DISPID_HTMLDOCUMENTEVENTS_ONKEYPRESS:  
  80.         case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEDOWN:  
  81.         case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEUP:  
  82.         case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOUT:  
  83.         case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOVER:  
  84.         case DISPID_HTMLDOCUMENTEVENTS_ONREADYSTATECHANGE:  
  85.         case DISPID_HTMLDOCUMENTEVENTS_ONBEFOREUPDATE:  
  86.         case DISPID_HTMLDOCUMENTEVENTS_ONAFTERUPDATE:  
  87.         case DISPID_HTMLDOCUMENTEVENTS_ONROWEXIT:  
  88.         case DISPID_HTMLDOCUMENTEVENTS_ONROWENTER:  
  89.         case DISPID_HTMLDOCUMENTEVENTS_ONDRAGSTART:  
  90.         case DISPID_HTMLDOCUMENTEVENTS_ONSELECTSTART:  
  91.         case DISPID_HTMLDOCUMENTEVENTS_ONERRORUPDATE:  
  92.         default:  
  93.             return E_NOTIMPL;  
  94.     }  
  95.              
  96.     return NOERROR;  
  97. }  
  98.                
  99. // ……  
    以下代码演示了如何安装Window和Docment事件,其中m_pUiWeb为指向WebBrowser对象的指针,m_pHtmlWindowEvents为指向自定义Window事件对象的指针,m_pHtmlDocEvents为指向CHtmlDocEvents对象的指针:
  1. void DocumentCompleteUiWeb(LPDISPATCH pDisp, VARIANT* URL)  
  2. {  
  3.     LPUNKNOWN pUnknown = m_pUiWeb->GetControlUnknown();  
  4.     if( NULL == pUnknown )  
  5.     {  
  6.         return;  
  7.     }  
  8.           
  9.     LPUNKNOWN pUnknownWeb = NULL;  
  10.     LPUNKNOWN pUnknownDisp = NULL;  
  11.     HRESULT hr = pUnknown->QueryInterface(IID_IUnknown, (LPVOID*)&pUnknownWeb);  
  12.     if( FAILED(hr) )  
  13.     {  
  14.         return;  
  15.     }  
  16.           
  17.     hr = pDisp->QueryInterface(IID_IUnknown, (LPVOID*)&pUnknownDisp);  
  18.     if( FAILED(hr) || pUnknownWeb != pUnknownDisp)  
  19.     {  
  20.         pUnknownWeb->Release();  
  21.         return;  
  22.     }  
  23.           
  24.     pUnknownWeb->Release();  
  25.     pUnknownDisp->Release();  
  26.     IHTMLDocument2 *pHtmlDoc2 = (IHTMLDocument2*)m_pUiWeb->get_Document();  
  27.     IConnectionPointContainer* pCPC = NULL;  
  28.     DWORD dwCookie = 0;  
  29.     {// 安装Web Window事件  
  30.         IHTMLWindow2 *pHtmlWnd2 = NULL;  
  31.         hr = pHtmlDoc2->get_parentWindow(&pHtmlWnd2);  
  32.         if( FAILED(hr) )  
  33.         {  
  34.             return;  
  35.         }  
  36.         hr = pHtmlWnd2->QueryInterface(IID_IConnectionPointContainer,  
  37.             reinterpret_cast(&pCPC));  
  38.         if(FAILED(hr))  
  39.         {  
  40.             return;  
  41.         }  
  42.         IConnectionPoint* pCP = NULL;  
  43.         pCPC->FindConnectionPoint(DIID_HTMLWindowEvents2, &pCP);  // 找到安装点  
  44.         if( NULL == m_pHtmlWindowEvents )  
  45.         {  
  46.             m_pHtmlWindowEvents = new CHtmlWindowEvents(this);  
  47.         }  
  48.         hr = pCP->Advise(m_pHtmlWindowEvents, &dwCookie);        //安装  
  49.         if( SUCCEEDED(hr) )  
  50.         {  
  51.             pCP->Release();  
  52.         }  
  53.         pCPC->Release();  
  54.     }  
  55.           
  56.     {// 安装Web Document事件  
  57.         hr = pHtmlDoc2->QueryInterface(IID_IConnectionPointContainer,  
  58.             reinterpret_cast(&pCPC));  
  59.         if(FAILED(hr))  
  60.         {  
  61.             return;  
  62.         }  
  63.         IConnectionPoint* pCP = NULL;  
  64.         pCPC->FindConnectionPoint(DIID_HTMLDocumentEvents2, &pCP); // 找到安装点  
  65.         if( NULL == m_pHtmlDocEvents )  
  66.         {  
  67.             m_pHtmlDocEvents = new CHtmlDocEvents(this, m_pMaskWnd, m_pUiWeb,  
  68.                 m_pPosIconWnd);  
  69.         }  
  70.         hr = pCP->Advise(m_pHtmlDocEvents, &dwCookie);   // 安装  
  71.         if( SUCCEEDED(hr) )  
  72.         {  
  73.             pCP->Release();  
  74.         }  
  75.         pCPC->Release();  
  76.     }  
  77. }  
♀ 用VC在网页中绘图
    用VC在网页上绘图主要通过WebBrowser的IElementBehavior接口和IHTMLPainter接口来实现。具体内容参照MSDN中的《Using Rendering Behaviors》说明,该说明中也有相关演示代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值