VC 监视网页中的元素事件

通过近两个月的学习《Internet Explorer 5.0程序设计》,我终于知道该怎样来挂接一个网页中各元素的事件,现将我解决方法告知如下:
本例利用C++来捕获IE网页中的元素事件.
一、建立一个MFC单文档应用程序,选择视图类为CEditView.
二、新建一个C++类,该类派生于IDispatch接口。例如:(我的类为CIESpyEvent)
  #pragma once
#include "oaidl.h"    //包含了IDspatch接口定义
#include <Mshtml.h>    //事件IID的定义
class CCSpyEventView; 
class CIESpyEvent : public IDispatch
{
public:
CIESpyEvent(CCSpyEventView *pSpyEventView);
public:
~CIESpyEvent(void);
public:
//成员变量
CCSpyEventView *m_pSpyEventView;
CString str;
public:
HRESULT STDMETHODCALLTYPE QueryInterface(const struct _GUID &iid,void ** ppv)
{
//*ppv=this;
if(iid==IID_IUnknown)
*ppv=static_cast <IUnknown *>(this);
else

if(iid==IID_IDispatch)
*ppv=static_cast <IDispatch *>(this);
else
return E_NOINTERFACE;
return S_OK;
}

ULONG STDMETHODCALLTYPE AddRef(void)
{ return 1; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的

ULONG STDMETHODCALLTYPE Release(void)
{ return 0; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的

      HRESULT  STDMETHODCALLTYPE GetTypeInfoCount(
            /* [out] */ UINT *pctinfo) ;
       
      HRESULT  STDMETHODCALLTYPE GetTypeInfo(
            /* [in] */ UINT iTInfo,
            /* [in] */ LCID lcid,
            /* [out] */ ITypeInfo **ppTInfo);
       
      HRESULT  STDMETHODCALLTYPE GetIDsOfNames(
            /* [in] */ REFIID riid,
            /* [size_is][in] */ LPOLESTR *rgszNames,
            /* [in] */ UINT cNames,
            /* [in] */ LCID lcid,
            /* [size_is][out] */ DISPID *rgDispId) ;
       
        HRESULT  STDMETHODCALLTYPE Invoke(
            /* [in] */ DISPID dispIdMember,
            /* [in] */ REFIID riid,
            /* [in] */ LCID lcid,
            /* [in] */ WORD wFlags,
            /* [out][in] */ DISPPARAMS *pDispParams,
            /* [out] */ VARIANT *pVarResult,
            /* [out] */ EXCEPINFO *pExcepInfo,
            /* [out] */ UINT *puArgErr) ;
       
public:
CComPtr <IConnectionPoint> m_pConnectionPoint;  //连接点
public:
void OnClickDoc(void);      //单击文档事件
public:
CComQIPtr <IHTMLDocument2,&IID_IHTMLDocument2> m_pDoc;  //保存文档的成员变量
};

//类实现

#include "StdAfx.h"
#include "IESpyEvent.h"
#include <afxconv.h>    //定义OLE2T宏
#include <ExDispID.h>  //
#include <mshtmdid.h>
#include <Mshtml.h>

#include "CSpyEventView.h"


CIESpyEvent::CIESpyEvent(CCSpyEventView *pSpyEventView)
{
m_pSpyEventView=NULL;
str=_T("");
if(pSpyEventView)
  m_pSpyEventView=pSpyEventView;
m_pConnectionPoint=NULL;
}

CIESpyEvent::~CIESpyEvent(void)
{
}

///实现IDispatch接口
HRESULT  CIESpyEvent::GetTypeInfoCount(  /* [out] */ UINT *pctinfo)
{
//反正没用
  return E_NOTIMPL;
}

HRESULT  CIESpyEvent::GetTypeInfo(
/* [in] */ UINT iTInfo,
/* [in] */ LCID lcid,
/* [out] */ ITypeInfo **ppTInfo)
{
    return E_NOTIMPL;
}

HRESULT CIESpyEvent::GetIDsOfNames(
  /* [in] */ REFIID riid,
  /* [size_is][in] */ LPOLESTR *rgszNames,
  /* [in] */ UINT cNames,
  /* [in] */ LCID lcid,
  /* [size_is][out] */ DISPID *rgDispId)
{
  return E_NOTIMPL;
}

HRESULT CIESpyEvent::Invoke(
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID riid,
/* [in] */ LCID lcid,
/* [in] */ WORD wFlags,
/* [out][in] */ DISPPARAMS *pDispParams,
/* [out] */ VARIANT *pVarResult,
/* [out] */ EXCEPINFO *pExcepInfo,
/* [out] */ UINT *puArgErr)
{
USES_CONVERSION;

switch(dispIdMember)
{
case DISPID_DOCUMENTCOMPLETE:
{
//获取文档指针
          LPDISPATCH lpDispatch=NULL;
  HRESULT hr=m_pSpyEventView->m_pIE->get_Document(&lpDispatch);
  ASSERT(lpDispatch);
  m_pSpyEventView->m_pHTMLDoc=lpDispatch;

      m_pDoc=lpDispatch;
 
  //
  lpDispatch->Release();
  ASSERT(m_pSpyEventView->m_pHTMLDoc);
  //断开以前链接
  if(m_pConnectionPoint)
  {
  if(m_pSpyEventView->m_dwDocumentCookie)
  {
  m_pConnectionPoint->Unadvise(m_pSpyEventView->m_dwDocumentCookie);
  m_pSpyEventView->m_dwDocumentCookie=0;
  m_pConnectionPoint=NULL;

  }
  }

  //连接新的文档连接点
  //start
  CComPtr <IConnectionPointContainer> pContainer;
  hr=m_pSpyEventView->m_pHTMLDoc->QueryInterface(IID_IConnectionPointContainer,(void**)&pContainer);
          if(SUCCEEDED(hr))
  {
  hr=pContainer->FindConnectionPoint(DIID_HTMLDocumentEvents,&m_pConnectionPoint);
              ASSERT(SUCCEEDED(hr));
  if(SUCCEEDED(hr))
  {
  hr=m_pConnectionPoint->Advise(this,&m_pSpyEventView->m_dwDocumentCookie);  //接收器最好单独是一个类,尽量不要共用。
                  ASSERT(SUCCEEDED(hr));
  if(FAILED(hr))
  {
  ::MessageBox(NULL,_T("Failed to Advise"),_T("文档连接点"),MB_OK);
  }
  }
  }
         
      //end
         
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONCLICK:
OnClickDoc();
break;
case DISPID_NAVIGATECOMPLETE2:
if(pDispParams->rgvarg[0].vt==(VT_BYREF|VT_VARIANT))
{
CComVariant varURL(*pDispParams->rgvarg[0].pvarVal);
varURL.ChangeType(VT_BSTR);
//::MessageBox(NULL,OLE2T(varURL.bstrVal),_T("Invoke"),MB_OK);
str+=_T("IE事件DISPID_NAVIGATECOMPLETE2:");
str+=_T("/r/n");
str+=OLE2T(varURL.bstrVal);
str+=_T("/r/n");
m_pSpyEventView->SetWindowText(str);
}
break;
case DISPID_PROPERTYCHANGE:
if(pDispParams->cArgs>0&&pDispParams->rgvarg[0].vt==VT_BSTR)
{
str+=_T("IE事件DISPID_PROPERTYCHANGE:");
str+=_T("/r/n");
str+=OLE2T(pDispParams->rgvarg[0].bstrVal);
str+=_T("/r/n");
m_pSpyEventView->SetWindowText(str);
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONPROPERTYCHANGE:    //元素属性改变激发事件 */
{
str+=_T("IE事件DISPID_HTMLDOCUMENTEVENTS_ONPROPERTYCHANGE:");
            HRESULT hr;

if(!m_pSpyEventView->m_pHTMLDoc)
{
::MessageBox(NULL,_T("无法获取文档接口"),_T("出错"),MB_OK);
break;
}
CComPtr <IHTMLWindow2> pWin;  //声明
CComPtr <IHTMLEventObj> pEventObj;
CComPtr <IHTMLEventObj2> pEventObj2;
CComPtr <IHTMLElement>  pElement;
//hr=(m_pSpyEventView->m_pHTMLDoc)->get_parentWindow(&pWin);
if(m_pDoc)
{
hr=m_pDoc->get_parentWindow(&pWin);

if(FAILED(hr))
{
::MessageBox(NULL,_T("无法获取窗体接口"),_T("出错"),MB_OK);
break;
}
}

            hr=pWin->get_event(&pEventObj);
           
            if(FAILED(hr))
{
              ::MessageBox(NULL,_T("无法获取事件接口"),_T("出错"),MB_OK);
break;
}

//获取事件对象2指针
            hr=pEventObj->QueryInterface(IID_IHTMLEventObj2,(void **)&pEventObj2);

//断言
ASSERT(SUCCEEDED(hr));

//获取发生事件的元素对象
hr=pEventObj->get_srcElement(&pElement);

            ASSERT(SUCCEEDED(hr));

//获取事件属性名称
BSTR bstrName;    //#define OLECHAR *BSTR

hr=pEventObj2->get_propertyName(&bstrName);
if(SUCCEEDED(hr))
{
str+=_T("propertyname:");
str+=OLE2T(bstrName);
str+=_T("/r/n");
}

hr=pEventObj2->get_type(&bstrName);
if(SUCCEEDED(hr))
{
str+=_T("Type:");
str+=OLE2T(bstrName);
str+=_T("/r/n");
}

hr=pElement->get_tagName(&bstrName);
if(SUCCEEDED(hr))
{
str+=_T("tagName:");
str+=OLE2T(bstrName);
str+=_T("/r/n");
}

hr=pElement->get_id(&bstrName);
{
str+=_T("ID:");
str+=OLE2T(bstrName);
str+=_T("/r/n");
}

hr=pElement->toString(&bstrName);
if(SUCCEEDED(hr))
{
str+=_T("toString:");
str+=OLE2T(bstrName);
str+=_T("/r/n");
}

m_pSpyEventView->SetWindowText(str);
}
break;
default:
break;
}
return S_OK;
}

void CIESpyEvent::OnClickDoc(void)
{
::MessageBox(NULL,_T("单击了文档对象"),_T("文档连接点"),MB_OK);
}

 
#7楼 得分:0回复于:2010-01-22 23:30:04
///
//
//CSpyEventView类为我建立应用程序所生存的类。

//头文件名称:CSpyEventView.h


// CSpyEventView.h

#include "IESpyEvent.h"      //接收器实现类(继承于IDispatch)
#include <Mshtml.h>
#pragma once

class CCSpyEventDoc;
class CCSpyEventView : public CEditView
{
protected: // 仅从序列化创建
CCSpyEventView();
DECLARE_DYNCREATE(CCSpyEventView)

// 属性
public:
CCSpyEventDoc* GetDocument() const;

// 操作
public:

// 重写
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

// 实现
public:
virtual ~CCSpyEventView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// 生成的消息映射函数
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnStartSpyie();
public:
CComPtr <IWebBrowser2> m_pIE;
public:
virtual void OnInitialUpdate();
public:
IConnectionPoint *m_pConnectionPoint;
public:
DWORD m_dwBrowserCookie;
DWORD m_dwDocumentCookie;
public:
afx_msg void OnSttvHtml();
public:
CIESpyEvent *m_pIESpyEvent;
public:
afx_msg void OnClearTextbox();
public:
CComQIPtr <IHTMLDocument2,&IID_IHTMLDocument2> m_pHTMLDoc;
};

#ifndef _DEBUG  // CSpyEventView.cpp 中的调试版本
inline CCSpyEventDoc* CCSpyEventView::GetDocument() const
  { return reinterpret_cast <CCSpyEventDoc*>(m_pDocument); }
#endif


///
//
//源文件名称:CSpyEventView.CPP
//
///

#include "stdafx.h"
#include "CSpyEvent.h"

#include "CSpyEventDoc.h"
#include "CSpyEventView.h"
#include <mshtmdid.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CCSpyEventView

IMPLEMENT_DYNCREATE(CCSpyEventView, CEditView)

BEGIN_MESSAGE_MAP(CCSpyEventView, CEditView)
// 标准打印命令
ON_COMMAND(ID_FILE_PRINT, &CEditView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CEditView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CEditView::OnFilePrintPreview)
ON_COMMAND(ID_START_SPYIE, &CCSpyEventView::OnStartSpyie)
ON_COMMAND(ID_STTV_HTML, &CCSpyEventView::OnSttvHtml)
ON_COMMAND(ID_CLEAR_TEXTBOX, &CCSpyEventView::OnClearTextbox)
END_MESSAGE_MAP()

// CCSpyEventView 构造/析构

CCSpyEventView::CCSpyEventView()
: m_pConnectionPoint(NULL)
, m_pIESpyEvent(NULL)
{
// TODO: 在此处添加构造代码
::CoInitialize(NULL);
    m_dwBrowserCookie=-1;
    m_dwDocumentCookie=-1;
}

CCSpyEventView::~CCSpyEventView()
{
    //析构中断开所有的连接
if(m_pConnectionPoint)
{
HRESULT hr=m_pConnectionPoint->Unadvise(m_dwBrowserCookie);
if(FAILED(hr))
{
::MessageBox(NULL,__T("Failed to Unadvise"),_T("C++ Event Sink"),MB_OK);
}
}

if(m_pIESpyEvent->m_pConnectionPoint)
{
HRESULT hr=m_pIESpyEvent->m_pConnectionPoint->Unadvise(m_dwDocumentCookie);
if(FAILED(hr))
{
::MessageBox(NULL,__T("Failed to Unadvise"),_T("C++ Event Sink"),MB_OK);
}
}
if(m_pIE)
m_pIE->Quit();
::CoUninitialize();
}

BOOL CCSpyEventView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
//  CREATESTRUCT cs 来修改窗口类或样式

BOOL bPreCreated = CEditView::PreCreateWindow(cs);
cs.style &= ~(ES_AUTOHSCROLL|WS_HSCROLL); // 启用换行

return bPreCreated;
}


// CCSpyEventView 打印

BOOL CCSpyEventView::OnPreparePrinting(CPrintInfo* pInfo)
{
// 默认 CEditView 准备
return CEditView::OnPreparePrinting(pInfo);
}

void CCSpyEventView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
// 默认 CEditView 开始打印
CEditView::OnBeginPrinting(pDC, pInfo);
}

void CCSpyEventView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo)
{
// 默认 CEditView 结束打印
CEditView::OnEndPrinting(pDC, pInfo);
}


// CCSpyEventView 诊断

#ifdef _DEBUG
void CCSpyEventView::AssertValid() const
{
CEditView::AssertValid();
}

void CCSpyEventView::Dump(CDumpContext& dc) const
{
CEditView::Dump(dc);
}

CCSpyEventDoc* CCSpyEventView::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCSpyEventDoc)));
return (CCSpyEventDoc*)m_pDocument;
}
#endif //_DEBUG


