《COM技术内幕》笔记(1)

《COM技术内幕》笔记(1)

第1章 组件

1、COM,即组件对象模型,是关于如何建立组件以及如何通过组件建构应用程序的一个规范。
2、组件的优点:应用程序可随时间的流逝而发展变化;定制应用程序;组件库;分布式组件。
3、对组件的需求:组件必须动态连接;必须隐藏其内部实现细节。
4、COM组件是以Win32动态链接库(DLLs)或可执行文件(EXEs)的形式发布的可执行代码组成

的。遵循COM规范编写的组件将能够满足对组件家够的所有需求。COM组件是动态链接的,COM使

用DLL将组件动态链接起来。对于COM组件的封装是很容易的。COM组件按照一种标准的方式来宣

布他们的存在。COM组件是一种给其他应用程序提供面向对象的API或服务的极好方法。
5、COM并不是一种计算机语言。
6、将COM同DLL相提并论是不合适的。实际上COM使用了DLL来给组件提供动态链接的能力。
7、COM并不是像Win32API那样的函数集,它更主要的是一种编写能够按面向对象API形式提供服

务的组件的方法。
8、COM并不是类似于MFC这样的C++类库。COM给开发人员提供的是一种开发与语言无关的组件库

的方法,但COM本身并没有提供任何实现。
9、COM具有一个被称作是COM库的API,它提供的是对所有客户及组件都非常有用的组件管理服务

第2章 接口

1、在COM中接口就是一切。
(1)接口可以保护系统免首外界变化的影响。
(2)接口可以使客户用同样的方式来处理不同的组件。
2、(1)COM接口在C++中是用纯抽象基类实现的。
   (2)一个COM组件可以提供多个接口。
   (3)一个C++类可以使用多继承来实现一个可以提供多个接口的组件。
3、类并非组件。
4、接口并非总是继承的。对接口的继承只不过是一种实现细节而已。除了可以使用一个类来实

现几个不同的接口外,还可以用单个的类来实现每一个接口再使用指向这些类的指针。
5、组件可以支持任意数目的接口。为支持多重接口,可以使用多重继承。支持多重接口的组件

可以被看作是接口的集合。
6、COM接口的不变性、多态以及接口继承。
(1)一旦公布了一个接口,那么它将永远保持不变。当对组件进行升级时,一般不会修改已有

的接口,而是加入一些新的接口。
(2)多态指的是可以按同一种方式来处理不同的对象。
7、虚拟函数表(vtbl):包含一组指向虚拟函数实现的指针。
定义一个纯抽象基类也就是定义了相应的内存结构。但此内存只是在派生类中实现此抽象基类时

才会被分配。当派生类继承一个抽象基类时,它将继承此内存结构。
8、在COM中,对一个组件的访问只能通过函数完成,而绝不能直接通过变量。

9、接口的真正的威力在于继承此接口的所有类均可以被客户按同一方式进行处理。

第3章 QueryInterface函数

1、接口查询:
客户同组件的交互都是通过一个接口完成的。在客户查询组件的其他接口时,也是通过接口完成

的。这个接口就是IUnknown。
IUnknown接口的定义包含在Win32 SDK中的UNKNOWN.H头文件中。
interface IUnknown
{
    virtual HRESULT _stdcall QueryInterface(const IID& iid,void **ppv) = 0;
    virtual ULONG _stdcall AddRef() = 0;
    virtual ULONG _stdcall Release() = 0;
}
在IUnknown中定义了一个名为QueryInterface的函数。客户可以调用QueryInterface来决定组件

是否支持某个特定的接口。
2、所有的COM接口都需要继承IUnknown。
3、由于所有的COM接口都继承了IUnknown,每个接口的vtbl中的前三个函数都是

QueryInterface,AddRef和Release。若某个接口的vtbl中的前三个函数不是这三个,那么它将不

是一个COM接口。由于所有的接口都是从IUnknown 继承的,因此所有的接口都支持

QueryInterface.因此组件的任何一个接口都可以被客户用来获取它所支持的其他接口。
4、非虚拟继承:注意IUnknown并不是虚拟基类,所以COM接口并不能按虚拟方式继承IUnknown,

