基于Mozilla Thunderbird的扩展开发(七)---工欲善其事,必先利其器

本文详细介绍基于Mozilla Thunderbird的扩展开发过程,包括手工打造插件、使用Ant自动化打包、集成开发工具推荐、DOM Inspector使用方法以及调试技巧等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

20080506.bmp

Mozilla扩展系列链接:

1浅谈基于Mozilla Thunderbird的扩展开发

2基于Mozilla平台的扩展开发(续)----XPCOM组件篇

3基于Mozilla Thunderbird的扩展开发(三)---如何获取邮件的完整信息

4基于Mozilla Thunderbird的扩展开发(四)---修改源代码实现自动保存附件

5基于Mozilla Thunderbird的扩展开发(五)---进程间通信之Socket篇(上)

6基于Mozilla Thunderbird的扩展开发(六)---进程间通信之Socket篇(下)

7, 基于Mozilla Thunderbird的扩展开发(七)---工欲善其事,必先利其器

Mozilla最为人诟病的地方就是没有称手的开发工具,这对于我们这些被微软惯坏的开发人员来说,如果没有Visual Studio这样舒服的工具的话,谁会投入你的怀抱呢?本文就希望从三个方面介绍下我所了解到的Mozilla 平台下的开发工具及一些小技巧。

最原始的方法当然是全部手工打造,从插件的编写,到打包,这样做的好处是对Mozilla平台下插件的开发有比较深入的了解,但缺点就是每次做一些小的修改后都需要重复进行压缩,打包等一系列繁杂的工序,如果你喜欢这种方法,可以参考我这篇文章:《浅谈基于Mozilla ThunderBird的扩展开发》,也可以参考Mozilla开发中心这篇文章《Building an Extension》。

      每次修改代码后就得自己手动重新打包,发布,安装,你对这些已经感到厌烦了吗?好的,那就想办法脱离苦海吧。我们仔细分析后发现,就是一个打包的问题,因此我们就可以使用Ant来完成这些琐碎的打包工作,下面就是《浅谈基于Mozilla ThunderBird的扩展开发》中使用的build.xml文件:

None.gif <? xml version="1.0" ?>
None.gif
< project  name ="helloworld"  default ="createxpi" >
None.gif  
< delete  file ="helloworld.xpi" />
None.gif  
< delete  file ="helloworld.jar" />
None.gif  
< target  name ="createjar" >
None.gif    
< zip  destfile ="helloworld.jar"  compress ="false" >
None.gif        
< fileset  dir ="chrome" >
None.gif            
< include  name ="content/**" />
None.gif        
</ fileset >
None.gif    
</ zip >
None.gif  
</ target >
None.gif
None.gif  
< target  name ="createxpi"  depends ="createjar" >
None.gif    
< zip  destfile ="helloworld.xpi" >
None.gif      
< zipfileset  dir ="."  includes ="helloworld.jar"  prefix ="chrome"   />
None.gif      
< zipfileset  dir ="."  includes ="chrome.manifest" />
None.gif      
< zipfileset  dir ="."  includes ="install.rdf"   />
None.gif    
</ zip >
None.gif  
</ target >
None.gif
</ project >
None.gif

如果你的项目结构比这个要复杂的话,请根据自己的需求更改此文件再使用Ant编译就可以了。这种方法也是我目前使用最多的方法了,因为感觉控制起来比较灵活。

      如果你喜欢集成化的开发工具,想让它为你做更多的事情的话,这里推荐一个工具:NetBean+foxbeans+foxfiles,后面两个插件是用于开发Mozilla平台插件的,下载地址为:

Foxbeans: http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=4209

Foxfiles: http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=4649

官方的入门文档:

http://wiki.netbeans.org/MozillaAddonDevelopment

不过不推荐用这个插件,试用了一下,并不是很好用。

     

      再来谈下另一个问题,在做界面时,如何快速地获知目标程序中想overlay掉的控件的id以及它的属性呢?这在做插件开发时是一个比较重要的方面,因为你的插件的界面就是附着在目标程序(firefoxthunderbirdsunbird)上的。那么官方推荐的工具就够用了,这个插件就是DOM Inspector它可以用来定位你所需要的控件。

      Venkman是官方推荐的调试工具,但个人感觉还是不大好用。

另外几个调试的技巧是:1)可以试用”dump语句来显示调试信息,不过这需要进行一些配置工作。2)在代码中使用nsIConsoleService 将日志信息输出到JavaScript控制台中。

3)自己编译一个debug版本的firefoxthunderbird,并且在其源代码或你的C++ XPCOM组件中设置断点,进一步的信息可以参考Mozilla开发中心的文档。

      除此以外,我们也可以自己开发一个日志工具类来记录感兴趣的信息,下面是我常用的一个日志组件类:

