组件对象模型

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

组件对象模型
控件和组件是什么
一样把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([in]REFIID iid,[out]v oid**ppv)=0;
virtual ULONG_stdcall AddRef(void)=0;
virtual ULONG_stdcall Release(void)=0;
}
她实现了“接口查询”和“引用计数”,她是一个纯抽象基类。

所有CO M概念的接口都必需从她继承。

实现的COM接口都应该遵守必然的原那么:
1。

查询IUnknown接口取得的必需一样。

2。

接口对称性。

3。

接口彼此性。

4。

接口传递性。

5。

时刻无关性。

要学好COM,必然得弄清楚COM的原理。

若是你学过C++或类似语言的话,这就比较好明白得了。

在C++里,一个子类能够从父类继承,如此子类能够复用父类的函数和成员。

在COM里,一个接口和一个类很相似,一个接口能够从另一个接口继承,可是与C++的区别是,接口的继承只是继承说明,不继承实现。

微软规定了所有的标准接口必需从IUnknown接口“继承”,以取得组件的两个大体能力:引用计数和查询接口。

一个Free的域名:,此刻放了一名老外写的学习心得。

IUnknown接口是一个很一般的类或结构,你乃至能够自己写他,只是他有特殊的规定,必需有QueryInterface,AddRef,Relaese方式。

能够说他是所有COM类的基类。

原始的IUnknown类是一个纯虚类,什么也不能干,用户必需重载并实现他的所有方式,之因此要用IUnknown虚拟类,只是为了接口统一。

也确实是说所有COM类这三个方式的地址在函数虚拟表中是完全一样的。

COM中的接口和C++中的类有些是相同的,可是也有一些区别,在COM中有一些接口他里面有些函数是微软在出厂时就已经编写好了的,可是,他也提供了一些多余的接口,他只做了概念,可是没有实例化,你能够利用VC编写程序了将他实例化,就能够够实现自己要求的功能了,可是你也要编写一个注册程序,至于如何编写要看你利用的接口而定了。

有一套教程,超级好,有生动的例子和循序渐进的说明。

最终的结论是,要在Windows平台上实现组件(可独立发布的程序单元)应该是COM此刻这种形式。

URL为:比较适合于初学者,只需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); .) must succeed (a>>a) Reflexive: If, in line 4, pB was successfully obtained, then
pB->QueryInterface(IID_IA, ...)
must succeed (a>>b, then b>>a);
Transitive: If, in line 4, pB was successfully obtained, and we do IC * pC = NULL;
hr = pB->QueryInterface(IID_IC, &pC); .)
must succeed (a>>b, and b>>c,then a>>c).
最小参考效劳大小。

咱们需要实现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一路。

以下的代码段说明了利用嵌套类来实现集合对象接口的范例:
m_pUnkOuter=pUnkOuter;
=pUnkOuter;
} ;
rotects against outer objects asking for interfaces。

相关文档
最新文档