《XPCOM组件开发》笔记(一)

news/2024/7/20 15:19:53 标签: 内存管理, javascript, c/c++

      本书是关于Gecko和基于Gecko应用程序来开发XPCOM组件的。简介部分探讨组件的概念,第一章你将编译简单的代码并注册到Mozilla中,此时会探讨组件和模块之间的关系,XPCOM接口以及注册的过程。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

      假定读者熟悉C++中的继承和封装,很多例子是javascript的,它用来做完脚本对象在Mozilla中访问XPCOM组件,因此熟悉它也是很好的。

      XPCOM表示跨平台组件对象模型,类似与微软的COM.若你有这方面的经验,可以直接运用上来。

      全书贯穿一个叫WebLock的例子来讲解XPCOM组件的开发,步骤如下:

1)     为组件开发基本的模块代码

2)     使用C++宏,特别的字符串类和智能指针来优化代码

3)     定义组件的功能,为这些功能创建XPIDL接口,为WebLock组件接口开发特定的实现代码。

4)     结束实现WebLock组件:nsIContentPolicy,文件I/O,加锁等

5)     WebLock组件创建用户接口

6)     打包WebLock以便发布和安装。

      组件在运行时组装到一起,构建时和其他组件无关,为了允许一个应用程序中的组件之间的互操作,XPCOM将组件的接口和实现相分离。XPCOM提供了一些工具和库来加载和操作这些组件,一些服务来帮助开发者编写模块化的跨平台代码,以及版本支持,因此组件可以在不破坏应用程序或重新创建应用程序的情况下替换和升级,还具有良好的可复用性。

      提供的其他功能有:组件管理,文件抽象化,对象消息传递,内存管理。组件一般以可复用的二进制库形式发布(例如windows上的DLL,它可以包括一个或多个组件,若在一个二进制库中有两个以上相关的组件,这个库就叫做模块。

      接口就是组件的通信通道,它不是什么新概念,我们写”hello world”时就用到了接口,那时接口是我们写的应用程序代码和打印代码之间,我们用stdio这个接口来打印字符串。XPCOM来写”hello world”的话,唯一的区别是它是在运行时查找这个打印函数,但在编译时并不知道stdio

      组件和面向接口编程的两个基本问题是组件生命周期和接口查询(在运行时识别组件支持哪些接口)。nsISupports基接口是XPCOM中所有接口的祖先接口,它提供了这两个问题的解决方案。

      XPCOM中,接口是引用计数的。组件必须跟踪客户端引用它的数目,并且当引用数为0时删除自己。

      当一个组件被创建后,其内部的一个整数跟踪这个引用数。当客户端实例化组件时这个引用计数自动加1,在组件的整个生命周期中,这个引用计数加加减减,始终保持大于0,某个时候,所有的客户都对组件不感兴趣了,引用计数到达0,组件就删除自己。

      若由客户来负责接口的计数,那么如果它忘记对引用计数减1的话就会出问题,接口将不会被释放,进而导致内存泄露。nsISupports提供了接口发现和引用计数的基本功能。其成员函数QueryInterfaceAddRef,Release,提供了从一个对象获取指定接口,增加引用计数,当对象不再被使用时释放它的功能。

None.gif Class Sample :  public  nsISupports
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gifPrivate:
InBlock.gif     Nsrefcnt mRefCnt;
InBlock.gifPublic:
InBlock.gif    Sample();
InBlock.gif    Virtual 
~Sample();
InBlock.gif    NS_IMETHOD QueryInterface(
const nsIID &aIID,void **aResult);
InBlock.gif    NS_IMETHOD_(nsrefcnt) AddRef(
void);
InBlock.gif    NS_IMETHOD_(nsrefcnt) Release(
void);
ExpandedBlockEnd.gif}
;
None.gif
None.gifSample()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
// initialize the reference count to 0
InBlock.gif
    mRefCnt = 0;
ExpandedBlockEnd.gif}

None.gifSample::
~ Sample()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedBlockEnd.gif}