这是由于会导致与COM不兼容的vtbl。若COM接口按虚拟方式继承IUnknown,那么COM接口的vtbl

中的头三个函数指向的将不是IUnknown的三个成员函数。
5、一个QuertyInterface可以用一个简单的if-then-else语句实现,但case语句是无法用的,因

为接口标识符是一个结构而不是一个数。
6、多重类型及类型转换
7、QueryInterface的规则
(1)QueryInterface返回的总是同一IUnknown指针。
(2)若客户曾经获取过某个接口,那么它将总能获取此接口。
(3)客户可以再次获取已经拥有的接口。
(4)客户可以从任何接口返回到起始接口。
(5)若能够从某个借口获取某特定接口,那么可以从任意接口都将可以获取此接口。
8、接口的IID决定了它的版本。当改变了下列条件中的任何一个时,就应给新接口指定新的ID:
(1)接口中函数的数目。
(2)接口中函数的是顺序。
(3)某个函数的参数。
(4)某个函数参数的顺序。
(5)某个函数参数的类型。
(6)函数可能的返回值。
(7)函数参数的含义。
(8)接口中函数的含义。
9、避免违反隐含和约:
(1)使接口不论在其成员函数怎么被调用都能正常工作。
(2)强制客户按一定的方式来使用此接口并在文档中将这一点说明清楚。

//

第4章 引用计数

1、生命期控制
IUnknown的另外两个成员函数AddRef和Release的作用就是给客户提供一种让它指示何时处理完

一个接口的手段。
2、AddRef和Release实现的是一种名为引用计数的内存管理技术。
引用计数是使组件能够自己将自己删除的最简单同时也是效率最高的方法。
COM组件将维护一个称做是引用计数的数值。当客户从组件取得一个接口时,此引用计数值将增1

。当客户使用完某个接口后,组件的引用计数值将减1。当引用计数值为0时,组件即可将自己从

内存中删除。
3、正确使用引用计数规则:
(1)在返回之前调用AddRef。对于那些返回接口指针的函数,在返回之前应用相应的指针调用

AddRef。这些函数包括QueryInterface及CreateInstance。这样当客户从这种函数得到一个接口

后,它将无需调用AddRef。
(2)在使用完接口之后调用Release。在使用完某个接口之后应调用此接口的Release函数。
(3)在赋值之后调用AddRef。在将一个接口指针赋给另外一个接口指针时,应调用AddRef。换

句话说,在建立接口的另外一个引用之后应增加相应组件的引用计数。
4、在客户看来,引用计数是处于接口级上而不是组件级上的。
5、为什么选择为每一个接口单独维护一个引用计数而不是针对整个组件维护引用计数?(1)使

