MFC中针对WebBrowser控件增加link链接点击事件监控

本文参考互联网资源:http://www.scottdstrader.com/blog/ether_archives/000040.html
http://download.csdn.net/download/xiemg/3640190
前言:
本文是基于MFC对话框工程加入WebBrowser控件的实现,不是DHTMLView等的实现。目标是监控当前打开页面中的link超链接点击监控,并拦截事件做自定义处理。目的是把http链接转换成rtsp链接,然后本地播放该链接。

1. 主对话框头文件PlayerDlg.h:
1.1 增加头文件引用

#include <comdef.h>
#include <mshtml.h>
#include <mshtmdid.h>
#include <map>
#include <vector>
#include <afxwin.h>
using namespace std;

#pragma warning(disable : 4146) //see Q231931 for explaintation
#import <mshtml.tlb> no_auto_exclude

1.2 增加成员变量,用于保存事件对应的html element元素的指针指针

    vector<IDispatchPtr> m_vElem;
    map<IDispatch*, DWORD> m_mapElem2EventCookie;

1.3. 增加事件相关的MFC宏声明

        DECLARE_DISPATCH_MAP() 
    DECLARE_EVENTSINK_MAP()
    DECLARE_INTERFACE_MAP()

1.4. 增加3个事件处理函数声明

void OnClick(MSHTML::IHTMLEventObj *pEvtObj);//link 点击事件处理函数
afx_msg void OnDocumentComplete(LPDISPATCH pDisp, VARIANT FAR* URL);//html document加载完成时的事件函数
afx_msg void OnBeforeNavigate2(LPDISPATCH pDisp, VARIANT FAR* URL, VARIANT FAR* Flags, VARIANT FAR* TargetFrameName, VARIANT FAR* PostData, VARIANT FAR* Headers, BOOL FAR* Cancel);//跳转到新连接之前的函数,可在此阻止跳转

2. 主对话框源文件PlayerDlg.cpp:
2.1. 增加事件的映射

BEGIN_EVENTSINK_MAP(CPlayerDlg, CDialogEx)
//{{AFX_EVENTSINK_MAP(CPlayerDlg)
    ON_EVENT(CPlayerDlg, IDC_IE_BROWSER, 259 /* DocumentComplete */, OnDocumentComplete, VTS_DISPATCH VTS_PVARIANT)
    ON_EVENT(CPlayerDlg, IDC_IE_BROWSER, 250 /* BeforeNavigate2 */, OnBeforeNavigate2, VTS_DISPATCH VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PBOOL)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()


BEGIN_DISPATCH_MAP(CPlayerDlg, CCmdTarget)
    DISP_FUNCTION_ID(CPlayerDlg,"HTMLELEMENTEVENTS2_ONCLICK", DISPID_HTMLELEMENTEVENTS2_ONCLICK,
    CPlayerDlg::OnClick, VT_EMPTY, VTS_DISPATCH)
END_DISPATCH_MAP()


BEGIN_INTERFACE_MAP(CPlayerDlg, CCmdTarget)
    INTERFACE_PART(CPlayerDlg,  DIID_HTMLAnchorEvents2, Dispatch)
END_INTERFACE_MAP()

2.2 3个事件处理函数的实现
函数1:

void CPlayerDlg::OnBeforeNavigate2(LPDISPATCH pDisp,
                                           VARIANT FAR* URL,
                                           VARIANT FAR* Flags,
                                           VARIANT FAR* TargetFrameName,
                                           VARIANT FAR* PostData,
                                           VARIANT FAR* Headers,
                                           BOOL FAR* Cancel)
{
   
    CString strURL(URL->bstrVal);
    *Cancel = FALSE;
    if(strURL == _T("about:blank"))
        *Cancel = FALSE;
    else
    {
        if(strURL.Find(_T(".ts")) > 0 || strURL.Find(_T(".TS")) > 0)
        {//是含有ts文件的链接地址,阻止跳转!
            *Cancel = TRUE;
            return;
        }
    }

    if(!(*Cancel))
    {//进入新页面之前,先释放掉事件连接
        map<IDispatch *, DWORD>::iterator itr;
        for(itr = m_mapElem2EventCookie.begin(); itr != m_mapElem2EventCookie.end(); itr++)
        {//DIID_HTMLDocumentEvents
            AfxConnectionUnadvise(itr->first, DIID_HTMLAnchorEvents2, GetIDispatch(FALSE), FALSE, itr->second);
        }
        m_mapElem2EventCookie.clear();
        m_vElem.clear();
    }
}

函数2, 在文件加载完成时,给所有link元素,增加DIID_HTMLAnchorEvents2接口链接到当前的CPlayerDlg类:

void CPlayerDlg::OnDocumentComplete(LPDISPATCH pDisp, VARIANT FAR* URL)
{ // Get the HTML document. //
    IWebBrowser2Ptr webBrowser(pDisp);
    IDispatchPtr htmlDocDisp;
    (*webBrowser).get_Document(&htmlDocDisp);
    MSHTML::IHTMLDocument2Ptr htmlDoc(htmlDocDisp);


    DWORD dwCookie = 0;
    // Get the collection of elements.
    MSHTML::IHTMLElementCollectionPtr elements;
    (*htmlDoc).get_all(&elements);

    IDispatchPtr disp;
    _variant_t index(0L, VT_I4);
    do
    {
        //Get all elements
        disp = (*elements).item(index, index);//第一个参数可以过滤,指定控件id:_variant_t(_T("control"))
        if (disp != NULL)
        {
            // Examine their action attribute to determine what should be done.
            IDispatchPtr element(disp);
            MSHTML::IHTMLElementPtr elemTag(disp);

            //为每个link控件,连接DIID_HTMLAnchorEvents2事件触发,连接到当前的类的OnClick函数来处理
            //注意BEGIN_DISPATCH_MAP中增加的OnClick函数映射
            DWORD dwCookie = 0;
            BSTR name = NULL;
            elemTag->get_tagName(&name);
             if(name != NULL && _tcsicmp(name, _T("a")) == 0)
             {//is link!!!!
                 LPUNKNOWN pUnkSink = GetIDispatch(FALSE);

                 if(AfxConnectionAdvise(element,  DIID_HTMLAnchorEvents2, pUnkSink, FALSE, &dwCookie))
                 {
                     m_vElem.push_back(element);
                     m_mapElem2EventCookie[element.GetInterfacePtr()] = dwCookie;
                     if(name != NULL)
                     {//打印调试信息
                         wstring wsName = name;
                         string sName = WcsToMbs(wsName);
                         TRACE("get tag:%s, bind DIID_HTMLAnchorEvents2\n", sName.c_str());
                     }
                 }
            }




            ++index.lVal;
        }
    }while (disp != NULL);
}

函数3,link点击事件处理函数:

void CPlayerDlg::OnClick(MSHTML::IHTMLEventObj *pEvtObj)
{
    MSHTML::IHTMLElementPtr elem = pEvtObj->srcElement;
    _variant_t href = elem->getAttribute(_T("href"), 0);
    CString sRtspUrl = href.bstrVal;
    if(sRtspUrl.Find(_T(".ts")) != -1 || sRtspUrl.Find(_T(".ts")) != -1)
    {
        sRtspUrl.Replace(_T("http:"), _T("rtsp:"));
                //...对rtsp执行播放动作
    }

}

回复

你的邮件地址不会被公开(Your email address will not be published.) Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>