2022年COM学习笔记 .pdf
《2022年COM学习笔记 .pdf》由会员分享,可在线阅读,更多相关《2022年COM学习笔记 .pdf(29页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、学习必备欢迎下载COM 学习笔记(一)初识COM COM-ComponentObject Model,组件对象模型。 一向以难学著称, 有人曾说过这样的话:世界上只有两个程序员真正理解COM ,他们都在微软工作。这句话虽然有点过,但基本上说出了 COM 确实有些难理解。不过,不用担心,本文并不探求多深多高的技术领域,而是带领大家浏览一下我们的COM ,就像本文的题目一样:初识COM 。首先,我们先来了解一下有关COM 的概念:COM (Component Object Model,组件对象模型)是微软公司的最高级的、包罗万象的二进制通信规范,用于软件组件间跨越多个进程、机器、硬件和操作系统 进
2、行互操作。下面我们来看看COM 的一些特点:在 COM 中,应用程序不是通过诸如ShowWindow()的 API 函数进行操纵。程序是由对象组成的, 对象向外提供一个或多个接口。接口是一组相关的函数,函数操作他们所属的对象。不能直接访问对象中的数据,而只能通过对象的接口函数访问。学过C+ 和数据结构 的人应该对上述说法并不陌生。在 COM 中,没有指向对象的指针这种东西,有的只是指向对象接口的指针。实际上,是指向另一个指针的指针。第二个指针指向一个指针表,表中的指针指向接口成员函数。该指针表称为 VTBL 。将指针指向对象后,就可以通过调用接口中的成员函数与该对象通信。如何将指针指向第一个对
3、象呢?可以调用一个返回指向对象指针的COM 函数如:CoCreateInstace()。COM 对象都提供一个叫IUnknown的接口,该接口包含方法AddRef() 、Release() 和QueryInterface()。每个接口都是从IUnknown接口派生出来的。 前两个方法操纵一个控制对象使用期限的内部引用计数。当对象第一次被创建时,创建者必须调用该对象的AddRef() ,将计数加1。每当其他的用户将一个指针指向该对象时,必须再次调用该对象的AddRef() 方法。当用户不再使用对象时,它调用对象的Release() 方法,将引用计数减1。当最后一个用户调用对象的Release()
4、 方法后,计数值变为0,导致对象释放自己。下面是 AddRef() 和 Release() 方法的简单实现:ULONG IUnknown:AddRef(void) m_RefCount+; return m_RefCount; ULONG IUnknown:Release(void) m_RefCount-; if(m_RefCount=0) 名师归纳总结 精品学习资料 - - - - - - - - - - - - - - -精心整理归纳 精选学习资料 - - - - - - - - - - - - - - - 第 1 页,共 29 页 - - - - - - - - - 学习必备欢迎下载d
5、elete this; return 0; return m_RefCount; 由于每一个对象都支持IUnknown接口,因此可以通过QueryInterface()来询问对象是否支持您感兴趣的其它接口。接口通过接口ID 来标识。HRESULT IUnknown:QueryInterface(REFIID riid,LPVOID FAR *ppv) if(riid=IID_IUnknown|riid=IID_IDropTarget) *ppv=(LPVOID)this; AddRef(); Return S_OK; else *ppv=NULL; return E_NOINTERFACE;
6、用于唯一地区分COM 中条目的标识符是一个被称为GUID(全局唯一标识符)或 UUID(通用唯一标识符)。Typedef struct_GUID unsigned long Data1; unsigned short Data2; unsigned short Data3; unsigned char Data8; GUID;GUID 的取值范围非常大,16 个字节可能形成的不同组合为3.41038 。在 COM 中传输格式化数据的工作是通过数据对象处理的,数据对象是支持IDataObject接口的对象。 IDataObject接口支持以下方法:IDataObject:GetData IDat
7、aObject:GetDataHere IDataObject:QueryGetData 名师归纳总结 精品学习资料 - - - - - - - - - - - - - - -精心整理归纳 精选学习资料 - - - - - - - - - - - - - - - 第 2 页,共 29 页 - - - - - - - - - 学习必备欢迎下载IDataObject:GetCanonicalFormatEtc IDataObject:SetData IDataObject:EnumFormatEtc IDataObject:DAdvise IDataObject:DUnadvise IDataOb
8、ject:EnumDAdvise决定了设计方案以及接口中需要包括的方法和参数后,必须使用接口描述语言(IDL )编写接口的抽象定义。编写好.IDL 文件后,使用VC+ 和 PlatformSDK自带得 MicrosoftIDL编译器编译, 并生成头文件、 勇于构建调度借口调用的代理和占为程序的代码以及实现开发工具和调用接口所必需的类型库。自动化,通过它COM 对象可以将其功能提供给解释型客户(如脚本编写语言)而不是编译型客户使用。在开发阶段,当COM 接口客户被编译时,编译器读取源代码,通过查阅头文件或类型库中的接口定义将方法名称解析为VTBL 条目,并生成目标代码,以便将必须的参数压入堆栈并
9、跳到接口VTBL 中相应条目保存的地址。编译过程可能需要很长时间,但编译后运行二进制代码的速度相对较快。而解释型客户在真正执行之前,不会将源代码解析为机器代码。 自动化对象通过一个叫做IDispatch的标准接口暴露其所有的功能,而不是将每项功能作为自定义接口的VTBL 中的条目来暴露。对对象的任何内部方法的调用都是通过该接口进行处理的。IDispatch接口的方法包括:IDispatch:Invoke IDispatch:GetIDsOfNames IDispatch:GetTypeInfo IDispatch:GetTypeInfoCount当客户想调用自动化对象的内部方法时,它调用对象的
10、IDispatch:Invoke()。客户可使用IDispatch:GetIDsOfNames获得想要做事情的ID。类型库是对象厂商提供的静态数据结构的集合,通过ItypeLib接口进行访问,包含关于单个对象、接口或类的信息。类型库可以包含描述下述内容的信息:服务器支持的对象类型 每个对象方法及其参数和类型 每个对象属性及其类型 枚举常量值 到在线文档中特定条目的引用COM Language RequirementsTheonly language requirement for COM is that code is generated in a language thatcan creat
11、e structures of pointers and, either explicitly or implicitly, callfunctions through pointers. Object-oriented languages such as C+ andSmalltalk? provide programming 名师归纳总结 精品学习资料 - - - - - - - - - - - - - - -精心整理归纳 精选学习资料 - - - - - - - - - - - - - - - 第 3 页,共 29 页 - - - - - - - - - 学习必备欢迎下载mechanis
12、ms that simplify the implementation ofCOM objects, but languages such as C, Pascal, Ada, Java , and even BASICprogramming environments can create and use COM objects. 以上摘自MSDN ,重要的是C, Pascal, Ada, Java,and even BASIC都可以用来编写COM 。以上初步介绍了关于COM 的一些东西, 不多也很浅, 理解以上的部分就够花费很长一段时间的了,如果真地对COM 感兴趣的话,最好有一定的基础,包
13、括:数据结构,面向对象的程序设计, Windows编程等,不过也不一定都学,只是这些会对你学习COM 并在短时间内掌握并深入理解COM 会有相当的好处。COM 学习笔记(二) CoCreateInstance具体内部实现cpp view plaincopy1. CoCreateInstance(.) 2. 3./. 4.IClassFactory *pClassFactory=NULL; 5.CoGetClassObject(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void *)&pClassFactory);
14、 6.pClassFactory-CreateInstance(NULL, IID_IUnknown, (void *)&pUnk); 7.pClassFactory-Release(); 8./. 9. 这段话的意思就是先得到类厂对象,再通过类厂创建组件从而得到IUnknown指针。 继续深入一步,看看CoGetClassObject的内部伪码:cpp view plaincopy1. CoGetClassObject(.) 2. 3./ 通过查注册表CLSID_Object,得知组件DLL 的位置、文件名4./ 装入 DLL 库5./ 使用函数 GetProcAddress(.)得到 DL
15、L 库中函数 DllGetClassObject的函数指针。6./ 调用 DllGetClassObject 7. 8./DllGetClassObject是干什么的,它是用来获得类厂对象的。只有先得到类厂才能去创建组件 . 名师归纳总结 精品学习资料 - - - - - - - - - - - - - - -精心整理归纳 精选学习资料 - - - - - - - - - - - - - - - 第 4 页,共 29 页 - - - - - - - - - 学习必备欢迎下载9./下面是 DllGetClassObject的伪码:10.DllGetClassObject(.) 11. 12./.
16、 13.CFactory* pFactory= new CFactory; / 类厂对象14.pFactory-QueryInterface(IID_IClassFactory, (void *)&pClassFactory); 15./ 查询 IClassFactory指针16.pFactory-Release(); 17./. 18. 19./CoGetClassObject的流程已经到此为止,现在返回CoCreateInstance,看看CreateInstance的伪码:20.CFactory:CreateInstance(.) 21. 22./. 23.CObject *pObjec
17、t = new CObject; / 组件对象24.pObject-QueryInterface(IID_IUnknown, (void *)&pUnk); 25.pObject-Release(); 26./. 27. 这部分我们将构造一个创建COM 组件的最小框架结构,然后看一看其内部处理流程是怎样的名师归纳总结 精品学习资料 - - - - - - - - - - - - - - -精心整理归纳 精选学习资料 - - - - - - - - - - - - - - - 第 5 页,共 29 页 - - - - - - - - - 学习必备欢迎下载cpp view plaincopy1.I
18、Unknown *pUnk=NULL; 2.IObject *pObject=NULL; 3.CoInitialize(NULL); 4.CoCreateInstance(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IUnknown, (void *)&pUnk); 5.pUnk-QueryInterface(IID_IOjbect, (void *)&pObject); 6.pUnk-Release(); 7.pObject-Func(); 8.pObject-Release(); 9.CoUninitialize(); cpp view pl
19、aincopy1.CoCreateInstance(.) 2. 3. 4.IClassFactory *pClassFactory=NULL; 5.CoGetClassObject(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void *)&pClassFactory); 6.pClassFactory-CreateInstance(NULL, IID_IUnknown, (void *)&pUnk); 7.pClassFactory-Release(); 8. 9. 这就是一个典型的创建COM 组件的框架,不过我
20、的兴趣在CoCreateInstance身上,让我们来看看它内部做了一些什么事情。以下是它内部实现的一个伪代码: cpp view plaincopy1.CoGetClassObject(.) 2. 3./ 通过查注册表CLSID_Object,得知组件DLL 的位置、文件名4./ 装入 DLL库5./ 使用函数 GetProcAddress(.)得到 DLL 库中函数 DllGetClassObject的函数指针。6./ 调用 DllGetClassObject7. 8.DllGetClassObject是干什么的, 它是用来获得类厂对象的。只有先得到类厂才能去创建组件. 9.下面是 Dll
21、GetClassObject的伪码:10.DllGetClassObject(.) 11. 名师归纳总结 精品学习资料 - - - - - - - - - - - - - - -精心整理归纳 精选学习资料 - - - - - - - - - - - - - - - 第 6 页,共 29 页 - - - - - - - - - 学习必备欢迎下载12. 13.CFactory* pFactory= new CFactory; / 类厂对象14.pFactory-QueryInterface(IID_IClassFactory, (void *)&pClassFactory); 15./ 查询 IC
22、lassFactory指针16.pFactory-Release(); 17. 18. 19.CoGetClassObject的流程已经到此为止,现在返回CoCreateInstance,看看CreateInstance的伪码:20.CFactory:CreateInstance(.) 21. 22. 23.CObject *pObject = new CObject; / 组件对象24.pObject-QueryInterface(IID_IUnknown, (void *)&pUnk); 25.pObject-Release(); 26. 27. 这段话的意思就是先得到类厂对象,再通过类厂
23、创建组件从而得到IUnknown指针。 继续深入一步,看看CoGetClassObject的内部伪码:上图是从 COM+ 技术内幕中COPY 来的一个例图,从图中可以清楚的看到CoCreateInstance的整个流程。(7) 一个典型的自注册的COM DLL所必有的四个函数DllGetClassObject:用于获得类厂指针DllRegisterServer:注册一些必要的信息到注册表中名师归纳总结 精品学习资料 - - - - - - - - - - - - - - -精心整理归纳 精选学习资料 - - - - - - - - - - - - - - - 第 7 页,共 29 页 - -
24、- - - - - - - 学习必备欢迎下载DllUnregisterServer:卸载注册信息DllCanUnloadNow:系统空闲时会调用这个函数,以确定是否可以卸载DLL DLL 还有一个函数是DllMain, 这个函数在COM 中并不要求一定要实现它,但是在VC生成的组件中自动都包含了它,它的作用主要是得到一个全局的实例对象。(8) 注册表在 COM 中的重要作用首先要知道GUID 的概念, COM 中所有的类、接口、类型库都用GUID 来唯一标识,GUID 是一个 128 位的字串,根据特制算法 生成的 GUID 可以保证是全世界唯一的。COM组件的创建, 查询接口都是通过注册表进
25、行的。有了注册表, 应用程序就不需要知道组件的DLL 文件名、位置,只需要根据CLSID 查就可以了。当版本升级的时侯,只要改一下注册表信息就可以神不知鬼不觉的转到新版本的DLL 。COM 学习笔记(三) IUnknown 接口一:接口定义任何一个接口都是继承于IUnknown接口。客户同组件的交互都是通过一个接口完成的。在客户查询组件的其他接口时,也是通过接口完成的。这个接口就是Iunkown,它的定义包含在Win32 SDK 中的 UNKOWN.h 头文件中。cpp view plaincopy1.interface IUnkown 2.3. 4.5.virtualHRESULT _std
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 2022年COM学习笔记 2022 COM 学习 笔记
限制150内