目标平台与 com com组件注册的位元是否相同.例如,如果 com com组件注册为 32 位,目标平台就不能

动态链态库是大部分COM组件的承载对象(不要在意ocx,它同样也是dll,只不过改了一下后缀而已)。当然Exe同样也是可以的(TTS中的TextToSpeech对象就是一个例证),只不过在事实上要少得多。


在Windows初期,动态链态库的出现是一场革命。它改变了Windows的一生,也为当今Windows操作系统的霸主地位打下一块坚实的基石。(关于Windows的历史问题,我一直没有弄得太清楚。请VCKBASE的有关史学家们尽快写出一篇文章来吧^_^)。
微软对动态链接库就是这样解释的:
动态链接库 (DLL) 是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。
嗯,讲得很清楚。动态链接库首先是一个可执行文件(微软解释说,exe叫做起直接可执行文件),它里面包含着一组需要共享的函数。当使用时,动态链接库(和Windows系统)会提供一个方法来使我们的应用程序可以调用其中的函数。此外,动态链接库还会包含一些资源(如:图标、对话框模板等等)。在MFC中,微软在现有动态链接库的基础上施用了一些技巧来提供一些另外功能,如MFC类的导出。
动态链接库的链接方式大致分为两类: 静态链接和动态链接.

静态链接又叫隐式链接,这种链接方式使我们在代码中不用语句来指示系统中,我们的应用程序要加载哪些动态链接库。其静态链接声明是放在工程属性中的(或者使用#pragma comment(lib,"XXX.lib"),这个可以和#include放在一起)。在指定时,只需要输入其动态链接库相应的导入库文件(.lib)。然后,你就可以在程序的任何地方像调用普通函数一样调用该动态链接库中存在的函数了(当然,你需要包含其相应的头文件。一般情况下,头文件会和LIB文件一块给出)。通过这种方法生成的程序在运行初始化的时候(具体到什么时候不太清楚。但我可以肯定是在WinMain函数之前了^_^),会自动将动态链接库加载在系统环境中,并将其映射到我们应用程序的进程当中去。当我们调用一个我们进程没有定义的函数时,VC运行库会通过查找LIB文件的相关信息找到相应动态链接库的函数并调用它。进程结束时,系统会缷载动态链接库。


动态链接又叫显式链接,顾名思义这种方式让我们必需在代码通过调用API来显式地加载动态链接库。COM组件模型全部都是采用这种方式来加载进程内组件模块(就是Dll)的。(我觉得微软的专业术语有些混乱耶)。这个方式有许多好处,它可以在运行时决定具体要加载哪个链接库,要调用哪个函数…这才叫动态链接呢。
要使用动态链接库并不难,首先要调用LoadLibrary,其原型如下:
 
 
 
二、面向对象的组件模型-COMWindows系统霸主地位诂计三四年内是不会被动摇的。因此,有n多Windows开发平台出现在我们面前。n多种开发语言是百花齐放啊。于是,我们像圣经里说的那样,操着不同的语言,彼此无法沟通。为改变这一现实,可爱的比尔就站出来了,”偶要改变世界!”。微软公司制定一个基于二进制通用接口规范-Component Object Model(组件对象模型)。但是,一开始COM的解决目标并非是为了通用接口,而是应用于复合文档(OLE)的实现。而今由于语言无关性、进程透明性、可重用性、保密性(除非高手高手高高手,有谁能从汇编码中看出实现技术来)、而且编写并不困难,所以发展成为了一项应用广泛的技术。
1) 组件对象与接口组件对象、接口是COM的根基。
下面,请允许我用C++对象做一个类比。
组件对象与C++对象的意义是基本相同的。它是一个功能、属性与逻辑的整体。它是一个实体对象,通过对它的接口操作,可以使用它所提供的功能。
接口相当于C++对象中的public成员。它被暴露给外部使用者,使用者只被允许调用这些被暴露在外面的接口来使用对象的功能。与public成员有所不同的是,接口不是一个变量也不是一个函数,而应该是一组函数。在逻辑上,这个组函数应该是功能相关的。一个组件对象可以拥有许多个接口。
我只知道C++的COM实现方法,至于Dephi我就一无所知。
C++实现方法是:由C++类对象来完成组件对象的实现,由C++纯虚类来代表接口。C++类对象通过多重继承多个接口,来的拥有多个接口。
下面,我举一个例子,来说明C++中的组件对象与接口的关系(下面的例子并不是一个COM实现,只是用来表示组件对象与接口的关系)
我如果要做一个人的组件对象的话,我首先要定义一些接口来表示人的外部表现行为。
 
 
2) 标识符(GUID)上面,我说过COM组件是基于二进制的。那么要我们使用签名(比如说类名、接口名)来指定一个组件显然是不理想的了(至少在识别方面会有些麻烦)。那么,既然是二进制系统最方便当然就是使用数字标识了。于是,微软定义了这么一个结构标准:
          
          这个标识符代表着一个COM对象,这是因为一个COM对象的标识符名都以CLISID_为前缀。接口名则是以IID_为前缀。不要问我,标识符定义与对象具体有什么关系式。我不知道。它们根本就没有什么关系的。一个COM对象在编写时,我们会使用随机的方法来确定它的标识符(这个工作可以由VC来帮我们搞定)。一旦COM对象得到一个标识符并发布出去的话,那么就不能更改了。另外,不要担心GUID会有所冲突。如果你的高中数学已经及格了的话,那么请算一算128位二进制中,重复的概率会有多少。假如你真的发现了GUID有冲突的话(你要保证这不是人为),建议你赶去买彩票吧。你离500万不远了。
 
