通过近两个月的学习《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);
}
|