程序调试更为方便;(2)支持资源的按需获取。
6、AddRef&Release的例子
ULONG _stdcall AddRef()
{
    return InterlockedIncrement(&m_cRef);
}
ULONG _stdcall Release()
{
    if(InterlockedDecrement(&m_cRef)
    {
        delete this;
        return 0;
    }
    return m_cRef;
}
7、当建立一个新组件时,应建立一个对此组件的引用。因此创建组件时,在将指针返回给客户

之前,应该增大组件的引用计数值。这使程序员可以不必在调用CreateInstance 或

QueryInterface之后记着去调用AddRef。
8、引用计数规则优化:
(1)输出参数规则:任何在输出参数中或作诶返回值返回一个新的接口指针的函数必须对此接

口指针调用AddRef。
(2)输入参数规则:对传入函数的接口指针,无需调用AddRef和Release,这是因为函数的生命

期嵌套在调用者的生命周期内。
(3)输入-输出函数规则:对于用输入-输出参数传递进来的接口指针,必须在给它赋另外一个

接口指针之前调用其Release。在函数返回之前,还必须对输出参数中所保存的接口指针调用

AddRef。如:
void ExchangeForCachedPtr( int i, IX **ppIX)
{
    (*ppIX)->Fx();  //Do something with in-parameter.
    (*ppIX)->Release();//Release in parameter.
    *ppIX = g_Cache[i];//Get cached pointer.
    (*ppIX)->AddRef();//AddRef pointer.
    (*ppIX)->Fx();//Do something with out-parameter.
}
(4)局部变量规则:对于局部复制的接口指针,由于它们只是在函数的生命周期内才存在,因

此无需调用AddRef和Release。
(5)全局变量规则:对于保存在全局变量中的接口指针,在将其传递给另外一个函数之前,必

须调用其AddRef。由于此变量是全局的,因此任何函数都可以通过调用其Release来终止其生命

期。对于保存在成员变量中的接口指针,也应按此种方式进行处理。因为类中的任何成员函数都

可以改变次中接口指针的状态。
(6)不能确定时的规则:对于任何不能确定的情形,都应调用AddRef和Release对。

第5章 动态链接

1、从DLL中输出函数:用extern "c"标记。
2、在使用VC时,可以用DUMPBIN。EXE来得到某个DLL中所输出的符号的清单。如下面的命令:

dumpbin -exports Cmpnt1.dll
3、装载DLL:LoadLibrary以被装载的DLL的名称作为参数并返回一个指向所装载的DLL的句柄。

win32的GetProcAddress函数可以使用此句柄以及待用的函数的名称,然后返回一个指向次函数

的指针。
4、使用DLL实现组件的原因:DLL可以共享它们所链入的应用程序的地址空间。

//

第6章 关于HRESULT、GUID、注册表及其他细节

1、HRESULT值的结构:
 _________________________________________________________
|    |                                                  |                                                            |                                            
|    |             15bits设备代码            |       16bits返回代码                            |
|__|_________________________|______________________________|
 31 30                                         16  15                           0

2、常用的HRESULT值:
3、一般不能直接将HRESULT值同某个成功代码(如S_OK)进行比较以决定某个函数是否成功也不

能直接将其同某个失败代码(如E_FAIL)进行比较以决定函数调用是否失败。应该使用

SECCEEDED和FAILED宏。
HRESULT hr = CoCreateInstance(...);
if(FAILED(hr))
    return ;
hr = pI->QueryInterface(...);
if(SUCCEEDED(hr))
{
    pIX->Fx();
    pIX->Release();
}
pI->Release();

4、当前所定义的设备代码:
——————————————————————————————————
FACILITY_WINDOWS  8
FACILITY_STORAGE  3
FACILITY_SSPI   9
FACILITY_RPC   1
FACILITY_WIN32   7
FACILITY_CONTROL  10
FACILITY_NULL   0
FACILITY_ITF   4
FACILITY_DISPATCH  2
FACILITY_CERT   11
——————————————————————————————————

5、关于定义自己的HRESULT的一些一般性规则:
(1)不要将0X0000及IX01FF范围内的值作为返回代码。这些值是为COM所定义的FACILITY_ITF代

码而保留的。只有遵循这一规则,才不致使用户自己定义的代码同COM所定义的代码相混淆。
(2)不要传播FACILITY_ITF错误代码。
(3)尽可能使用通用的COM成功及失败代码。
(4)避免定义自己的HRESULT,而可以在函数中使用一个输出参数。
6、用MAKE_HRESULT宏来定义一个HRESULT值,此宏可根据所提供的严重级别、设备代码及返回代

码生成一个HRESULT值。如:
MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,100);
7、GUID是英文Globally Unique Identifier(全局唯一标识符)的首字母缩写。IID是一个128比

特(16)字节的一个GUID结构。
8、生成GUID :UUIDGEN.EXE和GUIDGEN.EXE
9、GUID的比较:操作符==;等价函数IsEqualGUID,IsEqualIID,IsEqualCLSID。
10、将GUID作为组件标识符
11、由于一个GUID值占用了16个字节,因此一般不用值传递GUID参数。而大量使用的是按引用传

递。
12、COM只使用了注册表的一个分支:HKEY_CLASSES_ROOT。
13、注册表CLSID是一个具有如下格式的串:
{********-****-****-****-************}
14、CLSID关键字的子关键字InprocServer32关键字的缺省值是组件所在的DLL文件名称。
15、一些特殊关键字:
(1)AppID:此关键字下的子关键字的作用是将某个APPID(应用程序ID)隐射成某个远程服务

