Creating Components in C++
让我们开始检查怎么用C++写XPCOM组件,最常见的组件类型是用C++写,然后编译成dll。下图显示了你实现的动态库和XPCOM框架之间的关系。
当你创建一个组件或模块,并编译成库时,必须要导出一个NSGetModule方法,NSGetModule方法是访问库的入口。在注册或注销组件时,或XPCOM需要查询组件或库实现哪些接口时,该方法被调用。本章将描述整个过程。除了NSGetModule之外,还有nsIModule 和nsIFactory实际控制着组件的创建,还有字符组和XPCOM
粘合部分。后者提供了易于开发的工具,如智能指针,通用模块支持和简单字符串实现。最大和最复杂的部分是组件特定的代码本身。
XPCOM Initialization
要理解为什么,何时调用组件,需要了解XPCOM的初始化过程。当程序启动,则可以初始化XPCOM。开始XPCOM的初始化可以由用户或者程序启动本身完成。嵌入Gecko的web浏览器,启动时通过嵌入式API初始化XPCOM。别的程序可能等到要用XPCOM时才启动初始化。这两种情况初始化XPCOM的过程都是一样的。当程序调用初始化时XPCOM启动,出入的启动参数可以配置XPCOM,包括自定义的目录。这时API的主要目的是改变XPCOM的搜索目录,
XPCOM启动的步骤:
- 程序启动XPCOM
- XPCOM发出一个通知表示已经启动
- XPCOM找到并处理组件清单
- XPCOM找到并处理类型库清单
- 如果有新组件,XPCOM注册它们:
a。 XPCOM调用自动注册
b 。XPCOM注册新组件
c。XPCOM结束调用自动注册
6. XPCOM启动完成
XPCOM Registry Manifests
XPCOM用清单文件为本地系统保存关于组件的信息,有两种类型的清单:
• “ Component Manifests”
• “ Type Library Manifests”
Component Manifests.
当XPCOM启动时,它查找组件清单,名为compreg.dat。该文件列出了已经注册的组件,并保存了关于每个组件是干什么的信息。XPCOM用清单文件来确定哪些组件是被覆盖的。XPCOM把这个文件读到内存数据库
组件清单是组件和文件,组件和类的映射,包含以下内容:
- 定位在磁盘上的注册的组件文件的大小
- 类ID到位置的映射
- Contract ID 到Class ID映射
Type Library Manifests.
程序另一个重要文件是类型库清单,它在组件目录下,名为xpti.dat。它包含系统上所有类型库的位置和搜索路径。它也列出所有已知接口和定义接口的类型库文件的连接。类型库文件是XPCOM二进制组件框架的核心。
类型库清单包含以下信息:
- 所有类型库文件的位置
- 类型库中所有已知接口和结构定义的映射
用这两个文件的数据,XPCOM知道哪些组件库已经注册,实现了哪些接口。另外,它把组件和类型库关联起来。
下一节介绍如何挂钩XPCOM的启动和注册过程,使得组件的数据在清单中体现,如此一来,在启动的时候可以找到组件并注册。
Registration Methods in XPCOM
什么是XPCOM注册
简而言之,注册过程就是让XPCOM知道你的组件,如本节和下一节所述,你可以在安装时显示的注册你的组件,或者通过regxpcom程序,或者可以用自动注册方法,在服务管理器找到并注册组件到特定的目录:
• XPInstall APIs
• regxpcom command-line tool
• nsIComponentRegistrar APIs from Service Manager
注册过程相当复杂,本节介绍XPCOM的初始化,下一节介绍在代码里怎么做使得能让XPCOM注册组件。
一旦清单文件被读入,XPCOM检查是否有组件需要注册。有两种方式支持组件注册,第一种是用XPInstall,它是一种安装技术,有可能伴随着一个 Gecko程序,
在安装过程中注册的组件接口 。
另一种更明显的组件注册方法是用regxpcom程序,它是Mozilla的一部分,存在于Gecko SDK,regxpcom在默认的组件列表安装组件。
Gecko嵌入式程序也提供了自己的XPCOM组件安装方法,使用了nsIComponentRegistrar接口,一个程序可以提供一个非注册的组件目录,启动的时候自动注册组件,终止时自动卸载组件。
当注册过程开始,XPCOM给所有注册的观测者发出广播,表示开始注册一个新的组件。直到所有的组件注册完成,有发出一个通知表示所有的XPCOM的注册步骤已经完成。nsIObserver接口处理执行通知。
Autoregistration
自动注册在XPCOM有时候也叫注册,上一节我们讲述了用XPCOM注册组件的三个方法。有时候程序用nsIComponentRegistrar接口,使用自己的代码观察特定的目标并注册被添加的组件。这就是通常说的自动注册。你需要知道需要用你的组件的程序的安装和注册的需求是什么。
The Shutdown Process
当程序要关闭XPCOM,它调用ShutdownXPCOM,调用该方法时,发生以下事情:
- XPCOM给所有的观测者发出关闭通知
- XPCOM关闭组件管理器,服务管理器和相关服务
- XPCOM释放所有全局服务
- ShutdownXPCOM返回,程序正常退出
Component Loaders
组件可以用很多语言编写,目前本书讨论的是本地组件,提供NSGetModule的共享库。如果为Javascript安装一个组件加载器,你就可以写javascript组件。
为了
注册、注销、装置和管理不同的组件类型,XPCOM用组件加载器抽象了XPCOM组件和XPCOM的接口。该加载器负责初始化,装载,卸载和支持每个组件的nsIModule接口。组件加载器也支持脚本组件。
当创建一个本地组件,组件加载器查找组件共享库的导出符号,这里的本地包括所有可以生成动态库的语言,脚本语言和非本地语言不能创建本地库。要使用非本地XPCOM库,XPCOM需要有知道怎么出来这些类型组件的特殊的组件加载器。
XPConnect,
提供了一个组件加载程序,使不同类型,包括接口和它们的参数,可以使用JavaScript,每中XPCOM支持的语言都要有一个组件加载器。
Three parts of a XPCOM Component Library
XPCOM至少有三个层次,从里到外包括:
XPCOM核心对象就是你要实现的功能。例如,对象可能启动一个网络下载并实现监听接口,或者可能提供内容类型处理。不管怎么样,它都是XPCOM组件的核心,其他层次支持它,并把它插入到XPCOM系统中,一个单独库可能有多个这样的核心对象。
核心对象的上一层是工厂代码,工厂对象提供了核心对象的抽象,第一章介绍了使用了工厂模式的工厂对象,在XPCOM库的这层中,工厂对象的低层核心对象的工厂。
再往外一层是模块代码,模块接口提供了另外一种抽象,这时工厂对象支持多个工厂。从组件库的外部,只有一个NSGetModule()入口。从这个入口,可以生成多个工厂和XPCOM对象。以下章节将详细讲述这些层次。这里我们只是介绍,工厂模式是由nsIFactory接口表示。模块层次由nsIModule表示,
大多数组件库只需要这两个接口,,还有nsISupport接口,
负责XPCOM负加载 识别,并利用其核心对象代码。
下一节我们将写真实的代码编译成组件库,
你会看到每一层是如何实现的以及每个接口的使用。
XPCOM Glue
XPCOM包含很多,大部分的XPCOM接口并不冻结,
只在Gecko的内部使用。XPCOM提供很多从AVL链表的数据结构,不用自己写链表,重用nsVoidArray或者其他可用的类是很有诱惑力的,但是这可能是致命的错误。任何时候类都可能出现异常行为。
XPCOM是一个非常开放的环境,在运行时可以通过 CID, Contract ID, IID获取一个服务或者组件。最新统计XPIDL定义了超过1300个接口,
少于100是被冻结的,这意味着开发者有很多接口可用。如果在IDL组件中,一个接口没有 被显示标记为冻结,版本改变时可能导致你的组件被分解。
The Glue Library
通常你要避免任何解冻接口。可是,XPCOM提供一些解冻工具,在实际的组件编程中经常用到。
智能指针类,nsCOMPtr,可以做引用计数,而且很少出错。实际上并不冻结,也不是nsDebug,打印调试信息的类,或nsMemory,该类确保
每个人都使用相同的堆、通用的工厂和模块。不用
每个开发人员发现并把这些不同的文件复制到自己的应用程序中,取代的是,XPCOM提供单一的库,你可以连接到程序中,如下图所示,
这就是粘合库,它在你的组件和XPCOM之间提供一个桥梁,或粘合层。粘合库的一个版本是建在XPCOM中,
当你的组件使用它时,
链接到这个库的快照。
它直接包括这些解冻类的一个副本,它允许改变
XPCOM库版本而不影响程序。
XPCOM String Classes
XPCOM使用的基本的字符串类型是nsAString 和nsACString .
字符串类实现这些抽象类,是XPCOM中另一组有用的解冻类。为了利用某些Gecko API,
大多数组件和嵌入应用程序的需要链接到一些字符串类。但是,Mozilla使用的字符串代码高度复杂。 nsEmbedString 和nsEmbedCString对组件开发来说是很轻的字符串类,
特别是在小型嵌入式应用程序。该字符串最低限度支持nsAString/nsACString字符串类。
在你的组件中, 你可以限制自己使用nsEmbedString或者使用其他字符串的所有功能。WebLock使用了nsEmbedString 。
胶水库为XPCOM的公共函数提供了存根函数。当胶水库初始化,它动态装载XPCOM库的符号,避免组件直接连接到XPCOM库。