None.gif
//  typical, generic implementation of QI
None.gif
NS_IMETHODIMP Sample::QueryInterface( const  nsIID  & aIID,
None.gif
void   ** aResult)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif
if (aResult == NULL) dot.gif{//空指针
InBlock.gif
return NS_ERROR_NULL_POINTER;
ExpandedSubBlockEnd.gif}

InBlock.gif
*aResult = NULL;
ExpandedSubBlockStart.gifContractedSubBlock.gif
if (aIID.Equals(kISupportsIID)) dot.gif{
InBlock.gif
*aResult = (void *this;
ExpandedSubBlockEnd.gif}

ExpandedSubBlockStart.gifContractedSubBlock.gif
if (*aResult == NULL) dot.gif{//接口不支持,书上这里好像错了
InBlock.gif
return NS_ERROR_NO_INTERFACE;
ExpandedSubBlockEnd.gif}

InBlock.gif
// add a reference
InBlock.gif
AddRef();//引用计数加1
InBlock.gif
return NS_OK;
ExpandedBlockEnd.gif}

None.gifNS_IMETHODIMP_(nsrefcnt) Sample::AddRef()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
return ++mRefCnt;
ExpandedBlockEnd.gif}

None.gifNS_IMETHODIMP_(nsrefcnt) Sample::Release()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
if (--mRefCnt == 0dot.gif{//当前是最后一个引用组件的客户 
InBlock.gif
        delete this;
InBlock.gif        
return 0;
ExpandedSubBlockEnd.gif}

InBlock.gif
// optional: return the reference count
InBlock.gif
return mRefCnt;
ExpandedBlockEnd.gif}