器名称。分布式COM将用到此关键字。
(2)组见类别:注册表的这一分支可以将CATID(组件类别ID)映射成某个特定的组件类别。
(3)Interface:用于将IID映射成与某个接口相关的信息。
(4)Licenses:保存授权使用COM组件的一些许可信息。
(5)TypeLib:类型库关键字所保存的是关于接口成员函数所用参数的信息等。
16、ProgID命名约定:
<Program>.<component>.<version>
17、从ProgID到CLSID的转换:COM库函数:CLSIDFromProgID和ProgIdFromCLSID:
CLSID clsid;
CLSIDFromProgID("****.****.****",&clsid);
18、自注册:DLL一定要输出下边两个函数:
STDAPI DllRegisterServer();
STDAPI DllUnregisterServer();
用户可以使用程序REGSVR32.EXE来注册某个组件,它实际上是通过上述函数来完成组件的注册的


19、组件类别使开发人员能够使开发人员无需创建组件实例就能决定它是否特工所需接口。一个

组件类别实际上就是一个接口集合,该集合将被分配给一个GUID,此GUID此时被称做是CATID。

对于某个组件而言,若它实现了某个组件类别的所有接口,那么它可以将其注册成该组件类别的

一个成员。这样,客户就能够通过从注册表中选择只属于某个特定组件类别的组件而准确找到它

所需的组件。
20、组件类别的用途:指定某个组件必须实现的接口集合;用于指定组件需要其客户提供的接口

集合。
22、在使用COM库中的其他函数(除CoBuildVersion外,此函数将返回COM库的版本号)之前,进

程必须先调用CoInitialize来初始化COM库函数。当进程不再需要使用COM库函数时,必须调用

CoUninitialize。对每一个进程,COM库函数只需初始化一次。这并不是说不能多次调用

CoInitailize,但需保证每一个CoInitialize都有一个相应的CoUnoinitialize调用。当进程已

经调用过CoInitialize后,再次调用此函数所得到的返回值将是S_FALSE而不再是S_OK.
23、OLE是建立在COM基础之上的,它增加了对类型库、剪贴板、拖放、ActiveX文档、自动化以

及ActiveX控件的支持。在OLE库中包含对这些特性的额外的支持。在需要使用这些特性时,应调

用OleInitailize及OleUninitialize,而不是CoInitailize和 CoUninitialize。Ole*函数将调用

Co*函数。但若程序中没有用到那些额外的功能,使用Ole*将会造成资源的浪费。
24、COM中分配和释放内存的标准方法:任务内存分配器。使用此分配器,组件可以给客户提供

一块可以由客户删除的内存。可在多线程应用程序中使用。
一些方便的函数:
void  *CoTaskMemAlloc(
ULONG cb  //size in bytes of block to be allocated
);
void CoTaskMemFree(
void *pv  //pointer to memory block to be freed
);
25、StringFromGUID2可以将某个GUID转换成一个字符串:
wchar_t szCLSID[39];
int r = ::StringFromGUID2(CLSID_Component1,szCLSID,39);
 传给StringFromGUID2的参数是一个Unicode串(即一个宽字符wchar_t类型的数组而不是char类

型的字符数组)。在非Unicode的系统中,需要将结果转化为单字节字符(char)。为此,可以使

用ANSI的wcstombs函数如下:
#ifndef _UNICODE
char szCLSID_single[39];
wcstombs(szCLSID_single,szCLSID,39);
#end if

posted on 2014-03-19 10:33 提里奥弗丁 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/Fordring/p/3610791.html

