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

本文详细介绍XPCOM组件的开发过程,包括IDL定义、组件实现及在扩展中使用等关键步骤。通过一个简单的加法组件示例,帮助读者掌握XPCOM组件的开发技巧。

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

源代码下载:HelloWorld示例.rar


在《浅谈基于Mozilla ThunderBird的扩展开发》这篇入门文章中简单介绍了基于Mozllia平台进行扩展开发的基础知识,但仍然欠缺最为重要的一种武器---没错,XPCOM!这篇文章就是为它准备的。

XPCOM是什么?

      这个问题不多做解释了,相信XPCOM对于了解COM技术的人来说很快就可以上手开发了,下列是Mozilla官方给出的一些XPCOM知识的入门资源:

个人尤其推荐IBM developerworks上那5篇文章。

       使用已有的XPCOM

              XPCOM的使用十分简单,Mozilla平台已经为我们提供了许多功能强大的XPCOM组件了,如果你需要某方面功能的组件,请先看看Mozilla平台下是不是已经有对应的了,别再自己造轮子了

           关于这方面也不打算再多说了,有兴趣的朋友可以阅读IBM developerworks下面这篇文章,《实战 Firefox 扩展开发》,相信通过这样一个图片批量下载工具的开发,就会对于Mozilla平台下已有的XPCOM组件的使用有所了解的。


     So,what's next? 

    没错,自己如何开发XPCOM组件并在扩展中使用。网上对于这方面的资料不是很多,而且没有特别完整的示例,这就是我写这篇文章的目的所在,通过一个简单的XPCOM组件的开发全过程,展示XPCOM组件的内部细节。

       项目目标:

组件要实现的功能非常简单,就只提供一个做加法的接口供客户调用。

 long Add(in long a, in long b);

然后在扩展中调用这个加法接口。

 

准备工作

 

0,按照《浅谈基于Mozilla ThunderBird的扩展开发》这篇文章建立起开发扩展的基本环境。  

1、下载Gecko SDK

http://ftp.mozilla.org/pub/mozilla.org/mozilla/releases/mozilla1.8b1/gecko-sdk-i586-pc-msvc-1.8b1.zip 我们需要使用它来对IDL定义进行解释。

2、创建GUID

使用微软的的guidgen 生成GUID,例如b7b04070-45fc -4635- b219-7a172f806bee

4,从C:\mozilla-build\moztools-180compat\bin下拷贝libIDL-0.6.dllglib-1.2.dll\gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\bin下,否则运行xpidl会报错.

开发XPCOM组件

1,创建接口文件定义

None.gif #include  " nsISupports.idl "
None.gif[scriptable, uuid(b7b04070
- 45fc  - 4635 -  b219 - 7a172f806bee)]
None.gif
interface  IMyComponent : nsISupports
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif  
long Add(in long a, in long b);
ExpandedBlockEnd.gif}
;
None.gif

2、使用Gecko SDK xpidl.exe
      
进入xpidl所在目录,在CMD中输入命令

None.gif xpidl -m header -I  ..\ idl  IMyComponent . idl(这里应该是IDL定义文件的实际路径)
None.gifxpidl -m typelib -I 
..\ idl  IMyComponent . idl
None.gif

如果上面执行有问题的话,可以将

None.gif\gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\bin;\gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\idl;\gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\include;

加入到环境变量的PATH里面去     

如果上述命令执行通过,在\gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\bin就会得到IMyComponent.hIMyComponent.xpt 2个文件。

2、创建新文件

根据IMyComponent.h创建文件MyComponent.hMyComponent.cppMyComponentModule.cpp