3) IUnknown接口COM模式所有接口必须遵守一定规范,这就是IUnknown接口的出处。每个一接口都必须从这个接口继承。在C++中,微软已经为我们把IUnknown定义好了:
          
          
          
注:void *可以指向任何对象。我开始的时候对void*一点都不理解。这里使用的原因是传出与传入指针类型不确定。
QueryInterface函数功能是当我们得到一个接口指针,并且我们想得到另一个接口指针的时候,提供帮助。我们将我们想要得到的接口的标识符传给iid,将把指针的做一个次&来传给ppv。如果QueryInterface成功的话,会返回S_OK。我们指针中就会指向我们想要的接口。
AddRef,Release用于实现引用计数机制。
在二进制系统中,组件对象不像C++环境中对象那样具有明确的生存期。可能会出现这种情况,两个(或者两个以上)的地方(可能是不同的程序之间,也可能是不同的线程之间)同时使用着一个组件对象,如果其中一个地方delete掉了组件对象的话。其它地方不可能会知道,当它们尝试调用这个象的话,轻则导致重伤,重则导致死亡。这不是我们希望看到的。于是,COM模型设制一个引用计数机制。
当一个地方开始使用对象的时候,它必须调用AddRef()一次。当我们使用QueryInterface时候,QueryInterface必须为我们调用一次AddRef()。AddRef()会使组件对象的引用计数增1。当这个地方不再使用对象时,它必须调用Release()一次。Release()会使组件对象的引用计数减1。当组件对象的引用计数变成0,就表明没有人再去使用组件对象了。这时,组件对象应该结束自己的生命。这样,就保证了组件对象生存期间其它程序的安全。
当然,你可以使用自己的引用机制,只要你的行为上支持AddRef和Release。比如说,不设置对象的引用计数,而是为每个接口设置一个引用计数。当所有的接口引用计数都为0时,delete对象。
好了,前面的示例中,我并没有遵守IUknown规范,下面我要遵守它。我把上次同样东西用……省略掉了。
          
 
          
 
请伃细,观察上面的描述IDL代码和图形。并不是太难吧。
4) COM对象的接口原则
为了规范COM的接口机制,微软向COM开发者发布了COM对象的接口原则。
(1)IUnknown接口的等价性
当我们要等到两个接口指针,我如何判断它们从属于一个对象呢。COM接口原则规定,同一个对象的Queryinterface的IID_IUnknown查询出来的IUnknown指针值应当相等。也就是说,每个对象的IUnknown指是唯一的。我们可以通过判断IUnknown指针是否相等来判断它们是否指向同一个对象。
 
        

   前面的例子是一个简单的无状态工厂版本,但实际中工厂应该存储状态。至少要保存它所创建的对象的信息。当一个工厂对动态共享库中的类的实例进行管理时,它应当知道何时可以卸载掉库。如果工厂保存了状态,那么你就可以查看是否有显示的引用并判断是否工厂创建过任何对象。

      工厂能保存的另外一种状态是对象是否是单例的。若是,则以后对工厂的调用应当返回一个对象。(这可以通过IServiceManager简化),