// CCSpyEventView 消息处理程序

void CCSpyEventView::OnStartSpyie()
{
// TODO: 在此添加命令处理程序代码
//SetWindowText(_T(""));
m_pIESpyEvent->str=_T("");
if(!m_pIE)
return;
BSTR bstrURL=::SysAllocString(L"http://www.ourgame.com");
CComVariant varEmpty;
m_pIE->Navigate(bstrURL,&varEmpty,&varEmpty,&varEmpty,&varEmpty);
::SysFreeString(bstrURL);

    //为IE建立连接点
IConnectionPointContainer *pCPContainer;

HRESULT hr=m_pIE->QueryInterface(IID_IConnectionPointContainer,(void**)&pCPContainer);
ASSERT(pCPContainer);
hr=pCPContainer->FindConnectionPoint(DIID_DWebBrowserEvents2,&m_pConnectionPoint);
ASSERT(m_pConnectionPoint);
hr=m_pConnectionPoint->Advise(static_cast <IUnknown*>(this->m_pIESpyEvent),&m_dwBrowserCookie);
if(FAILED(hr))
return ;

pCPContainer->Release();
}


void CCSpyEventView::OnInitialUpdate()
{
CEditView::OnInitialUpdate();

// TODO: 在此添加专用代码和/或调用基类

m_pIESpyEvent=new CIESpyEvent(this);  //建立类

HRESULT hr=::CoCreateInstance(CLSID_InternetExplorer,NULL,
                          CLSCTX_SERVER,IID_IWebBrowser2,(void **)&m_pIE);
ASSERT(SUCCEEDED(hr));

    m_pIE->put_Visible(VARIANT_TRUE);    //显示IE实例
}

