VC操作Web Browser的若干技巧

来源:互联网 发布:seo霸屏技术 编辑:程序博客网 时间:2024/05/23 19:17
♀ 获取文档的总高度和宽度以及页面当前显示的文档位置
    以下代码用于获取页面当前显示的文档位置,如需获取文档的总高度和宽度,只需将函数get_scrollLeft()和get_scrollTop()换为get_scrollWidth()和get_scrollHeight()即可(注意,获取高度和宽度只有当收到WebBrowser的DocumentComplete事件后才有效)。其中m_pUiWeb为指向WebBrowser控件的指针。
BOOL GetDocPos(LONG &nPosX, LONG &nPosY){    nPosX = 0;    nPosY = 0;    IHTMLDocument2 *pWebDoc = (IHTMLDocument2*)m_pUiWeb->get_Document();    IHTMLDocument3 *pWebDoc3 = NULL;    HRESULT hRes = pWebDoc->QueryInterface(IID_IHTMLDocument3,        (void**)&pWebDoc3);    if( FAILED(hRes) || NULL == pWebDoc3 )    {        return FALSE;    }    IHTMLElement *pHtmlBody = NULL;    hRes = pWebDoc3->get_documentElement(&pHtmlBody);    if( FAILED(hRes) || NULL == pHtmlBody )    {        return FALSE;    }    IHTMLElement2 *pHtmlElement = NULL;    hRes = pHtmlBody->QueryInterface(IID_IHTMLElement2, (void**)&pHtmlElement);    if( FAILED(hRes) || NULL == pHtmlElement )    {        return FALSE;    }    hRes = pHtmlElement->get_scrollLeft(&nPosX);    if( FAILED(hRes) )    {        nPosX = 0;        return FALSE;    }    hRes = pHtmlElement->get_scrollTop(&nPosY);    if( FAILED(hRes) )    {        nPosX = 0;        nPosY = 0;        return FALSE;    }    return TRUE;}
♀ 屏蔽或者修改鼠标右键菜单
    因为在WebBrowser中右键菜单是由Docment对象管理的,所以要屏蔽或者修改右键菜单,必须从Docment对象入手,WebBrowser向我们提供了IDocHostUIHandler接口以完成对Docment对象UI的相关操作,在该接口包含有一个ShowContextMenu()函数,通过对该函数的重载我们就可完成屏蔽或者修改右键菜单的任务。那么,我们只剩下了如何将Docment对象原有的UIHandler替换为我们自定义的UIHandler的任务,请参考下面的例子。其中,CDocHostUIHandler为自定义的UIHandler类。
