最近在做网页浏览器的开发,遇到一个问题,就是如何截取网页上所有元素的事件
参考了几篇文章
微软的这一篇
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派生过来,是不是哪里有错误,还是还需要别的步骤呢?

解决方案 »

  1.   

    那说明还没未实现的虚函数或者函数参数错了STDMETHODIMP GetIDsOfNames(const IID &,LPOLESTR *,UINT,LCID,DISPID *);
      

  2.   


    哦,那就是说,如果纯虚函数都实现正确的话,IDispatch接口派生的类应该也是可以正确初始化的,是吗?我顺便再检查检查
      

  3.   


    刚刚测试过了,果真可以啊......唉..看来我基础知识太缺乏了,我总以为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);
    是什么原因呢?是和连接点容器的获取有关吗?还是别的什么原因?
    刚刚那个问题已经试了可以了,这个问题你回不回答都没事,我都会结贴的.