None.gif const CI  =  Components.interfaces, CC  =  Components.classes, CR  =  Components.results;
None.giftBirdBiffUtility.classID 
=  Components.ID( " {e07f8540-831f-11db-9fe1-0800200c9a66} " );
None.giftBirdBiffUtility.contractID 
=   " @phinecos.cnblogs.com/HelloWorld/utility;1 " ;
None.giftBirdBiffUtility.classDescription 
=   " Utility Service " ;
None.gif
None.gif
// 日志组件
None.gif
function  tBirdBiffUtility()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif  
this.consoleService = CC["@mozilla.org/consoleservice;1"].getService(CI.nsIConsoleService);//控制台服务
InBlock.gif
  this.logFile = null;//日志文件对象
InBlock.gif
  this.logToFile = true;//是否开启日志功能,默认为开启,插件发布后,关闭它就是
ExpandedBlockEnd.gif
}

None.gif
None.giftBirdBiffUtility.prototype 
=
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif  initialize: 
function()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{//初始化
InBlock.gif
    this.getLoggingPref();
ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  closeLogFile: 
function()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{//关闭日志文件
InBlock.gif
    if(this.logFile)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
this.logFile.close(null);
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  openLogFile: 
function()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{//打开日志文件
InBlock.gif
    this.closeLogFile();//关闭先前的日志文件
InBlock.gif

InBlock.gif    
if(!this.logToFile)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
return;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
var tmpFile = CC["@mozilla.org/file/directory_service;1"]
InBlock.gif        .getService(CI.nsIProperties).get(
"TmpD", CI.nsILocalFile);
InBlock.gif    
//构造日志文件名称
InBlock.gif
    var filename = "HelloWorld";
InBlock.gif    
if(this.isFirefox())
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      filename 
+= "-firefox.log";
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
if(this.isSunbird())
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      filename 
+= "-sunbird.log";
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
if(this.isThunderbird())
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      filename 
+= "-thunderbird.log";
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    tmpFile.append(filename);
InBlock.gif    
//创建不重名的日志文件
InBlock.gif
    tmpFile.createUnique(CI.nsIFile.NORMAL_FILE_TYPE, 0664);
InBlock.gif
InBlock.gif    
this.logFile = CC["@mozilla.org/network/file-output-stream;1"]
InBlock.gif        .createInstance(CI.nsIFileOutputStream);
InBlock.gif
InBlock.gif    
// write, create, truncate
InBlock.gif
    this.logFile.init(tmpFile, 0x02 | 0x08 | 0x200664this.logFile.DEFAULT_REPLACEMENT_CHARACTER);
ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  isFirefox: 
function()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    
if(this.getApplicationId() == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}")
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
return true;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
return false;
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  isSunbird: 
function()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    
if(this.getApplicationId() == "{718e30fb-e89b-41dd-9da7-e25a45638b28}")
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
return true;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
return false;
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  isThunderbird: 
function()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    
if(this.getApplicationId() == "{3550f703-e582-4d05-9a08-453d09bdfdc6}")
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
return true;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
return false;
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  getLoggingPref: 
function()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    
// look for and use a preference if given
InBlock.gif
    if (this.logToFile == true)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{//开启了日志功能
InBlock.gif
        this.openLogFile();
InBlock.gif          
this.logToConsole("tBirdBiffUtility.getLoggingPref""thunderbirdbiff.logToFile preference setting is " + this.logToFile);
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{//没有开启日志功能
InBlock.gif
      this.logToConsole("tBirdBiffUtility.logToFile""No thunderbirdbiff.logToFile preference setting found, using FALSE default");
InBlock.gif      
this.logToFile = false;
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  logError: 
function(source, message)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{//记录错误信息
InBlock.gif
    var callingFunction = source;
InBlock.gif    
var error = CC["@mozilla.org/scripterror;1"].createInstance(CI.nsIScriptError);
InBlock.gif    error.init(callingFunction 
+ "(): " + message, nullnullnullnull, CI.nsIScriptError.errorFlag, null);
InBlock.gif    
this.consoleService.logMessage(error);
InBlock.gif    
this.log(source, "ERROR-" + message);
InBlock.gif    
this.callingFunction = null;
InBlock.gif    
this.error = null;
ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  writeToLogFile: 
function(msg)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{//写入日志文件
InBlock.gif
    if(this.logToFile)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
this.logFile.write(msg + "\n", msg.length + 1);
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  log: 
function(source, message)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{//日志功能
InBlock.gif
    var msg =  source + "():\n\   " + message;
InBlock.gif
InBlock.gif    
try
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
this.writeToLogFile(msg);
ExpandedSubBlockEnd.gif    }

InBlock.gif    
catch(e)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
var errorMsg = "Error trying to write logfile: " + e + " -- Opening a new file\n";
InBlock.gif      
this.logToConsole(errorMsg);
InBlock.gif      
this.openLogFile();
InBlock.gif      
if(this.logFile)
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
this.writeToLogFile(errorMsg);
InBlock.gif        
this.writeToLogFile(msg);
ExpandedSubBlockEnd.gif      }

InBlock.gif
InBlock.gif      errorMsg 
= null;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    msg 
= null;
ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  logToConsole: 
function(source, message)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{//写日志到控制台
InBlock.gif
    var msg = this.getAddonName() + "." + source + "():\n\   " + message;
InBlock.gif    
this.consoleService.logStringMessage(msg);
InBlock.gif    
this.log(source, message);
InBlock.gif    msg 
= null;
ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  getApplicationInfo: 
function()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{//获取目标程序信息
InBlock.gif
    return CC["@mozilla.org/xre/app-info;1"].getService(CI.nsIXULAppInfo);
ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  getApplicationId: 
function()
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{//获取目标程序id
InBlock.gif
    if(!this.id)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      
this.id = this.getApplicationInfo().ID;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
return this.id;
ExpandedSubBlockEnd.gif  }
,
InBlock.gif
InBlock.gif  onObserve: 
function(subject, topic, data)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockEnd.gif    }
,
InBlock.gif
InBlock.gif  
// nsISupports
InBlock.gif
    QueryInterface: function(aIID)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif    
if( aIID.equals(CI.nsISupports) ||
InBlock.gif      aIID.equals(CI.nsIClassInfo) 
||
InBlock.gif      aIID.equals(CI.nsIObserver))
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return this;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
throw CR.NS_ERROR_NO_INTERFACE;
ExpandedSubBlockEnd.gif    }
,
InBlock.gif
InBlock.gif  
// nsIClassInfo
InBlock.gif
    getInterfaces: function(aCount)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
var ifaces = new Array();
InBlock.gif    ifaces.push(CI.nsISupports);
InBlock.gif    ifaces.push(CI.nsIClassInfo);
InBlock.gif    ifaces.push(CI.nsIObserver);
InBlock.gif        aCount.value 
= ifaces.length;
InBlock.gif        
return ifaces;
ExpandedSubBlockEnd.gif    }
,
InBlock.gif
InBlock.gif  
// nsIClassInfo
ExpandedSubBlockStart.gifContractedSubBlock.gif
    getHelperForLanguage: function(aLanguage) dot.gifreturn null; },
ExpandedSubBlockStart.gifContractedSubBlock.gif  get contractID() 
dot.gifreturn tBirdBiffUtility.contractID; },
ExpandedSubBlockStart.gifContractedSubBlock.gif  get classID() 
dot.gifreturn tBirdBiffUtility.classID; },
ExpandedSubBlockStart.gifContractedSubBlock.gif  get classDescription() 
dot.gifreturn tBirdBiffUtility.classDescription; },
ExpandedSubBlockStart.gifContractedSubBlock.gif  get implementationLanguage() 
dot.gifreturn CI.nsIProgrammingLanguage.JAVASCRIPT; },
ExpandedSubBlockStart.gifContractedSubBlock.gif  get flags() 
dot.gifreturn CI.nsIClassInfo.SINGLETON; },
InBlock.gif
InBlock.gif  
// nsIObserver
InBlock.gif
    observe: function(aSubject, aTopic, aData)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