ExpandedBlockStart.gif ContractedBlock.gif /**/ /* MyComponent.h*/
None.gif
None.gif
#pragma  once
None.gif
None.gif#ifndef _MY_COMPONENT_H_
None.gif
#define  _MY_COMPONENT_H_
None.gif
None.gif#include 
" IMyComponent.h "
None.gif
#define  MY_COMPONENT_CONTRACTID "@mydomain.com/XPCOMSample/MyComponent;1"
None.gif
#define  MY_COMPONENT_CLASSNAME "A Simple XPCOM Sample"
None.gif
#define  MY_COMPONENT_CID  {0xb7b04070, 0x45fc, 0x4635,{ 0xb2, 0x19, 0x7a, 0x17, 0x2f, 0x80, 0x6b, 0xee } }
None.gif
None.gif
None.gif
class  MyComponent: public  IMyComponent
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif    NS_DECL_ISUPPORTS
InBlock.gif    NS_DECL_IMYCOMPONENT
InBlock.gif    MyComponent(
void);
InBlock.gif    
~MyComponent(void);
ExpandedBlockEnd.gif}
;
None.gif
#endif
None.gif

None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ /* MyComponent.cpp*/
None.gif#include 
" StdAfx.h "
None.gif#include 
" MyComponent.h "
None.gif
None.gifNS_IMPL_ISUPPORTS1(MyComponent, IMyComponent)
None.gif
None.gifMyComponent::MyComponent(
void )
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedBlockEnd.gif}

None.gif
None.gifMyComponent::
~ MyComponent( void )
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedBlockEnd.gif}

None.gif
None.gifNS_IMETHODIMP MyComponent::Add(PRInt32 a, PRInt32 b, PRInt32 
* _retval)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
*_retval = a + b;
InBlock.gif    
return NS_OK;
ExpandedBlockEnd.gif}

None.gif


ExpandedBlockStart.gif ContractedBlock.gif /**/ /* MyComponentModule.cpp*/
None.gif#include 
" StdAfx.h "
None.gif#include 
" nsIGenericFactory.h "
None.gif#include 
" MyComponent.h "
None.gif
None.gifNS_GENERIC_FACTORY_CONSTRUCTOR(MyComponent)
None.gif
None.gif
static  nsModuleComponentInfo components[]  =
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        MY_COMPONENT_CLASSNAME, 
InBlock.gif        MY_COMPONENT_CID,
InBlock.gif        MY_COMPONENT_CONTRACTID,
InBlock.gif        MyComponentConstructor,
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}
;
None.gif
None.gifNS_IMPL_NSGETMODULE(
" MyComponentsModule " , components) 
None.gif

编译XPCOM组件

1、创建工程

使用VC2005,创建新的DLL工程,将IMyComponent.h MyComponent.hMyComponent.cppMyComponentModule.cpp添加到工程中。

 

2、工程配置

None.gif1)c/c++ GeneralAdditional Include Directories 中设置为\gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\include
None.gif
2) c/c++Preprocessor Preprocessor Definitions中加入MYCOMPONENT_EXPORTS,XPCOM_GLUE
None.gif
3)c/c++Code GenerationRuntime Library中设置为Multi-threaded DLL (/MD)
None.gif
,这里非常重要,否则编译会报错的!!。
None.gif
4)LinkerAdditional Liberary Directoryse设置为\gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\lib
None.gif
5)Linker Additional Depenendies加入nspr4.lib plds4.lib plc4.lib xpcomglue.lib
None.gif

3、编译生成MyComponent.dll

在扩展中使用XPCOM组件

 

对《浅谈基于Mozilla ThunderBird的扩展开发中的helloworld项目进行修改,加入一个文件夹components和一个安装文件install.js
2008042501.jpg

   关于这两个东西具体的含义这里就不多做介绍了,简单点说
,intall.js就是把XPCOM组件注册到Mozilla平台中去,就类似于Windows的注册表一样,从而可以使用组件。

1Install.js的内容:

None.gif// Install script for helloworld
None.gif

None.gif
var err;
None.gifconst APP_VERSION
="0.0.0.1";//版本号
None.gif

None.gif
//初始化安装
None.gif
err = initInstall("helloworld"+APP_VERSION,  // name for install UI
None.gif
                  "/helloworld",               // registered name
None.gif
                  APP_VERSION);              // package version
None.gif
if(err!=0)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{//安装出错,取消安装
InBlock.gif
    cancelInstall(err);
ExpandedBlockEnd.gif}

