请高手讲讲COM! 我看了com的书,还是不明白是怎么回事,请高手用精炼的语言给我讲讲!在下不胜感激. 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 1.windows对象。2.对象通过接口表现,一个对象可以支持多个接口,每个对象必须提供IUNKNOWN接口,实现QueryInterface,AddRef,Release方法。接口的查询必须满足传递性,对称性,自反性。3.对象重用,通过包含或者聚集实现。对象聚集的关键在于提供IUNKNOWN指针给内部对象,使之获得对外部对象的认识。4.通过对象服务器,实现对象的访问,DLL服务器存在于客户进程中;而EXE服务器通过LRPC与客户通讯,在LRPC边界上通过marshal机制打包请求和响应。 COM简介现在很多地方都能听到COM这个词,那么,什么是COM?简而言之,COM,即"组件",是一种"二进制标准--一种应用于已经编译为机器码的可执行文件的标准"。为了更清楚的了解到底COM是什么样的,我们先来看看为什么需要COM--COM的产生正是由对它的需求决定的。 在程序开发技术上,编写代码的方式由最早的面向过程, 到现在的面向对象;相映的,代码重用的方式也由从最早的源代码级重用,到库(LIB)和动态链接库等二进制(机器码)等级的重用。但是,这时的代码重用方式却不能与编程技术相协调。面相对象的编程技术要求能够重用一个对象,而不仅仅是一个函数。这个要求在源代码级可以很容易的实现,在那时现有的二进制级确无法很好的做到这点。 我们知道,要从库或动态链接库中导出一个函数,需要一个格式声明,在C中就是头文件在VB中需要键入到源代码中。但是,这个格式声明是在源代码级的,它不能保证当程序编译为可执行代码后还能正常工作。原因在于,不同的语言、不同的编译器,对同一个(或等效的)源代码级的定义,有其各自不同的实现方式。当用一个编译器编写一个程序,这个程序使用由另一个编译器编译的库中的对象时,前者会假设这个库是按照自己标准实现的,即,由给定的对象的地址,该编译器按照自己的方式在二进制数据中定位其成员变量和成员函数的位置。两种编译器的定位方式可能是不同的,而二进制数据不能描述自己是如何组织的,这就产生了混乱。当然,不会有人愿意因此而放弃二进制等级的代码重用,二进制等级的重用有很多优势,在这里我并不想赘述。此时,显然,关键就是需要一个可执行代码级的标准,由它来规定,一个编译器应该以何种二进制格式来组织导出它的对象,以及如何在其他编译器导出的对象的二进制数据中进行定位。COM便应运而生了。COM使得不同的语言不同的编译器产生的对象能够互操作。以下文字摘自MSDN:COM要求用来编写组件的语言必须具备建立指针结构和通过指针来调用函数的能力,无论它是显示的实现(C/C++)还是暗含的(VB)。一般来说,一个对象是由一组数据以及操作这些数据的函数组成的。COM对象要求所有访问必须通过一组或几组相关的函数来完成,这些函数组被称为界面(interface),在界面中的函数被称为方法(method)。此外,COM要求对方法的访问权只能通过一个指向该界面的指针来获得。除了制定基本的二进制对象标准,定义了几个基本的接口来为所有基于COM的技术提供常用的功能,并且提供了几个所有组件都需要的API函数。COM还定义了对象应如何在一个分布的环境中协同工作,并且增加了安全特性以保证系统和组件的完整性。COM技术使对象跨越进程和机器边界进行互操作像在单个进程中一样容易。将对变量的访问统一到对函数的访问中,COM定义了界面这个概念,一个界面本质上是一个函数入口地址的列表。可以想象,界面将对象的定义从对象的实现中剥离出来,而这个定义却是二进制的,它可以为对象在二进制级别上描述自己,而对象自己却从不真正露面,因为它经常不能被正常识别。界面是一个很简洁的结构,各个语言都可以实现,COM通过它实现语言无关性。同时,它还具备很好的弹性,使得对实现的更改不必导致界面的变动;在同一个实现上可以有多个界面而互不干扰;在界面与其对象之间插入一些通讯机制,可以将实际的对象放在其他进程甚至远程计算机中,本进程只保留界面,而使用不会受到影响。由此可见,对用户来说,其所见的只是界面,当它使用这个对象时,也会"实例化"某个界面,因而,界面需要一个标识,以便用户"实例化"。COM是为广泛的代码重用而设计的,从其表现来看,就好像任何人(只要经过最终用户同意)都可以向系统中添加API一样。因此,界面的命名便成为问题,为了解决重名的问题,COM使用GUID注来标识一个界面,当GUID表示一个界面时,它也叫做IID。(当然COM也提供被称为ProgID的标识,但不保证它的唯一性。)对象虽然使用界面,但仍然离不开其实现--对象本身,数据是对象的组成之一,对象需要内存空间来保存数据。但是,应当记得,对象向用户隐瞒了自己的实现,用户只知道对象的界面,却不知道它本身需要多少内存空间。对象可以随时(随新版本发布)改变自己的实现(当然保持界面不变),对用户来说,这就使得对象的尺寸难以琢磨,导致用户无法分配合适的空间给对象。因此,需要一个知道对象实际尺寸的对象来创建这个对象。任何对象的实现(coclass)都必须存在于某个可执行文件(通常是动态链接库)中,这个可执行文件通常被成为Server。Server当然知道它内部的对象的实际尺寸,由它来创建对象是最好不过的了,COM定义了一个基本的界面:IClassFactory用来将Server描述成一个对象,由它来实现对象的建立。IClassFactory有两个方法:CreateInstance()用来创建一个对象,LockServer()用来锁定Server以免其被卸载。初始的IClassFactory由一个标准的接口取得。对象最终还是要被销毁的,但是什么时候才能安全的销毁一个对象又成为问题。对一个已经存在的对象而言,可能存在它的多个正在使用的界面,可能有远程的用户正在使用它,这使得任何用户都不能随意的销毁一个对象--可能别的用户还在使用。那么,就需要某种机制来记录到底有多少用户在使用一个对象。以下文字摘自MSDN:一种可以保证对象已经不在被使用的方法是完全依赖于到对象的通讯机制,当所有到对象的通讯连接都断开后,由它来通知系统销毁对象。但是,有很多原因使得这种方法不能被接受。一个问题是,它将导致在跨进程/跨网络模型和单进程模型中编程产生很大的差异。在跨进程/跨网络模型中,通讯系统要提供必需的挂钩来管理对象的生存期,而在单进程模型中,到对象的连接是直接的,没有任何中间的通讯机制(译者:当然就无人来管理对象的生存期)。另一个问是,这可能导致存在一个系统提供的软件层,它可能对在单进程情况下的对象的性能产生不利的影响。而且,基于精确监控的机制不大可能被扩展到能够监控成千上万的对象。所以,最终的选择就是--由对象自己来管理自己的生存期,当它发现所有到自己的连接断开后,就销毁自己。对象检测到自己的连接的最好方式就是记录正在使用的界面--用户只能通过界面来访问对象,如果所有的界面都不存在了,当然就不会有人再使用这个对象了。COM记录界面使用情况的方法是使用一个被成为"引用计数器"的变量,这个变量位于对象内部,而且是可以通过任何一个属于该对象的界面访问的。当用户得到这个界面时,将计数器加一;当不再继续使用时,将计数器减一。这是用户的职责,就好像它们必须分配和释放内存空间一样。当计数器变为零后,便意味着所有的界面都已经消失了,此时对象可以安全的销毁自己。这种机制在每个界面中加入了两个方法:AddRef()和Release(),用来操作计数器。既然一个对象可能有多个界面,各个界面之间就应当有某种机制,使得通过一个界面可以得到另一个界面,即,可以航行于同一对象的各个界面之间。这就需要在对象内部记录每个界面的IID和其界面,用户通过任何属于该对象的界面都可以访问该记录,从而获得它们想要的界面。(应当注意,经这种方法得到的界面不必增量引用计数器,该方法已经自动做了这个操作,界面是带着一个引用计数被传递到用户的--否则对象可能在界面传递到用户之前就被销毁。从IClassFactory获得界面时与此属同一情况。但当不再使用该界面时仍然需要减少引用计数器。)这种机制在每个界面中加入了一个方法:QueryInterface(),用来查询需要的界面。这三个每个界面都必须具备的方法被定义为一个基本的界面IUnknown,所有其他的界面都必须衍生自IUnknown,IClassFactory也不例外。注:GUID是Global Unique Identifier(世界唯一标识),它是一个128bit值,所有可能的值是一个相当庞大的数字,可以保证所标识的对象的唯一性。 COM就是接口就是C++中的纯虚基类就是函数的内存地址 在我看来com是一种技术,通过它的实现细则,实现了一个程序的零件化。而每一个零件提供了对零件操作的接口。 http://www.gdsoftpark.com/chs/TechCenter/Articles/Catalog/showpage.asp?PageID=540http://www.gdsoftpark.com/chs/TechCenter/Articles/Catalog/showpage.asp?PageID=541 MoveFileEx驱动文件 clistctrl问题 请问WEBBROWSER中如何判断 网页打开完整了? 关于FTP服务器 分贼多,散散,顺便问个小问题,如何让一个非活动、非TOPMOST窗口,处于一个特定的活动窗口的上边? 对于import进来的ocx组件, 我可以从它继承出一个类吗? 关于印章识别 crazy_lazy_pig请进 有关iPlanet Directory Server编程的问题 为什么消息映射要用宏而不是虚函数?之二 十万个为什么? ▉▉▉win98机器接宽带上网,有时能连上网,有时连不上,网络不通。真是怪了。 高手请进,如何得到命名管道的局域网实现?
2.对象通过接口表现,一个对象可以支持多个接口,每个对象必须提供IUNKNOWN接口,实现QueryInterface,AddRef,Release方法。接口的查询必须满足传递性,对称性,自反性。
3.对象重用,通过包含或者聚集实现。对象聚集的关键在于提供IUNKNOWN指针给内部对象,使之获得对外部对象的认识。
4.通过对象服务器,实现对象的访问,DLL服务器存在于客户进程中;而EXE服务器通过LRPC与客户通讯,在LRPC边界上通过marshal机制打包请求和响应。
现在很多地方都能听到COM这个词,那么,什么是COM?简而言之,COM,即"组件",
是一种"二进制标准--一种应用于已经编译为机器码的可执行文件的标准"。为了更清楚的了
解到底COM是什么样的,我们先来看看为什么需要COM--COM的产生正是由对它的需求决定
的。 在程序开发技术上,编写代码的方式由最早的面向过程, 到现在的面向对象;相映的,
代码重用的方式也由从最早的源代码级重用,到库(LIB)和动态链接库等二进制(机器码)
等级的重用。但是,这时的代码重用方式却不能与编程技术相协调。面相对象的编程技术要求能够重
用一个对象,而不仅仅是一个函数。这个要求在源代码级可以很容易的实现,在那时现有的
二进制级确无法很好的做到这点。 我们知道,要从库或动态链接库中导出一个函数,需要一个格式声明,在C中就是头文件
在VB中需要键入到源代码中。但是,这个格式声明是在源代码级的,它不能保证当程序编译
为可执行代码后还能正常工作。原因在于,不同的语言、不同的编译器,对同一个(或等效
的)源代码级的定义,有其各自不同的实现方式。当用一个编译器编写一个程序,这个程序使用由另一个编译器编译的库中的对象时,前
者会假设这个库是按照自己标准实现的,即,由给定的对象的地址,该编译器按照自己的方
式在二进制数据中定位其成员变量和成员函数的位置。两种编译器的定位方式可能是不同的,
而二进制数据不能描述自己是如何组织的,这就产生了混乱。当然,不会有人愿意因此而放弃二进制等级的代码重用,二进制等级的重用有很多优势,
在这里我并不想赘述。此时,显然,关键就是需要一个可执行代码级的标准,由它来规定,一个编译器应该以
何种二进制格式来组织导出它的对象,以及如何在其他编译器导出的对象的二进制数据中进
行定位。COM便应运而生了。COM使得不同的语言不同的编译器产生的对象能够互操作。以下文字摘自MSDN:
COM要求用来编写组件的语言必须具备建立指针结构和通过指针来调用函数的能力,无
论它是显示的实现(C/C++)还是暗含的(VB)。
一般来说,一个对象是由一组数据以及操作这些数据的函数组成的。COM对象要求所有
访问必须通过一组或几组相关的函数来完成,这些函数组被称为界面(interface),在界面
中的函数被称为方法(method)。此外,COM要求对方法的访问权只能通过一个指向该界面
的指针来获得。
除了制定基本的二进制对象标准,定义了几个基本的接口来为所有基于COM的技术提供
常用的功能,并且提供了几个所有组件都需要的API函数。COM还定义了对象应如何在一个分
布的环境中协同工作,并且增加了安全特性以保证系统和组件的完整性。
COM技术使对象跨越进程和机器边界进行互操作像在单个进程中一样容易。将对变量的访问统一到对函数的访问中,COM定义了界面这个概念,一个界面本质上是
一个函数入口地址的列表。可以想象,界面将对象的定义从对象的实现中剥离出来,而这个
定义却是二进制的,它可以为对象在二进制级别上描述自己,而对象自己却从不真正露面,
因为它经常不能被正常识别。
界面是一个很简洁的结构,各个语言都可以实现,COM通过它实现语言无关性。同时,
它还具备很好的弹性,使得对实现的更改不必导致界面的变动;在同一个实现上可以有多个
界面而互不干扰;在界面与其对象之间插入一些通讯机制,可以将实际的对象放在其他进程
甚至远程计算机中,本进程只保留界面,而使用不会受到影响。由此可见,对用户来说,其所见的只是界面,当它使用这个对象时,也会"实例化"某个
界面,因而,界面需要一个标识,以便用户"实例化"。COM是为广泛的代码重用而设计的,
从其表现来看,就好像任何人(只要经过最终用户同意)都可以向系统中添加API一样。因
此,界面的命名便成为问题,为了解决重名的问题,COM使用GUID注来标识一个界面,当
GUID表示一个界面时,它也叫做IID。(当然COM也提供被称为ProgID的标识,但不保证它
的唯一性。)对象虽然使用界面,但仍然离不开其实现--对象本身,数据是对象的组成之一,对象需
要内存空间来保存数据。但是,应当记得,对象向用户隐瞒了自己的实现,用户只知道对象
的界面,却不知道它本身需要多少内存空间。对象可以随时(随新版本发布)改变自己的实
现(当然保持界面不变),对用户来说,这就使得对象的尺寸难以琢磨,导致用户无法分配
合适的空间给对象。因此,需要一个知道对象实际尺寸的对象来创建这个对象。
任何对象的实现(coclass)都必须存在于某个可执行文件(通常是动态链接库)中,
这个可执行文件通常被成为Server。Server当然知道它内部的对象的实际尺寸,由它来创建
对象是最好不过的了,COM定义了一个基本的界面:IClassFactory用来将Server描述成一个
对象,由它来实现对象的建立。IClassFactory有两个方法:CreateInstance()用来创建一个
对象,LockServer()用来锁定Server以免其被卸载。初始的IClassFactory由一个标准的接口
取得。对象最终还是要被销毁的,但是什么时候才能安全的销毁一个对象又成为问题。对一个
已经存在的对象而言,可能存在它的多个正在使用的界面,可能有远程的用户正在使用它,
这使得任何用户都不能随意的销毁一个对象--可能别的用户还在使用。那么,就需要某种机
制来记录到底有多少用户在使用一个对象。以下文字摘自MSDN:
一种可以保证对象已经不在被使用的方法是完全依赖于到对象的通讯机制,当所有到对
象的通讯连接都断开后,由它来通知系统销毁对象。但是,有很多原因使得这种方法不能被
接受。一个问题是,它将导致在跨进程/跨网络模型和单进程模型中编程产生很大的差异。
在跨进程/跨网络模型中,通讯系统要提供必需的挂钩来管理对象的生存期,而在单进程模
型中,到对象的连接是直接的,没有任何中间的通讯机制(译者:当然就无人来管理对象的
生存期)。另一个问是,这可能导致存在一个系统提供的软件层,它可能对在单进程情况下
的对象的性能产生不利的影响。而且,基于精确监控的机制不大可能被扩展到能够监控成千
上万的对象。所以,最终的选择就是--由对象自己来管理自己的生存期,当它发现所有到自己的连接
断开后,就销毁自己。对象检测到自己的连接的最好方式就是记录正在使用的界面--用户只
能通过界面来访问对象,如果所有的界面都不存在了,当然就不会有人再使用这个对象了。
COM记录界面使用情况的方法是使用一个被成为"引用计数器"的变量,这个变量位于对象内
部,而且是可以通过任何一个属于该对象的界面访问的。当用户得到这个界面时,将计数器
加一;当不再继续使用时,将计数器减一。这是用户的职责,就好像它们必须分配和释放内
存空间一样。当计数器变为零后,便意味着所有的界面都已经消失了,此时对象可以安全的
销毁自己。
这种机制在每个界面中加入了两个方法:AddRef()和Release(),用来操作计数器。既然一个对象可能有多个界面,各个界面之间就应当有某种机制,使得通过一个界面可
以得到另一个界面,即,可以航行于同一对象的各个界面之间。这就需要在对象内部记录每
个界面的IID和其界面,用户通过任何属于该对象的界面都可以访问该记录,从而获得它们想
要的界面。(应当注意,经这种方法得到的界面不必增量引用计数器,该方法已经自动做了
这个操作,界面是带着一个引用计数被传递到用户的--否则对象可能在界面传递到用户之前
就被销毁。从IClassFactory获得界面时与此属同一情况。但当不再使用该界面时仍然需要减
少引用计数器。)
这种机制在每个界面中加入了一个方法:QueryInterface(),用来查询需要的界面。这三个每个界面都必须具备的方法被定义为一个基本的界面IUnknown,所有其他的界面都必须衍生自IUnknown,IClassFactory也不例外。注:GUID是Global Unique Identifier(世界唯一标识),它是一个128bit值,所有可能的值是
一个相当庞大的数字,可以保证所标识的对象的唯一性。
http://www.gdsoftpark.com/chs/TechCenter/Articles/Catalog/showpage.asp?PageID=541