switch(aTopic)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
case "xpcom-startup":
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
// this is run very early, right after XPCOM is initialized, but before
InBlock.gif
                // user profile information is applied. Register ourselves as an observer
InBlock.gif
                // for 'profile-after-change' and 'quit-application'
InBlock.gif
                //
InBlock.gif
        var obsSvc = CC["@mozilla.org/observer-service;1"].getService(CI.nsIObserverService);
InBlock.gif                obsSvc.addObserver(
this"profile-after-change"false);
InBlock.gif                obsSvc.addObserver(
this"quit-application"false);
InBlock.gif                
break;
ExpandedSubBlockEnd.gif      }

InBlock.gif
InBlock.gif      
case "profile-after-change":
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif                
// This happens after profile has been loaded and user preferences have been read.
InBlock.gif
                // startup code here
InBlock.gif
        this.initialize();
InBlock.gif        
break;
ExpandedSubBlockEnd.gif      }

InBlock.gif
InBlock.gif            
case "quit-application":
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif        
var obsSvc = CC["@mozilla.org/observer-service;1"].getService(CI.nsIObserverService);
InBlock.gif                obsSvc.removeObserver(
this"profile-after-change");
InBlock.gif                obsSvc.removeObserver(
this"quit-application");
InBlock.gif        
break;
ExpandedSubBlockEnd.gif      }

