最近在做网页浏览器的开发,遇到一个问题,就是如何截取网页上所有元素的事件
参考了几篇文章
微软的这一篇
http://msdn.microsoft.com/en-us/library/bb508508(VS.85).aspx
其中这么一段
STDMETHODIMP CEventSink::Invoke(DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr)
{
switch (dispidMember)
{
case DISPID_HTMLELEMENTEVENTS2_ONCLICK:
OnClick();
break; default:
break;
} return S_OK;
}
是在Invoke方法中得到所有的事件
关于连接点和事件我事先已经看过了
The following sample code demonstrates how you would detect the firing of an HTMLElementEvents2::onclick event in your implementation of IDispatch::Invoke.
这句里面从IDispatch派生的类来实现Invoke方法,具体怎么实现呢?
我在MFC下面派生了一个,可是我实例化对象的时候提示不能实例化抽象类,具体的写法我是参考这个帖子里面的例子的http://blog.csdn.net/sstower/article/details/6253409?reload
头文件如下
#pragma once
#include "oaidl.h"
class CeEventSink :
public IDispatch
{
public:
CeEventSink();
virtual ~CeEventSink();
public:
STDMETHODIMP QueryInterface(const struct _GUID &iid,void ** ppv);
ULONG __stdcall AddRef(void);
ULONG __stdcall Release(void);
STDMETHODIMP GetTypeInfoCount(unsigned int *);
STDMETHODIMP GetTypeInfo(unsigned int,unsigned long,struct ITypeInfo ** );
STDMETHODIMP GetIDsOfNames(const struct _GUID &,unsigned short ** ,unsigned int,unsigned long,long *);
STDMETHODIMP Invoke(
long dispID,
const struct _GUID &,
unsigned long,
unsigned short,
struct tagDISPPARAMS * pParams,
struct tagVARIANT *,
struct tagEXCEPINFO *,
unsigned int *);};CPP文件如下#include "stdafx.h"
#include "CeEventSink.h"
#include <mshtmdid.h>
CeEventSink::CeEventSink()
{
}
CeEventSink::~CeEventSink()
{
}STDMETHODIMP CeEventSink::QueryInterface(const struct _GUID &iid,void ** ppv)
{
if (iid == IID_IDispatch || iid==IID_IUnknown)
{
*ppv = (IDispatch*)this;
AddRef();
}
else
{
return E_NOINTERFACE;
}
return S_OK;
}ULONG __stdcall CeEventSink::AddRef(void)
{
return 1;
} // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的ULONG __stdcall CeEventSink::Release(void)
{ return 0; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的STDMETHODIMP CeEventSink::GetTypeInfoCount(unsigned int *)
{ return E_NOTIMPL; } // 不用实现,反正也不用STDMETHODIMP CeEventSink::GetTypeInfo(unsigned int,unsigned long,struct ITypeInfo ** )
{ return E_NOTIMPL; } // 不用实现,反正也不用STDMETHODIMP CeEventSink::GetIDsOfNames(const struct _GUID &,unsigned short ** ,unsigned int,unsigned long,long *)
{ return E_NOTIMPL; } // 不用实现,反正也不用STDMETHODIMP CeEventSink::Invoke(
long dispID,
const struct _GUID &,
unsigned long,
unsigned short,
struct tagDISPPARAMS * pParams,
struct tagVARIANT *,
struct tagEXCEPINFO *,
unsigned int *)
{ // 只需要实现这个就足够啦
switch(dispID)
{
case DISPID_HTMLELEMENTEVENTS2_ONCLICK:
{
CComQIPtr<IHTMLEventObj> spEvent = pParams->rgvarg[0].pdispVal;
if (spEvent)
{
CComQIPtr<IHTMLElement> spSrcElement;
spEvent->get_srcElement(&spSrcElement);
if (spSrcElement)
{
CComBSTR bstrName;
spSrcElement->get_tagName(&bstrName);
CString szTagName=bstrName;
if (szTagName.CompareNoCase("a"))
{
AfxMessageBox("点击的是超链接");
}
if (szTagName.CompareNoCase("img"))
{
AfxMessageBox("点击的是图片");
}
}
}
}
}
return S_OK;
}调用的时候是这样:
CeEventSink* pEventSink=new CeEventSink();
IUnknown* pUnknow=NULL;
hr=pEventSink->QueryInterface(IID_IUnknown,(void**)&pUnknow);
if (SUCCEEDED(hr))就提示不能实例化抽象类了
因为如果可以重载Invoke方法的话,我就可以参考下面这个帖子里面的方法对所有的元素事件进行截获了
http://cuijingbing.blog.163.com/blog/static/4682582520116297283718/如果我就是想从IDispatch派生过来,是不是哪里有错误,还是还需要别的步骤呢?
参考了几篇文章
微软的这一篇
http://msdn.microsoft.com/en-us/library/bb508508(VS.85).aspx
其中这么一段
STDMETHODIMP CEventSink::Invoke(DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr)
{
switch (dispidMember)
{
case DISPID_HTMLELEMENTEVENTS2_ONCLICK:
OnClick();
break; default:
break;
} return S_OK;
}
是在Invoke方法中得到所有的事件
关于连接点和事件我事先已经看过了
The following sample code demonstrates how you would detect the firing of an HTMLElementEvents2::onclick event in your implementation of IDispatch::Invoke.
这句里面从IDispatch派生的类来实现Invoke方法,具体怎么实现呢?
我在MFC下面派生了一个,可是我实例化对象的时候提示不能实例化抽象类,具体的写法我是参考这个帖子里面的例子的http://blog.csdn.net/sstower/article/details/6253409?reload
头文件如下
#pragma once
#include "oaidl.h"
class CeEventSink :
public IDispatch
{
public:
CeEventSink();
virtual ~CeEventSink();
public:
STDMETHODIMP QueryInterface(const struct _GUID &iid,void ** ppv);
ULONG __stdcall AddRef(void);
ULONG __stdcall Release(void);
STDMETHODIMP GetTypeInfoCount(unsigned int *);
STDMETHODIMP GetTypeInfo(unsigned int,unsigned long,struct ITypeInfo ** );
STDMETHODIMP GetIDsOfNames(const struct _GUID &,unsigned short ** ,unsigned int,unsigned long,long *);
STDMETHODIMP Invoke(
long dispID,
const struct _GUID &,
unsigned long,
unsigned short,
struct tagDISPPARAMS * pParams,
struct tagVARIANT *,
struct tagEXCEPINFO *,
unsigned int *);};CPP文件如下#include "stdafx.h"
#include "CeEventSink.h"
#include <mshtmdid.h>
CeEventSink::CeEventSink()
{
}
CeEventSink::~CeEventSink()
{
}STDMETHODIMP CeEventSink::QueryInterface(const struct _GUID &iid,void ** ppv)
{
if (iid == IID_IDispatch || iid==IID_IUnknown)
{
*ppv = (IDispatch*)this;
AddRef();
}
else
{
return E_NOINTERFACE;
}
return S_OK;
}ULONG __stdcall CeEventSink::AddRef(void)
{
return 1;
} // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的ULONG __stdcall CeEventSink::Release(void)
{ return 0; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的STDMETHODIMP CeEventSink::GetTypeInfoCount(unsigned int *)
{ return E_NOTIMPL; } // 不用实现,反正也不用STDMETHODIMP CeEventSink::GetTypeInfo(unsigned int,unsigned long,struct ITypeInfo ** )
{ return E_NOTIMPL; } // 不用实现,反正也不用STDMETHODIMP CeEventSink::GetIDsOfNames(const struct _GUID &,unsigned short ** ,unsigned int,unsigned long,long *)
{ return E_NOTIMPL; } // 不用实现,反正也不用STDMETHODIMP CeEventSink::Invoke(
long dispID,
const struct _GUID &,
unsigned long,
unsigned short,
struct tagDISPPARAMS * pParams,
struct tagVARIANT *,
struct tagEXCEPINFO *,
unsigned int *)
{ // 只需要实现这个就足够啦
switch(dispID)
{
case DISPID_HTMLELEMENTEVENTS2_ONCLICK:
{
CComQIPtr<IHTMLEventObj> spEvent = pParams->rgvarg[0].pdispVal;
if (spEvent)
{
CComQIPtr<IHTMLElement> spSrcElement;
spEvent->get_srcElement(&spSrcElement);
if (spSrcElement)
{
CComBSTR bstrName;
spSrcElement->get_tagName(&bstrName);
CString szTagName=bstrName;
if (szTagName.CompareNoCase("a"))
{
AfxMessageBox("点击的是超链接");
}
if (szTagName.CompareNoCase("img"))
{
AfxMessageBox("点击的是图片");
}
}
}
}
}
return S_OK;
}调用的时候是这样:
CeEventSink* pEventSink=new CeEventSink();
IUnknown* pUnknow=NULL;
hr=pEventSink->QueryInterface(IID_IUnknown,(void**)&pUnknow);
if (SUCCEEDED(hr))就提示不能实例化抽象类了
因为如果可以重载Invoke方法的话,我就可以参考下面这个帖子里面的方法对所有的元素事件进行截获了
http://cuijingbing.blog.163.com/blog/static/4682582520116297283718/如果我就是想从IDispatch派生过来,是不是哪里有错误,还是还需要别的步骤呢?
解决方案 »
- 在winXP sp2下的匿名管道与win2000下有什么不同?开发的时候需要注意什么?
- 又遇到难题了,纠结了很久,无法在treeview显示出本地磁盘(包括盘符、文件夹等)的系统小图标,高分~~
- 怎样保存DC里的内容?
- 一个vc技术的群,群号:5497193
- 为何调用WaitForSingleObject后程序就不相应了呢?
- 目录“D:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\VC98\MFC\SRC”主要是干什么用的?
- 我想要一个图表控件的源码,就是那种统计分析的!在哪找,Gallery中的,我不满意,谁能解决这个问题!
- 听说高程有水平和资格两种认证,有什么具体区别啊?哪个更好些?资格好像要开什么证明,具体证明的要求又是什么呢?
- 主对话框与DLL模块之间的通信,求一例子程序或关键代码
- 能不能提供几个好的有VC代码的站点
- 请问为什么stetextcolor 没有作用?
- 请教,如何把宽字符转换为网址上显示的字符窜?
哦,那就是说,如果纯虚函数都实现正确的话,IDispatch接口派生的类应该也是可以正确初始化的,是吗?我顺便再检查检查
刚刚测试过了,果真可以啊......唉..看来我基础知识太缺乏了,我总以为IDispatch是个特殊的接口不让实例化..方便的话还有个问题不知道你知道吗?
IConnectionPoint* pConnectionPoint=NULL;
hr=pConnectionPointContainer->FindConnectionPoint(DIID_HTMLDocumentEvents2,&pConnectionPoint);
这段代码要是找这个连接点就没有问题,成功取到连接点,
可是我要是改成
IConnectionPoint* pConnectionPoint=NULL;
hr=pConnectionPointContainer->FindConnectionPoint(DIID_HTMLElementEvents2,&pConnectionPoint);
就会失败,返回-2147220992,不知道怎么回事,我看微软的示例代码上就是
hr = pCPC->FindConnectionPoint(DIID_HTMLElementEvents2, &pCP);
难道这个和连接点容器的获取有关吗?
微软的连接点容器是
void CMyClass::ConnectEvents(IHTMLElement* pElem)
{
HRESULT hr;
IConnectionPointContainer* pCPC = NULL;
IConnectionPoint* pCP = NULL;
DWORD dwCookie; // Check that this is a connectable object.
hr = pElem->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);
这样获取的,我的是这样获取的
IHTMLDocument2* m_pHtmlDoc;
......
IConnectionPointContainer* pConnectionPointContainer=NULL;
HRESULT hr=m_pHtmlDoc->QueryInterface(IID_IConnectionPointContainer,(void**)&pConnectionPointContainer);
是什么原因呢?是和连接点容器的获取有关吗?还是别的什么原因?
刚刚那个问题已经试了可以了,这个问题你回不回答都没事,我都会结贴的.