本文参考互联网资源: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
#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;
map<IDispatch*, DWORD> m_mapElem2EventCookie;
1.3. 增加事件相关的MFC宏声明
DECLARE_DISPATCH_MAP()
DECLARE_EVENTSINK_MAP()
DECLARE_INTERFACE_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);//跳转到新连接之前的函数,可在此阻止跳转
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()
//{{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();
}
}
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);
}
{ // 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执行播放动作
}
}
{
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执行播放动作
}
}