void CCSpyEventView::OnSttvHtml()    //导航到站点
{
// TODO: 在此添加命令处理程序代码
if(m_pIE)
{
    BSTR bstrURL=::SysAllocString(L"http://www.abchina.com");//中国农业银行
CComVariant varEmpty;
m_pIE->Navigate(bstrURL,&varEmpty,&varEmpty,&varEmpty,&varEmpty);
::SysFreeString(bstrURL);
}
}

void CCSpyEventView::OnClearTextbox()    //清除文档内容
{
// TODO: 在此添加命令处理程序代码
    m_pIESpyEvent->str=_T("");
SetWindowText(m_pIESpyEvent->str);
}


//

//小结:
//本例是在VS2005中实现的。
/*******************************************************************************
注意的几个问题:
1。捕获连接点的问题。在这里我利用文档对象建立连接点DIID_HTMLDocumentEvents(也就是MSDN中说的dispinterface为HTMLDocumentEvents.
  例如:我为网页元素建立HTMLElementEvents连接点:
      CComPtr <IConnectionPointContainer> pCPContainer;
    CComPtr <IConnectionPoint> pConnectionPoint;
    CComPtr <IHTMLElement> pElem;
    CComPtr <IHTMLDocument2> pDoc;
      m_pIE->get_Document(&pDoc);  //m_pIE上面例子中
      HRESULT hr=pDOC->get_body(pElem);
      ASSERT(SUCCEEDED(hr));
      if(FAILED(hr))
      return hr;
      //获取连接点容器
      hr=pElem->QueryInterface(IID_IConectionPointContainer,&pCPContainer);
      if(FAILED(hr))
      return hr;
      //获取连接点
      hr=pCPContainer->FindConnectionPoint(DIID_HTMLElementEvents,&pConnectionPoint)
      if(FAILED(hr))
      return hr;
      //建立连接,CEventSink为实现事件处理的类(派生于IDispatch接口)
      hr=pConnectionPoint->Advise(CEventSink,&m_dwCookie);   
      //这里的CEventSink最好个连接点一个类,不要共用,因为连接点事件ID有可能相同。
      //处理事件在CEventSink::Invoke中进行,如DISPID_HTMLELEMENTEVENTS2_ONCLICK事件.
2。包容那些头文件
    mshtmdid.h  //定义了mshtml组件中连接点事件DISPID,如DISPID_HTMLELEMENTEVENTS2_ONCLICK
  mshtml.h    //定义了接口IID,如IID_IHTMLDocument2.
  exdisp.h    //定义了browser组件中的DISPID,如DISPID_DOCUMENTCOMPLETE
  afxconv.h  //BSTR到TCHAR的转换宏,如OLE2T
  exdispid.h
3.多多练习,实践出真知.

******************************************************************************/
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值