《COM技术内幕》笔记(1)相关推荐

  1. 《微软的梦工场》 笔记(1)

    转载于:https://www.cnblogs.com/wmxnlfd/p/10630918.html

  2. 阿里重金投数梦工场 布局PaaS动了谁的奶酪

    就目前云计算市场来看,巨头的争夺表面上还在IaaS激战,但实际上他们对PaaS也在默默布局.6月8日,PaaS相关服务商数梦工场宣布完成光大实业资本.阿里巴巴等公司共同投资的7.5亿元A轮融资.值得注 ...

  3. 数梦工场联手阿里云 推出大数据一体机

    本文讲的是数梦工场联手阿里云 推出大数据一体机[IT168 云计算]8月19日消息,作为全球领先的云计算和大数据场景化开发与服务提供商,数梦工场依托阿里云"飞天"大规模分布式计算系 ...

  4. 数梦工场助力云计算国标制定

    当前我国移动互联.云计算.大数据.物联网和工业控制等新技术.新应用处于高速发展阶段,面对全球网络安全戒备态势,各领域信息安全等级保护工作亟须完善.全国信息安全标准化技术委员会(SAC/TC 260)提 ...

  5. 数梦工场:我们帮你实现你驾驭数据的梦想

    6月4日,在第七届中国云计算大会上,数梦工场总裁王巍介绍说,数梦工场的数就是大数据,数梦工厂在大数据的基础上实现云架构:梦就是中国梦,数梦工厂解读中国梦为青山绿水.人民幸福.政治安定和经济繁荣:第三, ...

  6. 6月13日云栖精选夜读:数梦工场完成A轮7.5亿融资 三个维度构建“新型互联网”

    原文链接 在演讲中,吴敬传借助三个故事,从三个维度讲述了如何构建"新型互联网". 热点热 议 数梦工场完成A轮7.5亿融资 三个维度构建"新型互联网" 作者:阿 ...

  7. 数梦工场携手宁波共建创新大数据云基地

    2016年1月17日上午,宁波大数据云基地揭牌暨项目签约仪式在慈溪市政府举行.杭州数梦工场科技有限公司与慈溪市政府达成战略共识,建设区域综合性大数据云基地,旨在促进云计算.大数据技术在政务.经济.民生 ...

  8. 数梦工场7.5亿元都干点啥?

    数梦工场董事长兼CEO 吴敬传在发布会上做了以"数据连接梦想"为主题的演讲,首次提出"新型互联网"理念.吴敬传讲了3个小故事,从3个维度阐述了如何构建" ...

  9. 8.25关于笔试面试(数梦工场亲宝宝)

    Java笔试面试: ①亲宝宝(三天后回复): (1)时间:2018/8/24 9:29:00 (2)笔试: 1.String类.Integer类的各个方法的实现(主要是equals.hashCode方 ...

  10. 数梦工场,新型互联网领域“独角兽”出笼

    6月8日,杭州数梦工场科技有限公司迎来了公司发展历程中的一个重要里程碑--成功完成A轮融资,获得由光大实业资本.阿里巴巴等公司共同投资的7.5亿元,公司市场估值超过10亿美元.云计算大数据领域的又一家 ...

最新文章

  1. Apache Unable to find the wrapper https - did you forget to enable it when you configured PHP?
  2. 如何优雅地展示机器学习项目!
  3. KGmailNotifier-Gmail 邮件关照轨范
  4. 常用3种数据库的Sql分页
  5. wxWidgets:wxGridRangeSelectEvent类用法
  6. 《构建之法》阅读笔记02
  7. 帮你防沉迷、为你打call、解救路痴,一文看懂Google I/O 2018
  8. linux查看cpu占用率_Linux 性能查看
  9. idea中ssm集成freemark_基于SSM框架的迷你天猫商城
  10. 阿里云ecs 服务器配置 nginx https
  11. 华为tftp服务器如何配置文件,配置tftp服务器
  12. CSS文本框里的字_把网站搬进PPT里是种怎样的体验?
  13. 二元回归方程matlab,matlab 多元非线性回归方程问题
  14. 红耳朵象全国战略,让大众享受上门洗车的福利
  15. java生成eml_用Java创建一个.eml(email)文件
  16. 初中不读学计算机难吗,为什么初中生更加适合学习计算机编程?
  17. 怎么把PicPick设置成中文版?
  18. windows10计算机管理器,win10设备管理器怎么打开?设备管理器打开的方法
  19. 计算机设置了密码后不能打印了,win7系统共享打印机设置密码后无法连接如何解决...
  20. HTML 第一学期-第八章上机练习+课后练习(简答题)

热门文章

  1. ZOJ4062 Plants vs. Zombies 二分
  2. SpringBoot 限流实现
  3. 从“四舍五入”到“奇进偶舍”
  4. 实践是检验真理的唯一标准
  5. python编程 从入门到实践 第九章 类(下)
  6. Compact PCI总线知识整理
  7. php 8进制,PHP中的进制转换
  8. 数据分析的五大用处,你都知道吗?
  9. Visio 中插入的Excel 如何只显示数据部分?
  10. 匿名科创无人机学习心得