用类来实现工厂,你可以让工厂类从ISupports接口继承,也就可以管理工厂对象自身的生命周期。当你将工厂集合成组时,若需要判断他们是否可以卸载掉时很有用。通过IClassInfo,工厂支持对其底层实现的信息查询,比如对象使用什么语言写的,对象支持的接口等。

      在跨平台的环境中定义接口应该使用接口定义语言(IDL),XPCOM使用了它的一个变种XPIDL,让你能指明一个给定接口的方法,属性和常量,也可以定义接口层次关系。

它也有一些缺陷,它不支持多继承,方法名称也必须唯一。但它允许你产生类型库(typelib,后缀为.xpt的文件)。它是接口的二进制表现形式,提供了对接口程序级的控制和访问,而这对于在非C++环境中使用接口至关重要。当组件从其他语言访问,就使用二进制类型库来访问接口,从而得知它支持的方法,调用这些方法。实现这个功能的XPCOM的子集叫XPConnect。它是XPCOM中的一层,提供了从javascript等语言访问XPCOM组件的功能。每一个要映射到javascript的接口都应该有一个对应的类型库。从IDL文件可以产生类型库和C++头文件,使用的工具是xpidl编译器。

有一种对象名为服务对象,一般只有一份拷贝(当然同时可以有多种服务)。客户都是与同一个服务对象打交道。在XPCOM中有许多服务用来帮助开发者编写跨平台组件。包括跨平台文件抽象(提供了对文件,目录服务的统一形式的访问,确保每个用户使用相同的内存分配者的内存管理,允许传递简单消息的事件通知系统)

当开发完一个组件并编译成库后,它必须导出一个名为NSGetModule的方法,这个函数是访问库的入口点。它在组件的注册和注销,以及XPCOM想知道模块/库实现了哪些接口或类时被调用。nsIModulensIFactory接口控制组件的实际创建,还有字符串和XPCOM胶水部分。这些实用工具提供了像智能指针等功能。

      通过传递参数,你可以对XPCOM的初始化过程进行某些配置,包括特定目录的自定义位置。

b)注册新组件  c)调用自动注册结束

6)完成启动过程,XPCOM发出通知表明它已经启动完毕。

      XPCOM使用了名为清单的特殊文件来跟踪和持久化组件的信息到本地系统中。有两类清单:1)组件清单。2)类型库清单。

组件清单列出了所有注册组件,并保存了每个组件能做什么的详细信息,XPCOM将这个文件读入到一个驻内存数据库中。文件中主要有三种信息:1)注册组件在磁盘上的位置及其大小。2)类ID到位置的映射。3)契约ID到类ID的映射。

Manager的自动注册方法来在一个指定的组件目录中查找和注册组件:

当前面说的清单文件被读入后,XPCOM会检查看是否有组件需要被注册,有两种方法来注册。一种使用XPInstall,它提供了在安装过程中注册你的组件的接口。另一种是使用regxpcom,它会在默认的组件注册表中注册你的组件。当注册过程开始时,XPCOM会给所有的注册过的监听者广播一个通知,表明XPCOM已经开始注册新组件了。当所有组件注册完毕,另一个通知会被广播,表明XPCOM已经完成了注册过程。

64位系统下,有些组件(微软的)只有32位版本,64位的应用程序调用不了32位的COM组件,返回的结果就是没有注册类

别。 在64位系统中,VS2008默认会生成64位的程序,你可以改变程序的部署平台为×86来生成32位的程序。

在“解决方案”-》“开发项目的名称”,鼠标右击,单击“属性”-》“生成”-》“目标平台”,把“AnyCPU”改成“

×86”,重新编译程序即可。

我要回帖

更多关于 com组件注册 的文章

 

随机推荐