| <?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><lock aspectratio="t" v:ext="edit"></lock></shapetype>
| Mozilla扩展系列链接: 1,浅谈基于Mozilla Thunderbird的扩展开发
2,基于Mozilla平台的扩展开发(续)----XPCOM组件篇 3,基于Mozilla Thunderbird的扩展开发(三)---如何获取邮件的完整信息 4,基于Mozilla Thunderbird的扩展开发(四)---修改源代码实现自动保存附件 5,基于Mozilla Thunderbird的扩展开发(五)---进程间通信之Socket篇(上) |
Mozilla最为人诟病的地方就是没有称手的开发工具,这对于我们这些被微软惯坏的开发人员来说,如果没有Visual Studio这样舒服的工具的话,谁会投入你的怀抱呢?本文就希望从三个方面介绍下我所了解到的Mozilla平台下的开发工具及一些小技巧。
最原始的方法当然是全部手工打造,从插件的编写,到打包,这样做的好处是对Mozilla平台下插件的开发有比较深入的了解,但缺点就是每次做一些小的修改后都需要重复进行压缩,打包等一系列繁杂的工序,如果你喜欢这种方法,可以参考我这篇文章:《浅谈基于Mozilla ThunderBird的扩展开发》,也可以参考Mozilla开发中心这篇文章《Building an Extension》。
每次修改代码后就得自己手动重新打包,发布,安装,你对这些已经感到厌烦了吗?好的,那就想办法脱离苦海吧。我们仔细分析后发现,就是一个打包的问题,因此我们就可以使用Ant来完成这些琐碎的打包工作,下面就是《浅谈基于Mozilla ThunderBird的扩展开发》中使用的build.xml文件:
<?
xmlversion="1.0"
?>
<
project
name
="helloworld"
default
="createxpi"
>
<
delete
file
="helloworld.xpi"
/>
<
delete
file
="helloworld.jar"
/>
<
target
name
="createjar"
>
<
zip
destfile
="helloworld.jar"
compress
="false"
>
<
fileset
dir
="chrome"
>
<
include
name
="content/**"
/>
</
fileset
>
</
zip
>
</
target
>

<
target
name
="createxpi"
depends
="createjar"
>
<
zip
destfile
="helloworld.xpi"
>
<
zipfileset
dir
="."
includes
="helloworld.jar"
prefix
="chrome"
/>
<
zipfileset
dir
="."
includes
="chrome.manifest"
/>
<
zipfileset
dir
="."
includes
="install.rdf"
/>
</
zip
>
</
target
>
</
project
>
如果你的项目结构比这个要复杂的话,请根据自己的需求更改此文件再使用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以及它的属性呢?这在做插件开发时是一个比较重要的方面,因为你的插件的界面就是附着在目标程序(firefox,thunderbird或sunbird)上的。那么官方推荐的工具就够用了,这个插件就是DOM Inspector,它可以用来定位你所需要的控件。
Venkman是官方推荐的调试工具,但个人感觉还是不大好用。
另外几个调试的技巧是:1)可以试用”dump语句来显示调试信息,不过这需要进行一些配置工作。2)在代码中使用nsIConsoleService 将日志信息输出到JavaScript控制台中。
3)自己编译一个debug版本的firefox或thunderbird,并且在其源代码或你的C++ XPCOM组件中设置断点,进一步的信息可以参考Mozilla开发中心的文档。
除此以外,我们也可以自己开发一个日志工具类来记录感兴趣的信息,下面是我常用的一个日志组件类:
constCI
=
Components.interfaces,CC
=
Components.classes,CR
=
Components.results;
tBirdBiffUtility.classID
=
Components.ID(
"
{e07f8540-831f-11db-9fe1-0800200c9a66}
"
);
tBirdBiffUtility.contractID
=
"
@phinecos.cnblogs.com/HelloWorld/utility;1
"
;
tBirdBiffUtility.classDescription
=
"
UtilityService
"
;
//
日志组件
function
tBirdBiffUtility()
{
this.consoleService=CC["@mozilla.org/consoleservice;1"].getService(CI.nsIConsoleService);//控制台服务
this.logFile=null;//日志文件对象
this.logToFile=true;//是否开启日志功能,默认为开启,插件发布后,关闭它就是
}

tBirdBiffUtility.prototype
=

