已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
三、使用ATL简化编程

使用原生的COM接口的话,需要自己管理生存期,上边的程序很简单并无大碍,但稍微复杂一点的程序便十分棘手,还容易出错。为了减少编程人员的负担,使COM编程更加方便和可靠,微软的ATL(活动模板库)为我们准备了一个COM接口的智能指针:CComPtr<T>。

CComPtr<T>的主要作用是容纳接口的指针T*。CComPtr<T>在赋值时会自动进行Release和AddRef,在出作用域时自动进行Release,实现了自动管理生命周期。它同时重载了模板化赋值运算符,自动调用QueryInterface。还简化了CoCreateInstance等函数的调用。

首先,使用ATL要使用C++编译器编译,并且包含头文件atlbase.h:
#include <atlbase.h>

CComPtr<T>的使用很简单。建立一个空指针的操作如下:
CComPtr<ISpVoice> pISpVoice; // 自动设为NULL

在CComPtr<T>上建立新实例(注意是点运算符,不是箭头):
hr = XXXXXXXXXXXXCreateInstance(CLSID_SpVoice); // 省略了后两个参数:pUnkOuter=NULL, dwClsContext=CLSCTX_ALL

调用成员函数(箭头运算符):
hr = pISpVoice->Speak(L"电脑在说话!", SPF_DEFAULT, NULL);

赋值:
pISpVoice2 = pISpVoice; // 自动调用pISpVoice2的Release和pISpVoice的AddRef

转换接口类型:
CComPtr<IUnknown> pUnk = pISpVoice; // 自动调用QueryInterface,失败则返回NULL

取地址:
pUnk = NULL; // 作为输出(out)参数必须先置为NULL
pISpVoice.QueryInterface(&pUnk);
// &运算符获得pUnk.p成员变量的地址

CComPtr<T>在离开作用域时会自动释放。但有时需要手动释放,比如需要再次调用CoCreateInstance时。手动释放有两种方法:
1.赋值NULL
pISpVoice = NULL; // 自动调用Release
2.调用.Release(),注意不是->Release(),它会同时将值设为NULL,防止悬空指针产生
XXXXXXXXXXXXlease(); // 调用Release,同时设为NULL

有了CComPtr<T>,我们的程序可以简化为这样。可以看到,我们已经不再需要手工释放COM组件了,CoCreateInstance的调用也大为简化:
<code class="lang-cpp">#include <stdio.h>
#include <stdlib.h>
          
#include <windows.h> // 使用COM组件需要包含windows.h
#include <sapi.h> // 使用ISpVoice语音组件需要包含sapi.h
#include <atlbase.h> // 使用CComPtr<t>需要包含atlbase.h
          
#define ValidateHR(hr) \
    if (FAILED(hr)) { \
        printf("HRESULT错误:%p,在%s第%d行\n", hr, __FILE__, __LINE__); \
        exit(1); \
    }
          
int main()
{
    HRESULT hr = CoInitialize(0); // 初始化COM环境,参数保留,必须为0
    ValidateHR(hr);
          
    {
        // 建立ISpVoice接口实例(组件ID为CLSID_SpVoice)
        CComPtr<ispvoice> pISpVoice;
        hr = pISpVoice.CoCreateInstance(CLSID_SpVoice); // 点运算符。省略了后两个参数:NULL, CLSCTX_ALL
        ValidateHR(hr);
          
        // 调用ISpVoice的Speak成员函数
        hr = pISpVoice->Speak(L"电脑在说话!", SPF_DEFAULT, NULL);
        ValidateHR(hr);
          
    } // pISpVoice在作用域边界会自动释放
              
    CoUninitialize(); // 卸载COM环境
    return 0;
}</ispvoice></t></atlbase.h></sapi.h></windows.h></stdlib.h></stdio.h></code>

为了方便起见,以后的程序均使用CComPtr<IMyInterface>,不再使用IMyInterface*。
文号 / 789538

千古风流
名片发私信
学术分 4
总主题 466 帖总回复 2942 楼拥有证书:进士 学者 笔友
注册于 2009-05-30 21:22最后登录 2019-01-31 17:16
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步

个人简介

暂未填写
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

插入资源
全部
图片
视频
音频
附件
全部
未使用
已使用
正在上传
空空如也~
上传中..{{f.progress}}%
处理中..
上传失败,点击重试
等待中...
{{f.name}}
空空如也~
(视频){{r.oname}}
{{selectedResourcesId.indexOf(r.rid) + 1}}
处理中..
处理失败
插入表情
我的表情
共享表情
Emoji
上传
注意事项
最大尺寸100px,超过会被压缩。为保证效果,建议上传前自行处理。
建议上传自己DIY的表情,严禁上传侵权内容。
点击重试等待上传{{s.progress}}%处理中...已上传,正在处理中
空空如也~
处理中...
处理失败
加载中...
草稿箱
加载中...
此处只插入正文,如果要使用草稿中的其余内容,请点击继续创作。
{{fromNow(d.toc)}}
{{getDraftInfo(d)}}
标题:{{d.t}}
内容:{{d.c}}
继续创作
删除插入插入
插入公式
评论控制
加载中...
文号:{{pid}}
加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}
ID: {{user.uid}}