您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 信息化管理 > COM学习笔记+++
COM学习笔记(一)初识COMCOM--ComponentObjectModel,组件对象模型。一向以难学著称,有人曾说过这样的话:世界上只有两个程序员真正理解COM,他们都在微软工作。这句话虽然有点过,但基本上说出了COM确实有些难理解。不过,不用担心,本文并不探求多深多高的技术领域,而是带领大家浏览一下我们的COM,就像本文的题目一样:初识COM。首先,我们先来了解一下有关COM的概念:COM(ComponentObjectModel,组件对象模型)是微软公司的最高级的、包罗万象的二进制通信规范,用于软件组件间跨越多个进程、机器、硬件和操作系统进行互操作。下面我们来看看COM的一些特点:在COM中,应用程序不是通过诸如ShowWindow()的API函数进行操纵。程序是由对象组成的,对象向外提供一个或多个接口。接口是一组相关的函数,函数操作他们所属的对象。不能直接访问对象中的数据,而只能通过对象的接口函数访问。学过C++和数据结构的人应该对上述说法并不陌生。在COM中,没有指向对象的指针这种东西,有的只是指向对象接口的指针。实际上,是指向另一个指针的指针。第二个指针指向一个指针表,表中的指针指向接口成员函数。该指针表称为VTBL。将指针指向对象后,就可以通过调用接口中的成员函数与该对象通信。如何将指针指向第一个对象呢?可以调用一个返回指向对象指针的COM函数如:CoCreateInstace()。COM对象都提供一个叫IUnknown的接口,该接口包含方法AddRef()、Release()和QueryInterface()。每个接口都是从IUnknown接口派生出来的。前两个方法操纵一个控制对象使用期限的内部引用计数。当对象第一次被创建时,创建者必须调用该对象的AddRef(),将计数加1。每当其他的用户将一个指针指向该对象时,必须再次调用该对象的AddRef()方法。当用户不再使用对象时,它调用对象的Release()方法,将引用计数减1。当最后一个用户调用对象的Release()方法后,计数值变为0,导致对象释放自己。下面是AddRef()和Release()方法的简单实现:ULONGIUnknown::AddRef(void){m_RefCount++;returnm_RefCount;}ULONGIUnknown::Release(void){m_RefCount--;if(m_RefCount==0){deletethis;return0;}returnm_RefCount;}由于每一个对象都支持IUnknown接口,因此可以通过QueryInterface()来询问对象是否支持您感兴趣的其它接口。接口通过接口ID来标识。HRESULTIUnknown::QueryInterface(REFIIDriid,LPVOIDFAR*ppv){if(riid==IID_IUnknown||riid==IID_IDropTarget){*ppv=(LPVOID)this;AddRef();ReturnS_OK;}else{*ppv=NULL;returnE_NOINTERFACE;}用于唯一地区分COM中条目的标识符是一个被称为GUID(全局唯一标识符)或UUID(通用唯一标识符)。Typedefstruct_GUID{unsignedlongData1;unsignedshortData2;unsignedshortData3;unsignedcharData[8];}GUID;GUID的取值范围非常大,16个字节可能形成的不同组合为3.4ⅹ10^38。在COM中传输格式化数据的工作是通过数据对象处理的,数据对象是支持IDataObject接口的对象。IDataObject接口支持以下方法:IDataObject::GetDataIDataObject::GetDataHereIDataObject::QueryGetDataIDataObject::GetCanonicalFormatEtcIDataObject::SetDataIDataObject::EnumFormatEtcIDataObject::DAdviseIDataObject::DUnadviseIDataObject::EnumDAdvise决定了设计方案以及接口中需要包括的方法和参数后,必须使用接口描述语言(IDL)编写接口的抽象定义。编写好.IDL文件后,使用VC++和PlatformSDK自带得MicrosoftIDL编译器编译,并生成头文件、勇于构建调度借口调用的代理和占为程序的代码以及实现开发工具和调用接口所必需的类型库。自动化,通过它COM对象可以将其功能提供给解释型客户(如脚本编写语言)而不是编译型客户使用。在开发阶段,当COM接口客户被编译时,编译器读取源代码,通过查阅头文件或类型库中的接口定义将方法名称解析为VTBL条目,并生成目标代码,以便将必须的参数压入堆栈并跳到接口VTBL中相应条目保存的地址。编译过程可能需要很长时间,但编译后运行二进制代码的速度相对较快。而解释型客户在真正执行之前,不会将源代码解析为机器代码。自动化对象通过一个叫做IDispatch的标准接口暴露其所有的功能,而不是将每项功能作为自定义接口的VTBL中的条目来暴露。对对象的任何内部方法的调用都是通过该接口进行处理的。IDispatch接口的方法包括:IDispatch::InvokeIDispatch::GetIDsOfNamesIDispatch::GetTypeInfoIDispatch::GetTypeInfoCount当客户想调用自动化对象的内部方法时,它调用对象的IDispatch::Invoke()。客户可使用IDispatch::GetIDsOfNames获得想要做事情的ID。类型库是对象厂商提供的静态数据结构的集合,通过ItypeLib接口进行访问,包含关于单个对象、接口或类的信息。类型库可以包含描述下述内容的信息:服务器支持的对象类型·每个对象方法及其参数和类型·每个对象属性及其类型·枚举常量值·到在线文档中特定条目的引用COMLanguageRequirementsTheonlylanguagerequirementforCOMisthatcodeisgeneratedinalanguagethatcancreatestructuresofpointersand,eitherexplicitlyorimplicitly,callfunctionsthroughpointers.Object-orientedlanguagessuchasC++andSmalltalk?provideprogrammingmechanismsthatsimplifytheimplementationofCOMobjects,butlanguagessuchasC,Pascal,Ada,Java,andevenBASICprogrammingenvironmentscancreateanduseCOMobjects.以上摘自MSDN,重要的是C,Pascal,Ada,Java,andevenBASIC都可以用来编写COM。以上初步介绍了关于COM的一些东西,不多也很浅,理解以上的部分就够花费很长一段时间的了,如果真地对COM感兴趣的话,最好有一定的基础,包括:数据结构,面向对象的程序设计,Windows编程等,不过也不一定都学,只是这些会对你学习COM并在短时间内掌握并深入理解COM会有相当的好处。COM学习笔记(二)CoCreateInstance具体内部实现[cpp]viewplaincopy1.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.}这段话的意思就是先得到类厂对象,再通过类厂创建组件从而得到IUnknown指针。继续深入一步,看看CoGetClassObject的内部伪码:[cpp]viewplaincopy1.CoGetClassObject(.....)2.{3.//通过查注册表CLSID_Object,得知组件DLL的位置、文件名4.//装入DLL库5.//使用函数GetProcAddress(...)得到DLL库中函数DllGetClassObject的函数指针。6.//调用DllGetClassObject7.}8.///DllGetClassObject是干什么的,它是用来获得类厂对象的。只有先得到类厂才能去创建组件.9.///下面是DllGetClassObject的伪码:10.DllGetClassObject(...)11.{12.//......13.CFactory*pFactory=newCFactory;//类厂对象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*pObject=newCObject;//组件对象24.pObject-QueryInterface(IID_IUnknown,(void**)&pUnk);25.pObject-Release();26.//...........27.}这部分我们将构造一个创建COM组件的最小框架结构,然后看一看其内部处理流程是怎样的[cpp]viewplaincopy1.IUnknown*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]viewplaincopy1.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组件的框架,不过我的兴趣在CoCreateInstance身上,让我们来看看它内部做了一些什么事情。以下是它内部实现的一个伪代码:[cpp]viewplain
本文标题:COM学习笔记+++
链接地址:https://www.777doc.com/doc-2906770 .html