{
initialize:function()

{//初始化
this.getLoggingPref();
},
closeLogFile:function()

{//关闭日志文件
if(this.logFile)

{
this.logFile.close(null);
}
},
openLogFile:function()

{//打开日志文件
this.closeLogFile();//关闭先前的日志文件
if(!this.logToFile)

{
return;
}
vartmpFile=CC["@mozilla.org/file/directory_service;1"]
.getService(CI.nsIProperties).get("TmpD",CI.nsILocalFile);
//构造日志文件名称
varfilename="HelloWorld";
if(this.isFirefox())

{
filename+="-firefox.log";
}
if(this.isSunbird())

{
filename+="-sunbird.log";
}
if(this.isThunderbird())

{
filename+="-thunderbird.log";
}
tmpFile.append(filename);
//创建不重名的日志文件
tmpFile.createUnique(CI.nsIFile.NORMAL_FILE_TYPE,0664);
this.logFile=CC["@mozilla.org/network/file-output-stream;1"]
.createInstance(CI.nsIFileOutputStream);
//write,create,truncate
this.logFile.init(tmpFile,0x02|0x08|0x20,0664,this.logFile.DEFAULT_REPLACEMENT_CHARACTER);
},
isFirefox:function()

{
if(this.getApplicationId()=="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}")

{
returntrue;
}
else

{
returnfalse;
}
},
isSunbird:function()

{
if(this.getApplicationId()=="{718e30fb-e89b-41dd-9da7-e25a45638b28}")

{
returntrue;
}
else

{
returnfalse;
}
},
isThunderbird:function()

{
if(this.getApplicationId()=="{3550f703-e582-4d05-9a08-453d09bdfdc6}")

{
returntrue;
}
else

{
returnfalse;
}
},
getLoggingPref:function()

{
//lookforanduseapreferenceifgiven
if(this.logToFile==true)

{//开启了日志功能
this.openLogFile();
this.logToConsole("tBirdBiffUtility.getLoggingPref","thunderbirdbiff.logToFilepreferencesettingis"+this.logToFile);
}
else

{//没有开启日志功能
this.logToConsole("tBirdBiffUtility.logToFile","Nothunderbirdbiff.logToFilepreferencesettingfound,usingFALSEdefault");
this.logToFile=false;
}
},
logError:function(source,message)

{//记录错误信息
varcallingFunction=source;
varerror=CC["@mozilla.org/scripterror;1"].createInstance(CI.nsIScriptError);
error.init(callingFunction+"():"+message,null,null,null,null,CI.nsIScriptError.errorFlag,null);
this.consoleService.logMessage(error);
this.log(source,"ERROR-"+message);
this.callingFunction=null;
this.error=null;
},
writeToLogFile:function(msg)

{//写入日志文件
if(this.logToFile)

{
this.logFile.write(msg+"/n",msg.length+1);
}
},
log:function(source,message)

{//日志功能
varmsg=source+"():/n/"+message;
try

{
this.writeToLogFile(msg);
}
catch(e)

{
varerrorMsg="Errortryingtowritelogfile:"+e+"--Openinganewfile/n";
this.logToConsole(errorMsg);
this.openLogFile();
if(this.logFile)

{
this.writeToLogFile(errorMsg);
this.writeToLogFile(msg);
}
errorMsg=null;
}
msg=null;
},
logToConsole:function(source,message)

{//写日志到控制台
varmsg=this.getAddonName()+"."+source+"():/n/"+message;
this.consoleService.logStringMessage(msg);
this.log(source,message);
msg=null;
},
getApplicationInfo:function()

{//获取目标程序信息
returnCC["@mozilla.org/xre/app-info;1"].getService(CI.nsIXULAppInfo);
},
getApplicationId:function()

{//获取目标程序id
if(!this.id)

{
this.id=this.getApplicationInfo().ID;
}
returnthis.id;
},
onObserve:function(subject,topic,data)

{
},
//nsISupports
QueryInterface:function(aIID)

{
if(aIID.equals(CI.nsISupports)||
aIID.equals(CI.nsIClassInfo)||
aIID.equals(CI.nsIObserver))

{
returnthis;
}
throwCR.NS_ERROR_NO_INTERFACE;
},
//nsIClassInfo
getInterfaces:function(aCount)

{
varifaces=newArray();
ifaces.push(CI.nsISupports);
ifaces.push(CI.nsIClassInfo);
ifaces.push(CI.nsIObserver);
aCount.value=ifaces.length;
returnifaces;
},
//nsIClassInfo
getHelperForLanguage:function(aLanguage)
{returnnull;},
getcontractID()
{returntBirdBiffUtility.contractID;},
getclassID()
{returntBirdBiffUtility.classID;},
getclassDescription()
{returntBirdBiffUtility.classDescription;},
getimplementationLanguage()
{returnCI.nsIProgrammingLanguage.JAVASCRIPT;},
getflags()
{returnCI.nsIClassInfo.SINGLETON;},
//nsIObserver
observe:function(aSubject,aTopic,aData)

{
switch(aTopic)

{
case"xpcom-startup":

{
//thisisrunveryearly,rightafterXPCOMisinitialized,butbefore
//userprofileinformationisapplied.Registerourselvesasanobserver
//for'profile-after-change'and'quit-application'
//
varobsSvc=CC["@mozilla.org/observer-service;1"].getService(CI.nsIObserverService);
obsSvc.addObserver(this,"profile-after-change",false);
obsSvc.addObserver(this,"quit-application",false);
break;
}
case"profile-after-change":

{
//Thishappensafterprofilehasbeenloadedanduserpreferenceshavebeenread.
//startupcodehere
this.initialize();
break;
}
case"quit-application":

{
varobsSvc=CC["@mozilla.org/observer-service;1"].getService(CI.nsIObserverService);
obsSvc.removeObserver(this,"profile-after-change");
obsSvc.removeObserver(this,"quit-application");
break;
}
default:

{
this.onObserve(aSubject,aTopic,aData);
}
}
},

getwrappedJSObject()
{returnthis;}
}