None.gif
None.gif
//标准目录
None.gif
var fProgram = getFolder("Program");//程序根目录 
None.gif
var fChrome     = getFolder("Chrome");//chrome目录
None.gif
var fComponents = getFolder("Components");//components目录
None.gif

None.gif
// workaround for Mozilla 1.8a3 and newer, failing to register enigmime correctly
None.gif
var delComps = [ "compreg.dat" ]; // Components registry
None.gif
for (var j=0; j<delComps.length; j++)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif     
var delFile = getFolder(fComponents, delComps[j]);
InBlock.gif     
if (File.exists(delFile))
InBlock.gif        File.remove(delFile);
ExpandedBlockEnd.gif}

None.gif
None.giferr 
= getLastError();
None.gif
if (err == DOES_NOT_EXIST)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
// error code: file does not exist
InBlock.gif
    resetError();
ExpandedBlockEnd.gif}

None.gif
else if (err != SUCCESS) 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    cancelInstall(err);
ExpandedBlockEnd.gif}

None.gif
None.gif
// addDirectory: blank, archive_dir, install_dir, install_subdir
None.gif
addDirectory("""components",    fComponents, "");
None.gifaddDirectory(
"""chrome",        fChrome,     "");
None.gif
None.gif
None.giferr 
= getLastError();
None.gif
if (err == ACCESS_DENIED)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    alert(
"Unable to write to components directory "+fComponents+".\n You will need to restart the browser with administrator/root privileges to install this software. After installing as root (or administrator), you will need to restart the browser one more time, as a privileged user, to register the installed software.\n After the second restart, you can go back to running the browser without privileges!");
InBlock.gif    cancelInstall(ACCESS_DENIED);
InBlock.gif
ExpandedBlockEnd.gif}
 
None.gif
else if (err != SUCCESS)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    cancelInstall(err);
InBlock.gif
ExpandedBlockEnd.gif}
 
None.gif
else 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
// Register chrome
InBlock.gif
    registerChrome(PACKAGE | DELAYED_CHROME, getFolder("Chrome","helloworld.jar"), "content/helloworld/");
InBlock.gif    err 
= getLastError();
InBlock.gif    
if (err != SUCCESS)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      cancelInstall(err);
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif      performInstall();
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

2)在Componts文件夹中加入MyComponent.dllIMyComponent.xpt


3
)修改overlay.js如下:

None.gif //  This is the main function
None.gif
const ENIG_C  =  Components;
None.gifconst ENIG_ENIGMAIL_CONTRACTID 
=   " @mydomain.com/XPCOMSample/MyComponent;1 "
None.gif
var  gEnigmailSvc  =   null ;
None.gif
None.gif
function  helloWorld()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
try
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        alert(
"准备创建组件");
InBlock.gif        gEnigmailSvc 
= ENIG_C.classes[ENIG_ENIGMAIL_CONTRACTID].createInstance(ENIG_C.interfaces.IMyComponent);//创建实例
InBlock.gif
        if(gEnigmailSvc!=null)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            alert(
"创建组件成功");
InBlock.gif            gEnigmailSvc 
= gEnigmailSvc.QueryInterface(ENIG_C.interfaces.IMyComponent);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
else
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            alert(
"创建组件失败");
InBlock.gif            
return;
ExpandedSubBlockEnd.gif        }
    
InBlock.gif        
var res = gEnigmailSvc.Add(34);
InBlock.gif        alert(
'Performing 3+4. Returned ' + res + '.');
InBlock.gif        alert(
"创建结束");
ExpandedSubBlockEnd.gif    }

InBlock.gif    
catch(ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        alert(
"error");
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif


好了,到此就完成了这个最简单的
XPCOM组件的开发了,enjoy it!

Reference


1,VCXPCOM

2, http://enigmail.mozdev.org/home/index.php


需要完整代码的,请发email至 phinecos@163.com,也欢迎有兴趣的朋友们一起来交流Mozilla的扩展开发技术

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值