在VC++中绑定网页元素的事件(如onclick),通常会使用HTMLElementEvents2事件接口进行。大致如下: void CSomeObject:ConnectElement(IHTMLElement* pElement) { //取得连接点容器 CComQIPtr<IConnectionPointContainer> pCPC=pElement; //查找连接点 CComPtr<IConnectionPoint> pCP; pCPC->FindConnectionPoint( DIID_HTMLElementEvents2, &pCP); //连接事件接口 IUnknownPtr pUnk=this; //由CSomeObject实现HTMLElementEvents2事件接口 DWORD dwCookie; pCP->Advise( pUnk, &dwCookie); } 而在javascript中使用attachEvent绑定网页元素事件的方式却显得更自然,实现也更直接,我们是否也可以用VC++实现呢? - function fn_onclick()
- {
- alert("Hello world!");
- }
- document.all("button1").attachEvent("onclick",fn_onclick);
- document.all("button1").detachEvent("onclick",fn_onclick);
先看看在PIMShell中用VC++是怎样实现以上功能的。 - class ATL_NO_VTABLE CVCEventSinkDemo:
- public IDispatchImpl<IVCEventSinkDemo>
- {
- public:
- CVCEventSinkDemo()
- {
- }
- DECLARE_PROTECT_FINAL_CONSTRUCT()
- HRESULT FinalConstruct()
- {
- return S_OK;
- }
- void FinalRelease()
- {
- }
- private:
-
- PIMShellCore::IAjaxDelegatePtr m_pDelegate_onevents;
-
- static HRESULT CALLBACK Sink_onevents( VARIANT vEvent, VARIANT vContext, IUnknown* pInstance, VARIANT* pvarResult);
-
- void __attachEvents(bool bAttach);
- };
- void CVCEventSinkDemo::__attachEvents(bool bAttach)
- {
- if(bAttach)
- {
-
- IUnknownPtr pThis=this;
- m_pDelegate_onevents = o->Sys2->CreateDelegateVC1( pThis, (LONGLONG)&Sink_onevents);
-
- o->Control->AttachEvent(L"onclick", m_pDelegate_onevents);
- }
- else
- {
- if(m_pDelegate_onevents!=NULL)
- {
-
- o->Control->DetachEvent( L"onclick", m_pDelegate_onevents);
-
- m_pDelegate_onevents=NULL;
- }
- }
- }
- HRESULT CVCEventSinkDemo::Sink_onevents( VARIANT vEvent, VARIANT vContext, IUnknown* pInstance, VARIANT* pvarResult)
- {
- __SAFECALL_BEGIN;
-
- CVCEventSinkDemo* pThis=dynamic_cast<CVCEventSinkDemo*>(pInstance);
-
- MSHTML::IHTMLEventObjPtr e=vEvent.pdispVal;
-
- CString sType=e->type;
-
- if(sType==L"click")
- {
-
- }
- __SAFECALL_END;
- }
1、先生成一个代理对象,这个对象记录CVCEventSinkDemo的实例指针和回调函数,与C#中delegate的设计理念一致。 2、将代理对象传入attachEvent实现对onclick事件的绑定。 3、当事件发生时,系统调用代理对象的0方法, 4、在代理对象的0方法中,调用先前记录的回调函数,并将CVCEventSinkDemo的实例指针传入。 我们接下来看看CreateDelegateVC1是如何生成代理对象的。 - HRESULT CreateDelegateVC1( IUnknown* pInstance, LONGLONG lnCallback, IDispatch** ppDelegate)
- {
-
- CComObject<CVCDelegateDemo>* pDelegate;
- HRESULT hr=CComObject<CVCDelegateDemo>::CreateInstance(&pDelegate);
- if(FAILED(hr))
- return hr;
-
- pDelegate->__record(pInstance,lnCallback);
-
- return pDelegate->QueryInterface(IID_IDispatch,(void**)ppDelegate);
- }
接下来,我们看CVCDelegateDemo的0方法是如何实现的 - class ATL_NO_VTABLE CVCDelegateDemo:
- public IDispatchImpl<CVCDelegateDemo>
- {
- public:
- CVCDelegateDemo()
- {
- }
- DECLARE_PROTECT_FINAL_CONSTRUCT()
- HRESULT FinalConstruct()
- {
- return S_OK;
- }
- void FinalRelease()
- {
- }
- typedef HRESULT (CALLBACK* _delegateVC1)( VARIANT vParam1, VARIANT vContext, IUnknown* pInstance, VARIANT* pvarResult);
- private:
- IUnknownPtr m_pInstance;
- _delegateVC1 m_pCallback1;
- public:
-
-
- void __record(IUnknown* pInstance,LONGLONG lnCallback)
- {
-
- this->m_pInstance=pInstance;
- this->m_pCallback1=(_delegateVC1)lnCallback;
- }
- public:
-
- STDMETHOD(Invoke)( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
- DISPPARAMS* pDispParams, VARIANT* pvarResult,
- EXCEPINFO* pExcepInfo, UINT* puArgErr)
- {
-
- if(dispidMember!=0)
- return E_INVALIDARG;
-
- _variant_t vEvent=pDispParams->rgvarg[0];
-
- (*m_pCallback1)(vEvent,vtMissing,m_pInstance,pvarResult);
-
- return S_OK;
- }
- };
|