//
====================================================================================
//
constructorsforobjectswewanttoXPCOMify
//
var
gXpComObjects
=
[tBirdBiffUtility];
var
gCatObserverName
=
tBirdBiffUtility.classDescription;
//
canbeanything
var
gCatContractID
=
tBirdBiffUtility.contractID;
//
**********
//
genericregistrationcodebelow.UsefulURL:http://www.mozilla.org/projects/xpcom/book/cxc/html/weblock.html
//
**********
function
NSGetModule(compMgr,fileSpec)
{
gModule._catObserverName=gCatObserverName;
gModule._catContractId=gCatContractID;
for(variingXpComObjects)
gModule._xpComObjects[i]=newFactoryHolder(gXpComObjects[i]);
returngModule;
}

function
FactoryHolder(aObj)
{
this.classID=aObj.classID;
this.contractID=aObj.contractID;
this.className=aObj.classDescription;
this.factory=

{
createInstance:function(aOuter,aIID)

{
if(aOuter)
throwCR.NS_ERROR_NO_AGGREGATION;
return(newthis.constructor).QueryInterface(aIID);
}
};
this.factory.constructor=aObj;
}

var
gModule
=

{
_xpComObjects:
{},
_catObserverName:null,
_catContractId:null,
registerSelf:function(aComponentManager,aFileSpec,aLocation,aType)

{
aComponentManager.QueryInterface(CI.nsIComponentRegistrar);
for(varkeyinthis._xpComObjects)

{
varobj=this._xpComObjects[key];
aComponentManager.registerFactoryLocation(obj.classID,obj.className,
obj.contractID,aFileSpec,aLocation,aType);
}
varcatman=CC["@mozilla.org/categorymanager;1"].getService(CI.nsICategoryManager);
catman.addCategoryEntry("xpcom-startup",this._catObserverName,this._catContractId,true,true);
catman.addCategoryEntry("xpcom-shutdown",this._catObserverName,this._catContractId,true,true);
},
unregisterSelf:function(aCompMgr,aFileSpec,aLocation)

{
varcatman=CC["@mozilla.org/categorymanager;1"].getService(CI.nsICategoryManager);
catman.deleteCategoryEntry("xpcom-startup",this._catObserverName,true);
catman.deleteCategoryEntry("xpcom-shutdown",this._catObserverName,true);
aComponentManager.QueryInterface(CI.nsIComponentRegistrar);
for(varkeyinthis._xpComObjects)

{
varobj=this._xpComObjects[key];
aComponentManager.unregisterFactoryLocation(obj.classID,aFileSpec);
}
},
getClassObject:function(aComponentManager,aCID,aIID)

{
if(!aIID.equals(CI.nsIFactory))
throwCR.NS_ERROR_NOT_IMPLEMENTED;
for(varkeyinthis._xpComObjects)

{
if(aCID.equals(this._xpComObjects[key].classID))
returnthis._xpComObjects[key].factory;
}
throwCR.NS_ERROR_NO_INTERFACE;
},
canUnload:function(aComponentManager)

{
returntrue;
}
}



416

被折叠的 条评论
为什么被折叠?