None.gif

      XPCOM没有使用C++RTTI,它通过QueryInterface接口来将对象转换到其支持的接口。每个接口都被赋予一个标识符,它通过一个“uuidgen”的工具产生。UUID是一个唯一的,128位的数。在接口中,它叫做IID(对于组件来说,它叫契约ID.

      当一个客户想知道对象是否支持某个接口,它就将IID通过QueryInterface传给对象,若那个对象支持此接口,它就对其自身引用计数加1并返回一个到那个接口的指针。若不支持,则返回一个错误信息。

ExpandedBlockStart.gif ContractedBlock.gif      class  nsISupports  dot.gif {
InBlock.gif
public:
InBlock.gif
long QueryInterface(const nsIID & uuid,void **result) = 0;
InBlock.gif
long AddRef(void= 0;
InBlock.gif
long Release(void= 0;
ExpandedBlockEnd.gif}
;
None.gif

QueryInterface的第一个参数是一个名叫nsIID的类的引用,它是IID的简单封装。它有三个方法,Equals,Parse,ToString. Equals最重要,它用来在接口查询的过程中比较两个nsIID

      当你实现nsIID类时,当客户使用nsISupports IID调用QueryInterface时,必须确保其方法返回一个有效值

      前面的例子中可以简单地使用c语言风格的转换,但要转换为所需要的类型时要复杂些,因为你必须返回与所需要的接口对应的虚函数表的接口指针。当继承层次中有二义性时会出问题。

      除了前面讨论的IID接口标识符外,XPCOM还使用了两种标识符来区别类和组件:1CID.2)契约ID.

      CID IID 类似,也是 128 位数,唯一标识一个类或组件。用于 nsISupports

CID:00000000-0000-0000-c000-000000000046

 

#define SAMPLE_CID \

{ 0x<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />777f7150, 0x4a2b, 0x4301, \

{ 0xad, 0x10, 0x5e, 0xab, 0x25, 0xb3, 0x22, 0xaa}}

你还会经常看到NS_DEFINE_CID,这个宏定义了一个CID值常量。

static NS_DEFINE_CID(kWebShellCID, NS_WEB_SHELL_CID);

CID有时候也叫做类标识符,若CID引用的类实现2个以上的接口,则CID确保当它发布或冻结时实现了接口集合的全部接口。

      契约ID是给人看的,CID或者契约ID可以用来从组件管理器那获取一个组件,"@mozilla.org/network/ldap-operation;1",格式是域名/模块/组件名/版本号

      CID一样,契约ID引用到一个实现而不是接口,引用到接口是IID干的。但契约ID并不绑死在一个特定的实现,而CID却绑死了。契约ID只是指明了它想实现的一个特定的接口集合,而任何数目的CID都可以进来满足这个需求。契约IDCID的这个区别使得它可以用来override组件。

      工厂模式可以用来封装对象的创建。工厂的目标是在不向客户暴露对象实现和初始化的情况下创建对象。

None.gif int  New_SomeInterface(SomeInterface **  ret)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
// create the object
InBlock.gif
SomeClass* out = new SomeClass();
InBlock.gif
if (!outreturn -1;
InBlock.gif
// init the object
InBlock.gif
if (out->Init() == FALSE)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifdelete 
out;
InBlock.gif
return -1;
ExpandedSubBlockEnd.gif}

InBlock.gif
// cast to the interface
InBlock.gif
*ret = static_cast<SomeInterface*>(out);
InBlock.gif
return 0;
ExpandedBlockEnd.gif}

None.gif

      XPCOM中,工厂是 nsIFactory接口的实现,使用了工厂设计模式来封装对象的构建和初始化过程。


http://www.niftyadmin.cn/n/1201371.html

相关文章

红包算法 递归 php,【杂谈】PHP递归算法(二)

在前面的文章《PHP递归算法(一)》中&#xff0c;我们为大家介绍了如何利用静态变量的方法来实现递归算法。本篇文章我们就继续为大家介绍另一种实现递归算法的方法即通过全局变量的方法。下面我们结合代码示例&#xff0c;为大家介绍通过全局变量Global实现递归的方法。代码如下…

php分类mysql数据,php+mysql数据库无限分类代码(1/2)_PHP教程

class sortclass{var $data array();var $child array(-1>array());var $layer array(-1>-1);var $parent array();var $link;var $table;function sortclass($link, $table){$this->setnode(0, -1, ‘顶极节点’);$this->link $link;$this->table $table…

用NClay进行业务编写到底有多简单?

[NClay.Services.Service(typeof(IUserService))] publicclassUserService :DBAccess, IUserService { IUserService 成员#region IUserService 成员 public void Create(User user) { lock (typeof(UserService)) { …

js对联广告滚动代码 可关闭

在上篇对联广告滚动代码包括flash和图片之后有朋友问到需要可以关闭的js对联广告代码&#xff0c;找啊找&#xff0c;找到了 如下图演示&#xff1a; 演示地址:jsad-code-for-couplet-scroll-38/index.htm 下载地址&#xff1a;jsad-code-for-couplet-scroll-38.zip 转载于:ht…

linux怎么还原bak文件,Linux下面如何备份恢复系统? 有G4L,变得如此简单

Linux下面如何备份恢复系统?虽然说Linux操作系统很强壮&#xff0c;且有很完善的包管理功能&#xff0c;但是人有旦夕祸福、月有阴晴圆缺&#xff0c;总有失手的时候&#xff0c;万一误操作系统坏了该如何修复呢&#xff1f;总不能回到低级阶段慢慢重装吧&#xff1f;Windows下…

微软发布新的LCS SDK用于Office Communications Server 2007开发

微软发布统一通迅客户端API的SDK&#xff0c;使得应用程序的开发者可以整合Office Communications Server 2007 增强的VoIP&#xff0c;Video ,即时通讯&#xff0c;会议&#xff0c;电话&#xff0c;通讯录管理等到自己开发的程序里面。 [更多...]

groovy获取linux用户根目录,Groovy执行Shell命令

阿晨1998// a wrapper closure around executing a string // can take either a string or a list of strings (for arguments with spaces) // prints all output, complains and halts on error def runC…

CVSACL使用说明

1 CVSACL简介 目前北京的配置库使用的是CVS,虽然CVS已经比较成熟,但是在权限控制上还存在不足,目前只能控制到root一级,无法实现权限的精确控制。CVSACL就是实现访问控制的CVS补丁&#xff0c;可以将权限精确控制到最小一级目录&#xff0c;而且定义了8级不同的访问权限&#x…