ATL所自带响应Event的类

原文:http://blog.sina.com.cn/s/blog_86fe5b440101a2wv.html

ATL所自带响应Event的类有两个


IDispEventSimpleImpl

IDispEventImpl

它们的区别是一个是否带类型库,现在看看他们的模板参数
 

    template  
    class ATL_NO_VTABLE IDispEventSimpleImpl : public _IDispEventLocator  
    { 

    };  

 

    template
     const GUID* plibid = &GUID_NULL, WORD wMajor = 0, WORD wMinor = 0, class tihclass = CComTypeInfoHolder>  
    class ATL_NO_VTABLE IDispEventImpl : public IDispEventSimpleImpl  
    { 

    };  


 

可以看到IDispEventImpl的参数太多,居然连pdiid都可以默认参数。

区别:

IDispEventImpl能从IUnknow里QueryInterface出它的类型库,得到Event函数的详细结构,使下面SINK结构构造简单。而IDispEventSimpleImpl不使用类型库,使用手工打造,SINK结构自然要麻烦一些。

参数说明:

nID:控件ID,如果所有父类不是对话框类,这个值,可以随便设一个。但必须跟下面的SINK结构的ID相一致。

T:父类

pdiid:EVENT的IID。如果SINK结构是使用SINK_ENTRY_EX或SINK_ENTRY_INFO,里面的iid必须跟这里一致。

plibid:LIBID。如果pdiid用默认值IID_NULL,这个值最好用默认值。原因下面再解析。

wMajor和wMinor:版本信息。其用法跟plibid一样。

 

一、使用:

连接:

    可供选择两个函数。

    HRESULT DispEventAdvise(IUnknown* pUnk, const IID* piid)

    HRESULT Advise(IUnknown *punk)

    DispEventAdvise:

    适用于不是默认连接的情况(只要COM对象提供有EVENT就可以连接),这种情况由指定的piid进行连接。

    但前提IDispEventImpl或IDispEventSimpleImpl必须有指定参数,不能采用默认参数,否则很可能会工作不正常。

    Advise:

    仅适用于默认连接的情况,这个函数用起来很舒服。它里面使调用AtlGetObjectSourceInterface获得默认类型信息,并存起来。仅适用于IDispEventImpl。

    如果IDispEventSimpleImpl会因为在invoke时候发现有类型信息,但又不能处理类型信息而产生错误

断开:

    HRESULT Unadvise(IUnknown *punk);

    HRESULT DispEventUnadvise(IUnknown* pUnk, const IID* piid);

    最好跟连接的相配套,但Unadvise最终会调用DispEventUnadvise,所以也可以直接DispEventUnadvise。

     

    IDispEventImpl如果使用默认值的情况下,也就是使用Advise的情况下,其模板的构造版本,使不使用默认值,不重要,因为它会使用AtlGetObjectSourceInterface获得IID,LIBID,及版本信息。

    但如果使用DispEventAdvise,IDispEventImpl的构造就相对麻烦很多,全部参数,都需要老老实实地填 ,而且不能错。IID,LIBID一般都能从头文件里得到,但版本呢?可以使用AtlGetObjectSourceInterface执行一次,查看一下,得到具体值,再构造这个模板。

 

 

 

二、SINK结构:

下面再看一下SINK结构吧。
[cpp] view plaincopy

    BEGIN_SINK_MAP(className)  
        SINK_ENTRY(IDC_A171, 1, TextA171)       
        SINK_ENTRY_EX(2,__uuidof(HTMLDocumentEvents ),DISPID_HTMLDOCUMENTEVENTS_ONMOUSEDOWN,func)  
        SINK_ENTRY_INFO(1,__uuidof(_Itt3Events) , 1, OnMyFunc, &StatusChangeInfo)  
    END_SINK_MAP  

SINK结构与传统的MAP结构类似,也是begin-end结构,上面的结构是所有IDispEventSimpleImpl和IDispEventImpl共用。

从上面代码可以看到最简单是SINK_ENTRY,接着是SINK_ENTRY_EX, SINK_ENTRY_INFO,现在再来看看这三个结构的关系
[cpp] view plaincopy

    #define SINK_ENTRY_INFO(id, iid, dispid, fn, info) {id, &iid, (int)(INT_PTR)(static_cast*>((_atl_event_classtype*)8))-8, dispid, (void (__stdcall _atl_event_classtype::*)())fn, info},  
    #define SINK_ENTRY_EX(id, iid, dispid, fn) SINK_ENTRY_INFO(id, iid, dispid, fn, NULL)  
    #define SINK_ENTRY(id, dispid, fn) SINK_ENTRY_EX(id, IID_NULL, dispid, fn)  

 

SINK_ENTRY会从SINK_ENTRY_EX逐步演变为SINK_ENTRY_INFO,复杂的代码不多说,光说应用吧。

参数说明:

id:控件ID,与前面的Event类的ID相一致

dispid:EVENT里函数或属性的Dispatch ID

iid:EVENT的IID

fn:函数名字

info:函数参数结构,是最复杂的一项。(这里暂不解析,由于麻烦,一般不采用这种方式)

 

SINK_ENTRY:

    所以在EVENT模板参数的pdiid必须为IID_NULL,否则只能使用SINK_ENTRY_EX或SINK_ENTRY_INFO,但如果在IDispEventSimpleImpl使用IID_NULL作为IDD参数,尽管可以使用SINK_ENTRY通过编译,但最终运行的时候,没有类型信息的函数,所以最后还是运行错误。简单的话说,这个宏只能用于IDispEventImpl,而且pdiid==IID_NULL的情况。

SINK_ENTRY_EX:

    也只能用于IDispEventImpl,需要IID参数

SINK_ENTRY_INFO:

    是最复杂的情况,可以用于IDispEventImpl和IDispEventSimpleImpl,但要要构造麻烦info参数,这不一是一件爽事。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值