void NavigateComplete2(LPDISPATCH pDisp, VARIANT* URL){    // 判断事件通知对象    LPUNKNOWN pUnknown = m_pUiWeb->GetControlUnknown();    if( NULL == pUnknown )    {        return;    }    LPUNKNOWN pUnknownWeb = NULL;    LPUNKNOWN pUnknownDisp = NULL;    HRESULT hr = pUnknown->QueryInterface(IID_IUnknown, (LPVOID*)&pUnknownWeb);    if( FAILED(hr) )    {        return;    }    hr = pDisp->QueryInterface(IID_IUnknown, (LPVOID*)&pUnknownDisp);    if( FAILED(hr) || pUnknownWeb != pUnknownDisp)    {        pUnknownWeb->Release();        return;    }    pUnknownWeb->Release();    pUnknownDisp->Release();    // 修改Document对象    if( NULL == m_pDocHostUiHandler )    {        m_pDocHostUiHandler = new CDocHostUIHandler();    }    IHTMLDocument2 *pHtmlDoc2 = (IHTMLDocument2*)m_pUiWeb->get_Document();    ICustomDoc *pCustomDoc = NULL;    hr = pHtmlDoc2->QueryInterface(IID_ICustomDoc,        reinterpret_cast(&pCustomDoc));    if( FAILED(hr) )    {        return;    }    pCustomDoc->SetUIHandler(m_pDocHostUiHandler);    pCustomDoc->Release();}
    以下代码演示了如何屏蔽右键菜单:
STDMETHODIMP CDocHostUIHandler::QueryInterface(REFIID riid, PVOID* pInterface){    *pInterface = NULL;    if (riid==IID_IUnknown)    {        *pInterface=this;    }    else if (riid==IID_IDocHostUIHandler)    {        *pInterface=this;    }    if(*pInterface)    {        AddRef();        return S_OK;    }    return E_NOINTERFACE;}                           STDMETHODIMP CDocHostUIHandler::ShowContextMenu(DWORD dwID, POINT* pPt,    IUnknown* pcmdtReserved, IDispatch* pdispreserved){    return S_OK;}
    注意,由于微软提供的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 指针;
    原理性代码如下:
// 显示一个空白网页m_ie.Navigate2( &CComVariant(_T("about:blank")),NULL,NULL,NULL,NULL); // 得到 IHTMLDocument2 指针CComPtr< IDispatch > spDoc(m_ie.GetDocument()); // 得到 IPersistStreamInit 指针CComQIPtr< IPersistStreamInit, &IID_IPersistStreamInit > spPSI( spDoc ); // 申请内存,复制 HTML 字符串LPTSTR lpMem = (LPTSTR)::GlobalAlloc( GPTR, ::lstrlen( lpHtml )+1 );lstrcpy( lpMem, "xxx xxx" ); // 转换内存为流对象指针CComPtr< IStream > spStream;CreateStreamOnHGlobal( lpMem, TRUE, &spStream ); // 初始化后,装载显示spPSI->InitNew();spPSI->Load( spStream );
    IE 所能支持的数据传输协议,除了大家所熟悉的 http、ftp、file......还有一个协议是 res ,它表示浏览显示文件中的 HTML 资源。你可以在 IE 的地址栏上直接输入这样格式的 URL:"res://文件名/资源名"。
    把 HTML 文件加入到程序资源的方法比较简单,在资源卡片中,鼠标右键弹出菜单,执行 Import...(引入),选择指定的 HTML 文件,然后给一个资源名称即可。(在这里,最方便的资源名称用字符串比较好,如果使用整数ID,那么将来在使用的时候是这样的格式:res://文件名/#101,这里假设 101 是资源的ID号。真麻烦!我不太喜欢这样的方式。)对于图片文件等其它的附件,则需要手工编辑资源 RC 文件(用 IDE 环境引入,它会试图用文本方式打开一个2进制文件,多数情况下会“死机”)。
    手工编辑 RC 文件的部分是:
......///////////////////////////////////////////////////////////////////////////////// HTML//// 这两个是HTML文件,可以引入HTML_TOWORD      HTML DISCARDABLE  "res\\ToWord.htm"HTML_DLG     HTML DISCARDABLE  "res\\html_dlg.htm"// 下面的是GIF文件,需要手工加入~SEND_R1_C1.GIF  HTML DISCARDABLE  "res\\~Send_r1_c1.gif"~SEND_R1_C2.GIF  HTML DISCARDABLE  "res\\~Send_r1_c2.gif"LOGO.GIF         HTML DISCARDABLE  "res\\Logo.gif"SEND_R1_C1.GIF   HTML DISCARDABLE  "res\\Send_r1_c1.gif"SEND_R1_C2.GIF   HTML DISCARDABLE  "res\\Send_r1_c2.gif"SPACER.GIF       HTML DISCARDABLE  "res\\spacer.gif"#endif  // Chinese (P.R.C.) resources/////////////////////////////////////////////////////////////////////////////
♀ 响应事件
    WebBrowser的事件主要包括Control事件、Window事件及Docment事件三大类,微软分别提供了三个虚拟Event结构表示相关事件,分别是:DWebBrowserEvents、HTMLWindowEvents、HTMLDocumentEvents。使用时只需继承、实现相关Event结构,并安装相关事件即可。以下代码演示了如何继承、实现Docment事件。
// 事件类定义classCHtmlDocEvents : public HTMLDocumentEvents{public:    CHtmlDocEvents();    ~CHtmlDocEvents();    DWORD m_dwCount;protected:    virtual STDMETHODIMP QueryInterface(REFIID,void**);    virtual STDMETHODIMP_(DWORD) AddRef();    virtual STDMETHODIMP_(DWORD) Release();    virtual STDMETHODIMP GetTypeInfoCount(UINT*);     virtual STDMETHODIMP GetTypeInfo(UINT,LCID,ITypeInfo**);    virtual STDMETHODIMP GetIDsOfNames(REFIID,LPOLESTR*,UINT,LCID,DISPID*);    virtual STDMETHODIMP Invoke(DISPID,REFIID,LCID,WORD,DISPPARAMS*,        VARIANT*,EXCEPINFO*,UINT*);};             // 事件类实现STDMETHODIMP CHtmlDocEvents::QueryInterface(REFIID riid, PVOID* ppInterface){    *ppInterface = 0;    if (riid==IID_IUnknown)    {        *ppInterface = this;    }    else if (riid==IID_IDispatch)    {        *ppInterface = this;    }    else if (riid==DIID_HTMLDocumentEvents)    {        *ppInterface = this;    }                 if (*ppInterface)    {        (*reinterpret_cast(ppInterface))->AddRef();        return S_OK;    }                 return E_NOINTERFACE;}             STDMETHODIMP_(DWORD) CHtmlDocEvents::AddRef(){    m_dwCount++;    return m_dwCount;}             STDMETHODIMP_(DWORD) CHtmlDocEvents::Release(){    m_dwCount--;    return m_dwCount;}             STDMETHODIMP CHtmlDocEvents::GetIDsOfNames(REFIID, LPOLESTR*, UINT,    LCID, DISPID*){    return E_NOTIMPL;}             // ……// ……             STDMETHODIMP CHtmlDocEvents::Invoke(DISPID dispidMember, REFIID riid,    LCID lcid, WORD wFlags, DISPPARAMS* pdispparams,    VARIANT* pvarResult, EXCEPINFO* pexcepinfo,    UINT* puArgErr){    switch (dispidMember)    {        case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEMOVE:        case DISPID_HTMLDOCUMENTEVENTS_ONHELP:        case DISPID_HTMLDOCUMENTEVENTS_ONCLICK:        case DISPID_HTMLDOCUMENTEVENTS_ONDBLCLICK:        case DISPID_HTMLDOCUMENTEVENTS_ONKEYDOWN:        case DISPID_HTMLDOCUMENTEVENTS_ONKEYUP:        case DISPID_HTMLDOCUMENTEVENTS_ONKEYPRESS:        case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEDOWN:        case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEUP:        case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOUT:        case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOVER:        case DISPID_HTMLDOCUMENTEVENTS_ONREADYSTATECHANGE:        case DISPID_HTMLDOCUMENTEVENTS_ONBEFOREUPDATE:        case DISPID_HTMLDOCUMENTEVENTS_ONAFTERUPDATE:        case DISPID_HTMLDOCUMENTEVENTS_ONROWEXIT:        case DISPID_HTMLDOCUMENTEVENTS_ONROWENTER:        case DISPID_HTMLDOCUMENTEVENTS_ONDRAGSTART:        case DISPID_HTMLDOCUMENTEVENTS_ONSELECTSTART:        case DISPID_HTMLDOCUMENTEVENTS_ONERRORUPDATE:        default:            return E_NOTIMPL;    }               return NOERROR;}             // ……
    以下代码演示了如何安装Window和Docment事件,其中m_pUiWeb为指向WebBrowser对象的指针,m_pHtmlWindowEvents为指向自定义Window事件对象的指针,m_pHtmlDocEvents为指向CHtmlDocEvents对象的指针:
void DocumentCompleteUiWeb(LPDISPATCH pDisp, VARIANT* URL){    LPUNKNOWN pUnknown = m_pUiWeb->GetControlUnknown();    if( NULL == pUnknown )    {        return;    }            LPUNKNOWN pUnknownWeb = NULL;    LPUNKNOWN pUnknownDisp = NULL;    HRESULT hr = pUnknown->QueryInterface(IID_IUnknown, (LPVOID*)&pUnknownWeb);    if( FAILED(hr) )    {        return;    }            hr = pDisp->QueryInterface(IID_IUnknown, (LPVOID*)&pUnknownDisp);    if( FAILED(hr) || pUnknownWeb != pUnknownDisp)    {        pUnknownWeb->Release();        return;    }            pUnknownWeb->Release();    pUnknownDisp->Release();    IHTMLDocument2 *pHtmlDoc2 = (IHTMLDocument2*)m_pUiWeb->get_Document();    IConnectionPointContainer* pCPC = NULL;    DWORD dwCookie = 0;    {// 安装Web Window事件        IHTMLWindow2 *pHtmlWnd2 = NULL;        hr = pHtmlDoc2->get_parentWindow(&pHtmlWnd2);        if( FAILED(hr) )        {            return;        }        hr = pHtmlWnd2->QueryInterface(IID_IConnectionPointContainer,            reinterpret_cast(&pCPC));        if(FAILED(hr))        {            return;        }        IConnectionPoint* pCP = NULL;        pCPC->FindConnectionPoint(DIID_HTMLWindowEvents2, &pCP);  // 找到安装点        if( NULL == m_pHtmlWindowEvents )        {            m_pHtmlWindowEvents = new CHtmlWindowEvents(this);        }        hr = pCP->Advise(m_pHtmlWindowEvents, &dwCookie);        //安装        if( SUCCEEDED(hr) )        {            pCP->Release();        }        pCPC->Release();    }            {// 安装Web Document事件        hr = pHtmlDoc2->QueryInterface(IID_IConnectionPointContainer,            reinterpret_cast(&pCPC));        if(FAILED(hr))        {            return;        }        IConnectionPoint* pCP = NULL;        pCPC->FindConnectionPoint(DIID_HTMLDocumentEvents2, &pCP); // 找到安装点        if( NULL == m_pHtmlDocEvents )        {            m_pHtmlDocEvents = new CHtmlDocEvents(this, m_pMaskWnd, m_pUiWeb,                m_pPosIconWnd);        }        hr = pCP->Advise(m_pHtmlDocEvents, &dwCookie);   // 安装        if( SUCCEEDED(hr) )        {            pCP->Release();        }        pCPC->Release();    }}
♀ 用VC在网页中绘图
    用VC在网页上绘图主要通过WebBrowser的IElementBehavior接口和IHTMLPainter接口来实现。具体内容参照MSDN中的《Using Rendering Behaviors》说明,该说明中也有相关演示代码。
0 1