组件对象模型_第1页
组件对象模型_第2页
组件对象模型_第3页
组件对象模型_第4页
组件对象模型_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

组件对象模型控件和组件是什么一般把Control翻译成控件,把Component翻译成组件。控件就是具有用户界面的组件。要说的具体一点,就得回顾早期 Windows 的历史根源,当时控件指任何子窗口按钮、列表框、编辑框或者某个对话框中的静态文本。从概念上讲,这些窗口控件类似用来操作收音机或小电器的旋钮和按钮。随着控件数量的增加(组合框、日期时间控件等等),控件逐渐成为子窗口的代名词,无论是用在对话框中还是用在其它种类的主窗口中。没过多久 BASIC 程序员开始编写他们自己专用的控件,自然而然地人们便想到共享这些控件。共享代码的方法之一是通过磁盘拷贝,但那样显然效率低下。必须要有一种机制使开发者建立的控件能够在其它程序员的应用中轻而易举地插入,这便是VBA控件,OLE控件,OCX和最后ActiveX 控件的动机。 这就是控件和组件之间产生混淆之所在。因为为了解决控件的可复用问题,所有这些技术必须首先解决更为一般的组件重用问题。(COM,如果你还记得它的话,意思是组件对象模型)。在软件行话中,组件这个术语指任何可复用的对象或任何可与其它对象交互的代码体。子程序的发明,曾经一度成为程序员趋之若鹜的软件工程圣杯:一种统一的编程理论,它使程序员从基本构建块也就是用所选语言编写的各种组件建立大型系统。从子程序演变到OOP,到DLLs,再到COM,再到.NET框架的每一种新的编程范例都代表了一种不同的提供可重用性的方案。VBX使用DLLs的固化名称。COM使用接口和IUnknown。.NET框架使用微软的中间语言(MSIL)层和公共语言运行时(CLR)来提供统一的粘合。 因此,控件是组件的一个主要样本(并且历史上曾驱动着组件的开发),控件又不仅仅是唯一的一种组件。组件不需要显示任何信息或用户界面。组件可能实现科学计算,收集性能数据。规则1:必须实现Iunknown IUnKnown接口的定义: IUnKnown是一个接口。 所有COM接口都继承IUnKnown。IUnKnown的定义在WIN32 SDK中的UNKNWN头文件中。深入:COM组件其实是一种特殊的类,遵循一个统一的标准,使到各个软件都可以通过某种方法访问这个类的函数和方法,也就可以做到组件通用. com就是统一的标准-通过接口来调用com组件.接口是你的com组件能被外界所感知的部分,实际就是一组方法(虚函数). IUnknown是所有接口的基础,他负责两项工作:IUnknown:QueryInterface负责得到该组件的其他接口的指针IUnknown:AddRef/Release负责管理该组件的生存期,但有人使用该组件时,保证该组件不会被意外删除;再没人使用该组件时,保证该组件被自动删除 COM是组件对象模型,她是继面象对向之后的一种思想,而不是一种简单的实现。 通过IDL,很多具体的工作都可以实现她,如VC、VB等。 一句话:COM是接口(组件)的集合,接口是方法和属性的集合。 要了解COM,就得先了解IUnknown接口,IUnknown接口的C+形式的定义如下: interface IUnknown virtual HRESULT _stdcall QueryInterface(inREFIID iid,outvoid * * ppv)=0; virtual ULONG _stdcall AddRef(void)=0; virtual ULONG _stdcall Release(void)=0; 她实现了“接口查询”和“引用计数”,她是一个纯抽象基类。所有COM 定义的接口都必须从她继承。实现的COM接口都应该遵守一定的原则: 1。查询IUnknown接口得到的必须一样。 2。接口对称性。 3。接口相互性。 4。接口传递性。 5。时间无关性。要学好COM,一定得弄清楚COM的原理。如果你学过C+或类似语言的话,这就比较好理解了。在C+里,一个子类可以从父类继承,这样子类可以复用父类的函数和成员。在COM里,一个接口和一个类很相似,一个接口可以从另一个接口继承,但是与C+的区别 是,接口的继承只是继承说明,不继承实现。微软规定了所有的标准接口必须从IUnknown接口“继承”,以获得组件的两个基本能力:引用计数和查询接口。一个Free的域名:http:/ComD,现在放了一位老外写的学习心得。IUnknown接口是一个很普通的类或结构,你甚至可以自己写他,只是他有特殊的规定,必须有QueryInterface,AddRef,Relaese方法。可以说他是所有COM类的基类。原始的IUnknown类是一个纯虚类,什么也不能干,用户必须重载并实现他的所有方法,之所以要用IUnknown虚拟类,只是为了接口统一。也就是说所有COM类这三个方法的地址在函数虚拟表中是完全一样的。COM中的接口和C+中的类有些是相同的,但是也有一些区别,在COM中有一些接口他里面有些函数是微软在出厂时就已经编写好了的,但是,他也提供了一些多余的接口,他只做了定义,但是没有实例化,你可以利用VC编写程序了将他实例化,就可以实现自己要求的功能了,但是你也要编写一个注册程序,至于如何编写要看你利用的接口而定了。有一套教程,非常好,有生动的例子和循序渐进的说明。最终的结论是,要在Windows平台上实现组件(可独立发布的程序单元)应该是COM现在这种形式。URL为:/com/contents.asp比较适合于初学者,只需C+的基础,学起来也比较轻松。学完之后,比看任何一本关于COM的书都要理解得好。如果一个对象没有至少实现一个最小程度为IUnknown的接口,那它就不是Microsoft的组件对象模型(COM)。 接口设计规则 接口必须直接或间接地从IUnknown继承。 接口必须有唯一的识别(IID)。 接口是不变的。一旦分配和公布了IID,接口定义的任何因素都不能被改变。 接口的成员函数应该有HRESULT类型的返回值,使远端结构可报告远程过程调用(RPC)错误的情况。 接口成员函数的字符串参数应该是Unicode。 实现 IUnknown 对象的同一性。这要求对任何特定IUnknown接口的给定对象实例的QueryInterface调用返回相同的物理指针变量。这导致了所谓的两个接口的QueryInterface(IID_IUnknown, .)和结果的比较,以确定它们是否为同一对象(COM对象同一性)。 静态接口的设置。任何经由QueryInterface来访问对象的接口的设置,必须是静态而不是动态的。也就是说,假如一旦QueryInterface获得了一个给定的IID,那么它总是对相同的对象(除非有意想不到情况)调用,假如QueryInterface不能获得一个给定的IID,那么随后对相同IID的对象调用必定会失败。 对象完整性。对于可处理的接口设置,必须有反身性,对称性和过渡性。即给定代码如下: IA * pA = (some function returning an IA*); IB * pB = NULL; HRESULT hr; hr = pA-QueryInterface(IID_IB,&pB); / line 4 Symmetric: pA-QueryInterface(IID_IA, .) must succeed (aa) Reflexive: If, in line 4, pB was successfully obtained, then pB-QueryInterface(IID_IA, .) must succeed (ab, then ba);Transitive: If, in line 4, pB was successfully obtained, and we do IC * pC = NULL; hr = pB-QueryInterface(IID_IC, &pC); /Line 7 and pC is successfully obtained in line 7,then pA-QueryInterface(IID_IC, .) must succeed (ab, and bc,then ac). 最小参考服务大小。我们需要实现AddRef来维护一个服务台,它足够大以便支持给定对象的所有接口的2 31 1有出色的整体指示服务。一个32-位的无符号整型数满足要求。 Release并不意味着失败。假如客户想知道关于资源已被释放等情况,就必须在调用Release之前使用一些对象接口中的较高的语义。 内存管理规则 接口指针的生命期管理总是通过建立在每个COM接口上的AddRef和Release方法来实现。(参见下面的“引用计数规则”) 下面的规则适用于接口成员函数的参数,包括不是“按值”传递的返回值。 对于参数来说,调用程序应分配和释放内存。 出口参数必须由被调用程序分配,由调用程序用标准的COM内存分配程序来释放。 出入参数首先由调用程序分配,必要时由被调用程序释放及重分配。至于出口参数,调用程序有责任释放最终返回变量。此时必须使用标准的COM内存分配程序。假如函数返回调用失败的代码,则通常调用者没办法清除出口和入出口参数。这导致了一些附加规则: 错误返回时,出口参数必须可靠地被设置成可清除变量,它不能对调用程序有影响。 此外,所有的出口指针参数(包括调用分配,被调用委任结构)必须被明显地设为NULL。最直接的方法是在函数说明项中设成NULL。 返回错误时,所有的入出口参数必须为被调用者所搁置(这样保持为调用程序初始化的值;若调用程序没有对它初始化,则它是个出口参数,不是入出口参数),或者被明显地设为出口错误返回情况。 参考计数规则: 规则1:对于接口指针的每一个新的副本,AddRef必须被调用;Release在接口指针的每一个破坏时调用,除了子规则明显允许了其他情况。 以下规则对应于规则1的非例外情况。 规则1a:函数的入口出口参数。调用程序必须AddRef实际参数,因为当出口变量存放在它之上时,将由被调程序释放。 规则1b:获取全局变量。从全局变量的已存在的指针副本得到的接口指针的局部副本,必须被独立地引用计数。因为存在局部副本时,被调函数会破坏全局副本。 规则1c:新指针合成所需资源不多。函数使用内在知识合成接口指针,而不是从其他资源所得,此时必须对新指针做初始AddRef。这样的重要例子有事例生成法则,Iunknown:QueryInterface的实现,等等。 规则1d:内部存储指针副本的返回。指针返回之后,被调程序不知道它的生命期和指针的内部存储副本如何联系。所以,被调程序必须在返回前对指针副本调用AddRef。 规则2:对于接口指针的两个或更多的副本,它们的生命期的起始和终了的关系代码的特定知识,使AddRef/Release可以被省略。 从COM客户的角度,引用计数是和接口对应的概念。客户不应认为对象的所有接口有同一引用计数。 不应依赖于Addref & Release的返回值,而应用于调试目的。 指针稳定性;参见在Reference-Counting Rules下的OLE帮助文件中的子部分:Stabilizing the this Pointer and Keeping it Valid。 COM申请责任: 以客户,服务器,对象执行者之一身份使用COM的每一进程,要对三件事负责: 确定COM库是同COM函数CoBuildVersion一致的版本。 在使用其他函数之前通过调用CoInitialize初始化COM库。 在不用CoUninitialize时取消COM库的初始化。 进程内服务器能假定载入的进程已执行了这些步骤。 服务器规则 进程内服务器必须输出DllGetClassObject and DllCanUnloadNow。 进程内服务器必须支持COM自注册。 进程内和局部服务器应该在它们的文件版本信息中提供OLESelfReg字符串。 进程内服务器必须输出DllRegisterServer and DllUnRegisterServer。 局部服务器应支持/RegServer and /UnRegServer命令行开关。 生成集合对象 生成可合计的对象是可选的,且操作简单,有诸多益处。以下规则使用于创建可合计的对象(通常称为内部对象)。 由QueryInterface, AddRef, 和 Release对IUnknown接口的内部对象执行单独控制内部接口的引用计数,且不能授权给外部未知指针。这种IUnknown执行称为隐式IUnknown。 内部对象执行接口的QueryInterface, AddRef, 和 Release成员的实行,除了IUnknown自己,都必须授权给外部未知指针。这些实施不能直接影响内部对象的参考计数。 隐式Iunknown只对内部对象实施QueryInterface操作。 集合对象在占用外部未知指针参考时,不能调用AddRef。 如果当对象创建时,需要除Iunknown外的任一接口,创建失败同E_UBKNOWN一起。 以下的代码段阐明了使用嵌套类来实现集合对象接口的范例: / CSomeObject is an aggregatable object that implements / IUnknown and ISomeInterface class CSomeObject : public IUnknown private: DWORD m_cRef;/ Object reference count IUnknown* m_pUnkOuter; /Outer unknown, no AddRef / Nested class to implement the ISomeInterface interface class CImpSomeInterface: public ISomeInterface friend class CSomeObject ; private: private:DWORD m_cRef; /Interface ref-count, for debugging private:IUnknown*m_pUnkOuter; / Outerunknown, for delegation private:public: private:CImpSomeInterface() m_cRef = 0; ; private: CImpSomeInterface(void) ; private:/ IUnknown members delegate to the outer unknown private:/ IUnknown members do not control lifetime of object private:STDMETHODIMP QueryInterface(REFIID riid, void* ppv) private: return m_pUnkOuter-QueryInterface(riid,ppv); private:STDMETHODIMP_(DWORD) AddRef(void) private: return m_pUnkOuter-AddRef(); ; private:STDMETHODIMP_(DWORD) Release(void) private: return m_pUnkOuter-Release(); private:/ ISomeInterface members private:STDMETHODIMP SomeMethod(void) private: return S_OK; ; private: ; private:CImpSomeInterface m_ImpSomeInterface ; private:public: private:CSomeObject(IUnknown * pUnkOuter) m_cRef=0; / No AddRef necessary if non-NULL as were aggregated. m_pUnkOuter=pUnkOuter; m_ImpSomeInterface.m_pUnkOuter=pUnkOuter; ; / Static member function for creating new instances (dont use / new directly).Protects against outer objects asking for interfaces / other than IUnknown static HRESULT Create(IUnknown* pUnkOuter, REFIID riid, void *ppv) CSomeObject* pObj; if (pUnkOuter != NULL & riid != IID_IUnknown) return CLASS_E_NOAGGREGATION; pObj = new CSomeObject(pUnkOuter); if (pObj = NULL) return E_OUTOFMEMORY; / Set up the right unknown for delegation (the non-aggregation case) if (pUnkOuter = NULL) pObj-m_pUnkOuter = (IUnknown*)pObj ; HRESULT hr; if (FAILED(hr = pObj-QueryInterface(riid, (void*)ppv) delete pObj ; return hr; / Implicit IUnknown members, non-delegating / Implicit QueryInterface only controls inner object STDMETHODIMP QueryInterface(REFIID riid, void* ppv) *ppv=NULL; if (riid = IID_IUnknown) *ppv=this; if (riid = IID_ISomeInterface) *ppv=&m_ImpSomeInterface; if (NULL=*ppv) return ResultFromScode(E_NOINTERFACE); (IUnknown*)*ppv)-AddRef(); return NOERROR; ; STDMETHODIMP_(DWORD)AddRef(void) return+m_cRef; ; STDMETHODIMP_(DWORD)Release(void) if (-m_cRef != 0) return m_cRef; delete this; return 0; ; ; 集合对象 当在一个对象上产生另一个集合对象时,必须遵循以下规则: 当创建一个内部对象时,外部对象必须明确的向Iunknown请求。 外部对象必须保护重入时对破坏代码的人工引用的Release实施。 如果外部对象查询任一

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论