前面的例子是一个简单的无状态工厂版本,但实际中工厂应该存储状态。至少要保存它所创建的对象的信息。当一个工厂对动态共享库中的类的实例进行管理时,它应当知道何时可以卸载掉库。如果工厂保存了状态,那么你就可以查看是否有显示的引用并判断是否工厂创建过任何对象。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
工厂能保存的另外一种状态是对象是否是单例的。若是,则以后对工厂的调用应当返回一个对象。(这可以通过IServiceManager简化),
用类来实现工厂,你可以让工厂类从ISupports接口继承,也就可以管理工厂对象自身的生命周期。当你将工厂集合成组时,若需要判断他们是否可以卸载掉时很有用。通过IClassInfo,工厂支持对其底层实现的信息查询,比如对象使用什么语言写的,对象支持的接口等。
在跨平台的环境中定义接口应该使用接口定义语言(IDL),XPCOM使用了它的一个变种XPIDL,让你能指明一个给定接口的方法,属性和常量,也可以定义接口层次关系。
它也有一些缺陷,它不支持多继承,方法名称也必须唯一。但它允许你产生类型库(typelib,后缀为.xpt的文件)。它是接口的二进制表现形式,提供了对接口程序级的控制和访问,而这对于在非C++环境中使用接口至关重要。当组件从其他语言访问,就使用二进制类型库来访问接口,从而得知它支持的方法,调用这些方法。实现这个功能的XPCOM的子集叫XPConnect。它是XPCOM中的一层,提供了从javascript等语言访问XPCOM组件的功能。每一个要映射到javascript的接口都应该有一个对应的类型库。从IDL文件可以产生类型库和C++头文件,使用的工具是xpidl编译器。
有一种对象名为服务对象,一般只有一份拷贝(当然同时可以有多种服务)。客户都是与同一个服务对象打交道。在XPCOM中有许多服务用来帮助开发者编写跨平台组件。包括跨平台文件抽象(提供了对文件,目录服务的统一形式的访问,确保每个用户使用相同的内存分配者的内存管理,允许传递简单消息的事件通知系统)。
JavaScript版本:
// get the cookie manager component in JavaScript
var cookiemanager = Components.classes[ " @mozilla.org/
cookiemanager;1 " ].getService();
cookiemanager = cookiemanager.QueryInterface
(Components.interfaces.nsICookieManager);
// called as part of a largerDeleteAllCookies() function
function FinalizeCookieDeletions() {
for (var c=0; c<deletedCookies.length; c++) {
cookiemanager.remove(deletedCookies[c].host,
deletedCookies[c].name,
deletedCookies[c].path);
}
deletedCookies.length = 0;
}
C++版本:
nsresult rv = NS_GetServiceManager(getter_AddRefs(servMan));
if (NS_FAILED(rv))
return - 1 ;
nsCOMPtr < nsICookieManager > cookieManager;
rv = servMan -> GetServiceByContractID( " @mozilla.org/cookiemanager " ,
NS_GET_IID(nsICookieManager), getter_AddRefs(cookieManager));
if (NS_FAILED(rv))
return - 1 ;
PRUint32 len;
deletedCookies -> GetLength( & len);
for ( int c = 0 ; c < len; c ++ )
{
cookiemanager->Remove(deletedCookies[c].host,deletedCookies[c].name,deletedCookies[c].path);
}
示例:
cookiemanager;1 " ].getService();
cookiemanager = cookiemanager
.QueryInterface(Components.interfaces.nsICookieManager);
function loadCookies() {
// load cookies into a table
var enumerator = cookiemanager.enumerator;
var count = 0;
var showPolicyField = false;
while (enumerator.hasMoreElements()) {
var nextCookie = enumerator.getNext();
nextCookie = nextCookie.QueryInterface
(Components.interfaces.nsICookie);
.
}
function FinalizeCookieDeletions() {
for (var c=0; c<deletedCookies.length; c++) {
cookiemanager.remove(deletedCookies[c].host,
deletedCookies[c].name,
deletedCookies[c].path,
}
deletedCookies.length = 0;
}
当开发完一个组件并编译成库后,它必须导出一个名为NSGetModule的方法,这个函数是访问库的入口点。它在组件的注册和注销,以及XPCOM想知道模块/库实现了哪些接口或类时被调用。nsIModule和nsIFactory接口控制组件的实际创建,还有字符串和XPCOM胶水部分。这些实用工具提供了像智能指针等功能。
通过传递参数,你可以对XPCOM的初始化过程进行某些配置,包括特定目录的自定义位置。
XPCOM启动步骤:1)应用程序启动XPCOM,2)XPCOM发出一个通知表明它开始启动了。3)XPCOM发现并处理组件清单。4)XPCOM发现并处理类型库清单。5)若有新组件,XPCOM就注册他们:a)调用自动注册 b)注册新组件 c)调用自动注册结束
6)完成启动过程,XPCOM发出通知表明它已经启动完毕。
XPCOM使用了名为清单的特殊文件来跟踪和持久化组件的信息到本地系统中。有两类清单:1)组件清单。2)类型库清单。
组件清单列出了所有注册组件,并保存了每个组件能做什么的详细信息,XPCOM将这个文件读入到一个驻内存数据库中。文件中主要有三种信息:1)注册组件在磁盘上的位置及其大小。2)类ID到位置的映射。3)契约ID到类ID的映射。
注册就是让XPCOM知道你的组件的存在的过程。可以在安装的过程中显示注册组件,或使用regxpcom,或使用Service Manager的自动注册方法来在一个指定的组件目录中查找和注册组件:
1)XPInstall API 2)regxpcom命令行工具 3)Service Manage的nsIComponetRegistrar API
当前面说的清单文件被读入后,XPCOM会检查看是否有组件需要被注册,有两种方法来注册。一种使用XPInstall,它提供了在安装过程中注册你的组件的接口。另一种是使用regxpcom,它会在默认的组件注册表中注册你的组件。当注册过程开始时,XPCOM会给所有的注册过的监听者广播一个通知,表明XPCOM已经开始注册新组件了。当所有组件注册完毕,另一个通知会被广播,表明XPCOM已经完成了注册过程。
当应用程序准备关闭XPCOM时,它调用NS_ShutdownXPCOM,接下来:
1) XPCOM广播一个关闭通知给所有注册过的监听者
2) XPCOM关闭组件管理器,服务管理器和相关的服务
3) XPCOM释放所有全局服务
4)NS_ShutdownXPCOM 返回,应用程序退出。
注意关闭过程是不可逆的。