组件实现步骤
2012-04-19 09:46
211 查看
三、组件实现步骤
1、建立一个工作区(WorkSpace)
2、在工作区中,建立一个 ATL 工程(Project)。示例程序中工程名称叫 Simple11,接受全部默认选项。
3、ClassView 中,执行鼠标右键菜单命令 New Atl Object...,添加 ALT 类。
3-1、左侧分类 Category 选择 Objects,右侧 Objects 选择 SimpleObject(其实就是默认项目)
3-2、名称 Name 卡片中,输入组件名称。示例程序中是 Event1(注1)
3-3、属性 Attributes 卡片中,修改接口类型 Interface 为定制的 Custom(注2)
4、ClassView 中,选择接口(IEvent1),鼠标右键菜单添加函数 Add Method...
图二、增加接口函数 Add([in] long n1,[in] long n2)
图三、增加接口函数 Advise([in] ICallBack *pCallBack,[out] long *pdwCookie)
图四、增加接口函数 Unadvise([in] long dwCookie)
你应该注意到了,在Add()函数中,并没有[out]、[retval] 这样的 IDL 属性,嘿嘿,因为我们本来就不打算通过 Add() 函数直接得到计算结果。不然怎么演示回调接口呀:-) 另外,在函数 Advise()中,需要返回一个整数 dwCookie,这是干什么?道理很简单,因为我们的组件想同时支持多个对象的回调连接。因此当客户端传递一个接口给我们组件的时候,我返回给它唯一的一个 cookie 号码来表示身份,将来断开连接的时候 Unadvise(),它需要把这个 cookie 身份号再给我,这样我就知道是谁想断开了。
5、增加回调接口 ICallBack 的 IDL 定义。打开 IDL 文件并手工输入(黑体字部分为手工输入的) ,然后保存:
6、增加回调接口函数
图五、增加回调接口函数
其实和以前的方法一样,只要注意别选错了接口就好。
图六、增加接口函数 Fire_Result([in] long nResult)
我们计算整数和,得到结果后,就是要靠这个回调接口函数去反馈给客户端呀。
7、添加组件内部保存回调接口指针的数组
刚才已经说过,我们这个组件打算支持多个对象的回调连接,因此我们要使用一个数组来保存。在 ClassView 中,选择 CEvent1 类,增加成员变量 Add Member Variable...
图七、增加保存 ICallBack * 的数组
当然,保存一个数组可以有多种方式。示例程序比较简单,定义了一个10个元素空间的成员数组变量。如果你已经学会了使用 STL,那么你也可以用 vector 等容器来实现。注意!注意!注意!在构造函数中别忘了初始化数组元素为
NULL。
8、好了,下面开始完成所有代码
1、建立一个工作区(WorkSpace)
2、在工作区中,建立一个 ATL 工程(Project)。示例程序中工程名称叫 Simple11,接受全部默认选项。
3、ClassView 中,执行鼠标右键菜单命令 New Atl Object...,添加 ALT 类。
3-1、左侧分类 Category 选择 Objects,右侧 Objects 选择 SimpleObject(其实就是默认项目)
3-2、名称 Name 卡片中,输入组件名称。示例程序中是 Event1(注1)
3-3、属性 Attributes 卡片中,修改接口类型 Interface 为定制的 Custom(注2)
4、ClassView 中,选择接口(IEvent1),鼠标右键菜单添加函数 Add Method...
图二、增加接口函数 Add([in] long n1,[in] long n2)
图三、增加接口函数 Advise([in] ICallBack *pCallBack,[out] long *pdwCookie)
图四、增加接口函数 Unadvise([in] long dwCookie)
你应该注意到了,在Add()函数中,并没有[out]、[retval] 这样的 IDL 属性,嘿嘿,因为我们本来就不打算通过 Add() 函数直接得到计算结果。不然怎么演示回调接口呀:-) 另外,在函数 Advise()中,需要返回一个整数 dwCookie,这是干什么?道理很简单,因为我们的组件想同时支持多个对象的回调连接。因此当客户端传递一个接口给我们组件的时候,我返回给它唯一的一个 cookie 号码来表示身份,将来断开连接的时候 Unadvise(),它需要把这个 cookie 身份号再给我,这样我就知道是谁想断开了。
5、增加回调接口 ICallBack 的 IDL 定义。打开 IDL 文件并手工输入(黑体字部分为手工输入的) ,然后保存:
import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(7E659BB1-FB79-4188-9661-65CA22B6A3E6), // 这个 IID 可以用 GUDIGEN.EXE 产生 helpstring("ICallBack Interface"), pointer_default(unique) ] interface ICallBack : IUnknown { }; [ object, // 以下内容同示例程序,当然如果是你自己生成的程序就肯定有差别的啦 uuid(7E659BB0-FB79-4188-9661-65CA22B6A3E6), helpstring("IEvent1 Interface"), pointer_default(unique) ] interface IEvent1 : IUnknown { [helpstring("method Add")] HRESULT Add([in] long n1, [in] long n2); [helpstring("method Advise")] HRESULT Advise([in] ICallBack * pCallBack, [out] long * pdwCookie); [helpstring("method Unadvise")] HRESULT Unadvise([in] long dwCookie); }; [ uuid(695C9BB2-2AE9-4232-8225-17AB8BD3BABC), version(1.0), helpstring("Simple11 1.0 Type Library") ] library SIMPLE11Lib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); [ uuid(6FCF997C-C811-49DB-9D16-46FAF8D24822), helpstring("Event1 Class") ] coclass Event1 { [default] interface IEvent1; // 需要手工输入,据说 VB 使用的话,不能有 [source,default] 属性 [source, default] interface ICallBack; }; };
6、增加回调接口函数
图五、增加回调接口函数
其实和以前的方法一样,只要注意别选错了接口就好。
图六、增加接口函数 Fire_Result([in] long nResult)
我们计算整数和,得到结果后,就是要靠这个回调接口函数去反馈给客户端呀。
7、添加组件内部保存回调接口指针的数组
刚才已经说过,我们这个组件打算支持多个对象的回调连接,因此我们要使用一个数组来保存。在 ClassView 中,选择 CEvent1 类,增加成员变量 Add Member Variable...
图七、增加保存 ICallBack * 的数组
当然,保存一个数组可以有多种方式。示例程序比较简单,定义了一个10个元素空间的成员数组变量。如果你已经学会了使用 STL,那么你也可以用 vector 等容器来实现。注意!注意!注意!在构造函数中别忘了初始化数组元素为
NULL。
8、好了,下面开始完成所有代码
STDMETHODIMP CEvent1::Add(long n1, long n2) { long nResult = n1 + n2; for( int i=0; i<10; i++) { if( m_pCallBack[i] ) // 如果回调接口有效 m_pCallBack[i]->Fire_Result( nResult ); // 则发出事件/通知 } return S_OK; } STDMETHODIMP CEvent1::Advise(ICallBack *pCallBack, long *pdwCookie) { if( NULL == pCallBack ) // 居然给我一个空指针?! return E_INVALIDARG; for( int i=0; i<10; i++) // 寻找一个保存该接口指针的位置 { if( NULL == m_pCallBack[i] ) // 找到了 { m_pCallBack[i] = pCallBack; // 保存到数组中 m_pCallBack[i]->AddRef(); // 指针计数器 +1 *pdwCookie = i + 1; // cookie 就是数组下标 // +1 的目的是避免使用0,因为0表示无效 return S_OK; } } return E_OUTOFMEMORY; // 超过10个连接,内存不够用啦 } STDMETHODIMP CEvent1::Unadvise(long dwCookie) { if( dwCookie<1 || dwCookie>10 ) // 这是谁干的呀?乱给参数 return E_INVALIDARG; if( NULL == m_pCallBack[ dwCookie - 1 ] ) // 参数错误,或该接口指针已经无效了 return E_INVALIDARG; m_pCallBack[ dwCookie -1 ]->Release(); // 指针计数器 -1 m_pCallBack[ dwCookie -1 ] = NULL; // 空出该下标的数组元素 return S_OK; }
相关文章推荐
- android 利用PullToRefresh组件利用实现下拉刷新的操作步骤
- Android Widget小组件开发(一)——Android实现时钟Widget组件的步骤开发,这些知识也是不可缺少的!
- HTML5组件Canvas实现图像灰度化(步骤+实例效果)
- vue裁切预览组件功能的实现步骤
- react 实现的step组件(步骤引导)
- Android Widget小组件开发(一)——Android实现时钟Widget组件的步骤开发,这些知识也是必不可少的!
- Android Widget小组件开发(一)——Android实现时钟Widget组件的步骤开发,这些知识也是必不可少的!
- React简单的分页代码实现(子组件向父组件传值)
- 基于Vue2x实现响应式自适应轮播组件插件VueSliderShow功能
- layer前端组件实现图片显示功能
- YOLOv2训练自己的数据来实现人脸检测详细步骤
- JS拖拽插件实现步骤
- struts2如何实现页面分步骤滑动
- C++ builder 遍历所有组件的 caption 属性,轻松实现界面多语言支持
- ViewPager实现页卡的3种方法(谷歌组件)
- JS拖拽插件实现步骤
- Android:Toast在Service组件中实现其显示功能
- win7怎么使用休眠功能具体实现步骤
- flex 实现图片放大缩小恢复组件
- Vue2组件tree实现无限级树形菜单