COM初体验
以前在我学校里培训过一段时间C++,我敬爱的吴老师略有提及。那个时候觉得COM遥不可及,觉得,哇塞好神圣。我觉得自己啥都没学好,我不应该这么早去涉及这片过于光荣的领地。既没有觉悟也没有动力去迎接这样一场学习。让对于COM的学习一拖再拖,就像拖延症。然而现实总是残酷的这项技术早已经不再神秘不再光荣依旧,技术的发展甩给我狠狠地一记巴掌,如果连这种技术都不了解确实很难混下去了。
#define interface struct
在其它开发平台下,也可以自己编写预定义代码
COM组件与COM接口:
interface IUnknown
{
virtual HRESULT QueryInterface(const IID &iid, void **ppv) = ;
virtual ULONG AddRef() = ;
virtual ULONG Release() = ;
};
QueryInterface:
可以通过QueryInterface函数来查询某个组件是否支持某个特定的接口。若支持,QueryInterface返回一个指向此接口的指针。这里我们看到函数返回类型为HRESULT,参数其中一个的类型是const IID&。HRESULT跟IID是什么呢?

typedef struct _GUID
{
DWORD Data1; //随机数
WORD Data2; //和时间相关
WORD Data3; //和时间相关
BYTE Data4[]; //和网卡MAC相关
} GUID;
GUID:
// {0E04C466-6CE9-4513-B306-43E8F7025EB9}
static const GUID guid =
{ 0xe04c466, 0x6ce9, 0x4513, { 0xb3, 0x6, 0x43, 0xe8, 0xf7, 0x2, 0x5e, 0xb9 } };
QueryInterface的实现:
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppv)
{ if (iid == IID_IUnknown)
{
//即使CA继承了两个IUnknown接口,其中一个来自于IX,另一个来自于IY。我们一般返回第一个被继承的IX接口。
*ppv = static_cast<IX*>(this);
}
else if (iid == IID_IX)
{
//返回IX接口
*ppv = static_cast<IX*>(this);
}
else if (iid == IID_IY)
{
//返回IY接口
*ppv = static_cast<IY*>(this);
}
else
{
//查询不到IID,*ppv返回NULL。
*ppv = NULL;
return E_NOINTERFACE; //函数返回值返回E_NOINTERFACE,表示组件不支持iid的接口。
} //查询成功时,需要自增引用计数
AddRef(); return S_OK; //返回S_OK
}
引用计数的原理:
virtual ULONG STDMETHODCALLTYPE AddRef()
{
//简单实现方法
return ++m_lCount; //多线程编程采用如下方法,这种方法确保同一个时刻只会有一个线程来访问成员变量
//return InterlockedIncrement(&m_lCount);
} virtual ULONG STDMETHODCALLTYPE Release()
{
//简单实现方法
if (--m_lCount == )
{
delete this; //销毁自己
return ;
}
return m_lCount; ////多线程编程采用如下方法,这种方法确保同一个时刻只会有一个线程来访问成员变量
//if (InterlockedDecrement(&m_lCount) == 0)
//{
// delete this; //销毁自己
// return 0;
//}
//return m_lCount;
}
引用计数的优化:
一、输入参数原则:输入参数指的是给函数传递某个值的参数。在函数体中将会使用这个值但却不会修改它或将其返回给调用者。在C++中,输入参数实际上就是那些按值传递的参数。对传入函数的接口指针,无需调用AddRef与Release
二、局部变量原则对于局部复制的接口指针,由于它们只是在函数的生命期内才存在,因此无需调用AddRef与Release
void Fun(IX *pIXParam) //参数传递存在赋值过程
{
//pIXParam->AddRef(); //可优化,注释掉
pIXParam->Fx1();
pIXParam->Fx2();
//pIXParam->Release(); //可优化,注释掉
}
void Fun(IX *pIX)
{
IX *pIX2 = pIX;
//pIX2->AddRef(); //可优化,注释掉
pIX2->Fx1();
pIX2->Fx2();
//pIX2->Release(); //可优化,注释掉
}
void Fun(IX **ppIX)
{
(*ppIX)->Fx1();
(*ppIX)->Fx2();
(*ppIX)->Release(); //可以优化吗?
*ppIX = m_pIXOther;
(*ppIX)->AddRef(); //可以优化吗?
(*ppIX)->Fx1();
(*ppIX)->Fx2();
}
//以上两句务必要运行,因为*ppIX 与m_pIXOther不一个属性同一个组件。
//比如假设*ppIX是指向第一次的new CA(),而m_pIXOther却是指向第二次的new CA()。
//或者*ppIX是指向new CA(),而m_pIXOther是指向new CZ(),CA与CZ的共同点,只是都继承了IX接口而已。
COM初体验的更多相关文章
- .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
不知不觉,“.NET平台开源项目速览“系列文章已经15篇了,每一篇都非常受欢迎,可能技术水平不高,但足够入门了.虽然工作很忙,但还是会抽空把自己知道的,已经平时遇到的好的开源项目分享出来.今天就给大家 ...
- Xamarin+Prism开发详解四:简单Mac OS 虚拟机安装方法与Visual Studio for Mac 初体验
Mac OS 虚拟机安装方法 最近把自己的电脑升级了一下SSD固态硬盘,总算是有容量安装Mac 虚拟机了!经过心碎的安装探索,尝试了国内外的各种安装方法,最后在youtube上找到了一个好方法. 简单 ...
- Spring之初体验
Spring之初体验 Spring是一个轻量级的Java Web开发框架,以IoC(Inverse of Control 控制反转)和 ...
- Xamarin.iOS开发初体验
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKwAAAA+CAIAAAA5/WfHAAAJrklEQVR4nO2c/VdTRxrH+wfdU84pW0
- 【腾讯Bugly干货分享】基于 Webpack & Vue & Vue-Router 的 SPA 初体验
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d13a57132ff21c38110186 导语 最近这几年的前端圈子,由于 ...
- 【Knockout.js 学习体验之旅】(1)ko初体验
前言 什么,你现在还在看knockout.js?这货都已经落后主流一千年了!赶紧去学Angular.React啊,再不赶紧的话,他们也要变out了哦.身旁的90后小伙伴,嘴里还塞着山东的狗不理大蒜包, ...
- 在同一个硬盘上安装多个 Linux 发行版及 Fedora 21 、Fedora 22 初体验
在同一个硬盘上安装多个 Linux 发行版 以前对多个 Linux 发行版的折腾主要是在虚拟机上完成.我的桌面电脑性能比较强大,玩玩虚拟机没啥问题,但是笔记本电脑就不行了.要在我的笔记本电脑上折腾多个 ...
- 百度EChart3初体验
由于项目需要在首页搞一个订单数量的走势图,经过多方查找,体验,感觉ECharts不错,封装的很细,我们只需要看自己需要那种类型的图表,搞定好自己的json数据就OK.至于说如何体现出来,官网的教程很详 ...
- Python导出Excel为Lua/Json/Xml实例教程(二):xlrd初体验
Python导出Excel为Lua/Json/Xml实例教程(二):xlrd初体验 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出E ...
- Docker初体验
## Docker初体验 安装 因为我用的是mac,所以安装很简单,下载dmg下来之后拖拽安装即可完成. 需要注意的就是由于之前的docker是基于linux开发,不支持mac,所以就出现了docke ...
随机推荐
- Web.xml配置详解之context-param (加载spring的xml,然后初始化bean看的)
http://www.cnblogs.com/goody9807/p/4227296.html(很不错啊) 容器先加载spring的xml,然后初始化bean时,会为bean赋值,包括里面的占位符
- MORE ABORT AWR?
For some time, Oracle’s solution in this area has been its built-in tool, Statspack.Oracle Database ...
- ios framework通用库的制作
这篇文章是在史上最完整的iOS DIY framework 详细教程(一)的基础上加以修改 1.新建一个静态库工程: 2:取自己喜欢的名字: 3.删除向导所生成工程中的 Target: 3.删除Tes ...
- 吐槽:Lambda表达式
前面我曾经讨论过Lambda表达式(也就是匿名表达式)的用法, 这里我就主要强调一下匿名表达式的好处. 首先是不需要写多余的方法体,特别是订阅事件的时候,但是也有一个问题,那就是单个方法会因为匿名表达 ...
- 在调用Qt库来实现功能过程中的一些总结
1.对于QTabWidget中tab名字的变化.当其中只有一个&时,Qt Assistant中给出的解释是:If the tab's label contains an ampersand, ...
- 由C到C++的学习 ----Essential C++
一.array[] 与 vector<int> vector1 1 array[] <- 此中要填写数组的大小,而且array[]自己是不知道自己的大小的 2.1 vector< ...
- Setup VSFTPD Server with Virtual Users On CentOS, RHEL, Scientific Linux 6.5/6.4/6.3
We have already shown you How to Setup VSFTPD Server on CentOS 6.5/6.4 in our previous article. In t ...
- C#程序中:如何启用进程、结束进程、查找进程
在启动某个程序之前,如果需要先检查改程序是否已经运行,可以查找进程里有没有这个进程,再根据查找进程后的结果进行相应的判断操作. 产找进程的范围是任务管理器中的进程列表.如果进程被隐藏了,结果……(我没 ...
- 配置Struts2的异常处理
最好的方式是通过声明管理异常处理 1Action里面的execute()方法抛出所有异常:public String execute() throws Exception{} 2声明异常捕捉 ...
- 精通 Oracle+Python,第 4 部分:事务和大型对象
通过 Python 管理数据事务.处理大型对象 2010 年 3 月发布 事务包含一组 SQL 语句,这组 SQL 语句构成数据库中的一个逻辑操作,如转帐或信用卡支付操作.将 SQL 语句聚合到一个逻 ...