InBlock.gif
InBlock.gif            
default:
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif{
InBlock.gif                
this.onObserve(aSubject, aTopic, aData);
ExpandedSubBlockEnd.gif      }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif  }
,
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    get wrappedJSObject() 
dot.gifreturn this; }
ExpandedBlockEnd.gif}

None.gif
None.gif
//  ====================================================================================
None.gif//
 constructors for objects we want to XPCOMify
None.gif//
None.gif
var  gXpComObjects  =  [tBirdBiffUtility];
None.gif
var  gCatObserverName  =  tBirdBiffUtility.classDescription;  //  can be anything
None.gif
var  gCatContractID  =  tBirdBiffUtility.contractID;
None.gif
None.gif
//  **********
None.gif//
 generic registration code below. Useful URL: http://www.mozilla.org/projects/xpcom/book/cxc/html/weblock.html
None.gif//
 **********
None.gif
function  NSGetModule(compMgr, fileSpec)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    gModule._catObserverName 
= gCatObserverName;
InBlock.gif    gModule._catContractId 
= gCatContractID;
InBlock.gif
InBlock.gif    
for (var i in gXpComObjects)
InBlock.gif        gModule._xpComObjects[i] 
= new FactoryHolder(gXpComObjects[i]);
InBlock.gif
InBlock.gif    
return gModule;
ExpandedBlockEnd.gif}

None.gif
None.gif
function  FactoryHolder(aObj)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
this.classID = aObj.classID;
InBlock.gif    
this.contractID = aObj.contractID;
InBlock.gif    
this.className  = aObj.classDescription;
InBlock.gif    
this.factory =
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        createInstance: 
function(aOuter, aIID)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if (aOuter)
InBlock.gif                
throw CR.NS_ERROR_NO_AGGREGATION;
InBlock.gif
InBlock.gif            
return (new this.constructor).QueryInterface(aIID);
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }
;
InBlock.gif
InBlock.gif    
this.factory.constructor = aObj;
ExpandedBlockEnd.gif}

None.gif
None.gif
var  gModule  =
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    _xpComObjects: 
dot.gif{},
InBlock.gif    _catObserverName: 
null,
InBlock.gif    _catContractId: 
null,
InBlock.gif
InBlock.gif    registerSelf: 
function(aComponentManager, aFileSpec, aLocation, aType)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif    aComponentManager.QueryInterface(CI.nsIComponentRegistrar);
InBlock.gif        
for (var key in this._xpComObjects)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
var obj = this._xpComObjects[key];
InBlock.gif            aComponentManager.registerFactoryLocation(obj.classID, obj.className,
InBlock.gif            obj.contractID, aFileSpec, aLocation, aType);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif    
var catman = CC["@mozilla.org/categorymanager;1"].getService(CI.nsICategoryManager);
InBlock.gif        catman.addCategoryEntry(
"xpcom-startup"this._catObserverName, this._catContractId, truetrue);
InBlock.gif        catman.addCategoryEntry(
"xpcom-shutdown"this._catObserverName, this._catContractId, truetrue);
ExpandedSubBlockEnd.gif    }
,
InBlock.gif
InBlock.gif    unregisterSelf: 
function(aCompMgr, aFileSpec, aLocation)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif    
var catman = CC["@mozilla.org/categorymanager;1"].getService(CI.nsICategoryManager);
InBlock.gif        catman.deleteCategoryEntry(
"xpcom-startup"this._catObserverName, true);
InBlock.gif        catman.deleteCategoryEntry(
"xpcom-shutdown"this._catObserverName, true);
InBlock.gif
InBlock.gif    aComponentManager.QueryInterface(CI.nsIComponentRegistrar);
InBlock.gif        
for (var key in this._xpComObjects)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
var obj = this._xpComObjects[key];
InBlock.gif            aComponentManager.unregisterFactoryLocation(obj.classID, aFileSpec);
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }
,
InBlock.gif
InBlock.gif    getClassObject: 
function(aComponentManager, aCID, aIID)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif    
if (!aIID.equals(CI.nsIFactory))
InBlock.gif            
throw CR.NS_ERROR_NOT_IMPLEMENTED;
InBlock.gif
InBlock.gif        
for (var key in this._xpComObjects)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if (aCID.equals(this._xpComObjects[key].classID))
InBlock.gif                
return this._xpComObjects[key].factory;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
throw CR.NS_ERROR_NO_INTERFACE;
ExpandedSubBlockEnd.gif    }
,
InBlock.gif
InBlock.gif  canUnload: 
function(aComponentManager)
ExpandedSubBlockStart.gifContractedSubBlock.gif  
dot.gif{
InBlock.gif    
return true;
ExpandedSubBlockEnd.gif  }

ExpandedBlockEnd.gif}

None.gif
None.gif    
None.gif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值