Thunderbird extensions Weishin Pan 2010/08/26 OutLine • • • • Introduction XPCOM Demo Reference 2 Introduction • XUL (XML User Interface Language) Mozilla以XML為基礎所發展的語言,用來描述用戶介面 • CSS (Cascading Style Sheets) 使用者自定規則來控制HTML/XUL/XML所產生的介面外觀,背景,字型 • DOM(Document Object Model) 給予HTML與XML所使用的API,可以用來連結JavaScript或其他的程式語言與網頁 3 • XPConnect 將XPCOM與JavaScript連接起來的技術 • XBL (Extensible Binding Language) 一種標記語言,應用於各個XUL應用程式當中 • RDF (Resource Definition Framework) 透過這個格式來存放Extension的註冊訊息與描述資訊 • JavaScript 開發extension的核心語言,這種腳本語言的特色為其原始碼在送到用戶端前不須經過編 譯,而是透過Browser來解釋其字元代碼並執行 • XPInstall Mozilla 的跨平台安裝技術,提供了一個標準的方式將 XUL 應用程式的各個元件包裝成安 裝檔,讓 Mozilla users 可以下載並且安裝執行,以 XPI 格式為標準。XPI 的格式同 ZIP 及 JAR,為 PKZIP 壓縮後的檔案,只是內含可供管理安裝方式的腳本 4 XPCOM (Cross-platform Component Object Model) • 它是個用來撰寫跨平台與軟體模組化的一種架構,有自身的 API,定義著所提供的核心元件,介面與函式,與Microsoft所推 出的COM( Common Object Model)屬相同性質,透過介面 (Interface)的概念,來解決不同階段所開發的Components在 相容性問題以及系統的需求 • 透過XPIDL(Interface Description Language)的定義可使其 XPCOM物件可使用C、C++ 和 JavaScript 來創造,也可以在 C、C++、JavaScript、Python、與 Perl 擴充集的環境下來進 行開發 5 Mozilla application model User Interface layer Glue layer XPCOM layer 6 XPconnect • XPConnect 建立XPCOM物件 與 JavaScript 之 間的溝通 • XPConnect 允許 JavaScript 物件存取與運用 XPCOM 物件,也能使 JavaScript 物件可以表 示成 XPCOM 相容介面以供 XPCOM 物件呼 叫使用 7 http://m-alexandre.developpez.com/articles/xul/presentation/#note2 8 Environment OS : Windows XP SP3 MUA : Thunderbird2 (v2.0.0.9) (Win32) ftp://ftp.mozilla.org/pub/mozilla.org/thunderbird/releases/2.0.0.9/win32/en-US/Thunderbird%20Setup%202.0.0.9.exe (Source) ftp://ftp.mozilla.org/pub/mozilla.org/thunderbird/releases/2.0.0.9/source/thunderbird-2.0.0.9-source.tar.bz2 SDK: gecko-sdk-i586-pc-msvc-1.8b1 http://ftp.mozilla.org/pub/mozilla.org/mozilla/releases/mozilla1.8b1/gecko-sdk-i586-pc-msvc-1.8b1.zip Mozilla builder http://ftp.mozilla.org/pub/mozilla.org/mozilla/libraries/win32/MozillaBuildSetup-Latest.exe IDE: Visual studio 2005 9 Hello world • helloworld/ chrome.manifest -> Tells thunderbird where your chrome files(UI) are and what to do with them install.rdf -> The description file for your extension ("Install manifest") helloworld.xpi -> Installing package chrome/ helloworld.jar/ content/ contents.rdf -> The information file for package and overlay overlay.js -> The file with scripts to run in the browser window overlay.xul -> The file describing UI elements to add to the browser window 10 Chrome.manifest overlay content chrome://messenger/content/mailWindowOverlay.xul chrome://helloworld/content/overlay.xul helloworld jar:chrome/helloworld.jar!/content/ 11 Install.rdf <?xml version="1.0"?> <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> <Description about="urn:mozilla:install-manifest"> <em:id>{241b5bc7-a8aa-44a6-a18d-3054dc6047cf}</em:id> <em:name>Hello World</em:name> <em:version>1.0</em:version> <em:type>2</em:type> <em:creator>Weishin Pan</em:creator> <em:description>The classical demo with "Hello, world!"</em:description> <em:homepageURL>http://kb.mozillazine.org/Getting_started_with_extension_development</em:homepa geURL> <em:targetApplication> <!-- Thunderbird --> <Description> <em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id> <em:minVersion>2.0</em:minVersion> <em:maxVersion>2.0.0.*</em:maxVersion> </Description> </em:targetApplication> <!-- This is not needed for Firefox 1.1 and later. Only include this if you want to make your extension compatible with older versions --> <em:file> <Description about="urn:mozilla:extension:file:helloworld.jar"> <em:package>content/</em:package> </Description> </em:file> </Description> </RDF> 12 Contents.rdf <?xml version="1.0"?> <RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:chrome="http://www.mozilla.org/rdf/chrome#"> <RDF:Seq about="urn:mozilla:package:root"> <RDF:li resource="urn:mozilla:package:helloworld"/> </RDF:Seq> <!-- package information --> <RDF:Description RDF:about="urn:mozilla:package:helloworld" chrome:name="helloworld" chrome:extension="true" chrome:displayName="Hello World" chrome:author="Lewis Lv" chrome:authorURL="http://kb.mozillazine.org/Getting_started_with_extension_development" chrome:description="The Classical Demo With Hello World"> </RDF:Description> <!-- overlay information --> <RDF:Seq about="urn:mozilla:overlays"> <RDF:li resource="chrome://messenger/content/mailWindowOverlay.xul"/> </RDF:Seq> <RDF:Seq about="chrome://messenger/content/mailWindowOverlay.xul"> <RDF:li>chrome://helloworld/content/overlay.xul</RDF:li> </RDF:Seq> </RDF:RDF> 13 Overlay.js // This is the main function function helloWorld() { alert(“Hello world"); } 14 Overlay.xul <?xml version="1.0"?> <overlay id="helloworld-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/x-javascript" src="overlay.js"/> <menubar id="mail-menubar"> <menu id="MyAboutMenu" label="Test" insertbefore="tasksMenu"> <menupopup id="menu_TestAbout"> <menuitem id="helloworld-hello" label="Hello, world!" oncommand="helloWorld();"/> </menupopup> </menu> </menubar> </overlay> 15 helloworld.xpi • 壓縮 content資料夾成helloworld.zip,接著更改檔案類型為 .jar • 接著將chrome資料夾以及chrome.manifest,install.rdf壓縮成 helloworld.zip,街著將檔案類型改成.xpi以進行後續的安裝 16 Installation 開啟thunderbird,”Tools” -> “Add-ons” -> “Install …” -> 選擇套件目錄 -> 選擇xxx.xpi來進行安裝 -> 安裝成功後,重新開啟thunderbird -> 在工作列上可以看到 “test”的項目 -> 點選執行 17 18 Hello world (2) • Implantation an add() function for thunderbird • helloworld/ chrome.manifest -> Tells thunderbird where your chrome files(UI) are and what to do with them install.rdf -> The description file for your extension ("Install manifest") install.js -> Register the package helloworld.xpi -> Installing package chrome/ helloworld.jar/ content/ contents.rdf -> The information file for package and overlay overlay.js -> The file with scripts to run in the browser window overlay.xul -> The file describing UI elements to add to the browser window components/ helloworld.dll -> C++ Source code contains add() function IMycomponent.xpt -> IDL in binary code 19 開發環境設定 1. Copy C:\mozilla-build\moztools-180compat\bin\ libIDL-0.6.dll and glib1.2.dll 2. To \gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\bin 20 3. Create \gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\bin\Imycomponent.idl #include "nsISupports.idl" [scriptable, uuid(b7b04070-45fc -4635- b219-7a172f806bee)] interface IMyComponent : nsISupports { long Add(in long a, in long b); }; 4. Open visual studio 2005 -> “Tools” -> 建立GUID 21 XPCOM Component 22 • 在COM的IUnknown和XPCOM的nsISupports interface,它們的 基本目的是一樣的,要求所有的Component都應該實作 IUnknown/nsISupports interface, 接著user可以透過 QueryInterface()這個函式來得知這個Component是否支援” 某個版本的介面”的資訊 // For M$ COM interface IUnknown { virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) = 0; virtual ULONG AddRef(void) = 0; virtual ULONG Release(void) = 0; }; // For XPCOM interface nsISupports { void QueryInterface(in nsIIDRef uuid, out nsQIResult result); nsrefcnt AddRef(); nsrefcnt Release(); }; 23 5. Add Gecko-sdk path to windows PATH PATH -> …;\gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\bin;\gecko-sdk-i586-pc-msvc-1.8b1\geckosdk\idl;\gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\include; 6. Execute Xpidl.exe in command line(CMD) xpidl -m header -I ..\idl IMyComponent.idl xpidl -m typelib -I ..\idl IMyComponent.idl -> Create IMyComponent.h -> Create IMyComponent.xpt 24 7. Create a VC project for .dll (helloworld) and set the properties 1. c/c++ -> General Additional Include Directories add -> \gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\include 2. c/c++ -> Preprocessor -> Preprocessor Definitions add -> MYCOMPONENT_EXPORTS,XPCOM_GLUE 3. c/c++ -> Code Generation Runtime Library -> Multi-threaded DLL (/MD) 4. Linker-> Additional Liberary Directoryse add -> \gecko-sdk-i586-pc-msvc-1.8b1\gecko-sdk\lib 5. Linker-> Additional Depenendies add -> nspr4.lib plds4.lib plc4.lib xpcomglue.lib 6. Build in “Release” mode 25 /* MyComponent.h*/ #pragma once #ifndef _MY_COMPONENT_H_ #define _MY_COMPONENT_H_ #include "IMyComponent.h" #define MY_COMPONENT_CONTRACTID "@mydomain.com/XPCOMSample/MyComponent;1" #define MY_COMPONENT_CLASSNAME "A Simple XPCOM Sample" #define MY_COMPONENT_CID {0xb7b04070, 0x45fc, 0x4635,{ 0xb2, 0x19, 0x7a, 0x17, 0x2f, 0x80, 0x6b, 0xee } } class MyComponent:public IMyComponent { public: NS_DECL_ISUPPORTS NS_DECL_IMYCOMPONENT MyComponent(void); ~MyComponent(void); }; #endif 26 /* MyComponent.cpp*/ #include "StdAfx.h" #include "MyComponent.h" NS_IMPL_ISUPPORTS1(MyComponent, IMyComponent) MyComponent::MyComponent(void) { } MyComponent::~MyComponent(void) { } NS_IMETHODIMP MyComponent::Add(PRInt32 a, PRInt32 b, PRInt32 *_retval) { *_retval = a + b; return NS_OK; } 27 /* MyComponentModule.cpp*/ #include "StdAfx.h" #include "nsIGenericFactory.h" #include "MyComponent.h" NS_GENERIC_FACTORY_CONSTRUCTOR(MyComponent) static nsModuleComponentInfo components[] = { { MY_COMPONENT_CLASSNAME, MY_COMPONENT_CID, MY_COMPONENT_CONTRACTID, MyComponentConstructor, } }; NS_IMPL_NSGETMODULE("MyComponentsModule", components) 28 7. Generate a helloworld.dll 8. Add helloworld.dll and IMyComponent.xpi to dictionary “components” 29 Install.js // Install script for helloworld var err; const APP_VERSION="0.0.0.1";// Version //Initiation err = initInstall("helloworld"+APP_VERSION, // name for install UI "/helloworld", // registered name APP_VERSION); // package version if(err!=0) {// CancelInstall cancelInstall(err); } //Standard dictionary var fProgram = getFolder("Program");// root dictionary var fChrome = getFolder("Chrome");//chrome dictionary var fComponents = getFolder("Components");//components dictionary // workaround for Mozilla 1.8a3 and newer, failing to register enigmime correctly var delComps = [ "compreg.dat" ]; // Components registry for (var j=0; j<delComps.length; j++) { var delFile = getFolder(fComponents, delComps[j]); if (File.exists(delFile)) File.remove(delFile); } err = getLastError(); if (err == DOES_NOT_EXIST) { // error code: file does not exist resetError(); } else if (err != SUCCESS) { cancelInstall(err); } 30 Install.js(2) // addDirectory: blank, archive_dir, install_dir, install_subdir addDirectory("", "components", fComponents, ""); addDirectory("", "chrome", fChrome, ""); err = getLastError(); if (err == ACCESS_DENIED) { 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!"); cancelInstall(ACCESS_DENIED); } else if (err != SUCCESS) { cancelInstall(err); } else { // Register chrome registerChrome(PACKAGE | DELAYED_CHROME, getFolder("Chrome","helloworld.jar"), "content/helloworld/"); err = getLastError(); if (err != SUCCESS) { cancelInstall(err); } else { performInstall(); } } 31 overlay.js const PHINECOS_C = Components; const PHINECOS_HELLOWORLD_CONTRACTID = "@mydomain.com/XPCOMSample/MyComponent;1" var gHelloWorldSvc = null; // This is the main function function helloWorld() { try { alert("Component Installing"); gHelloWorldSvc = PHINECOS_C.classes[PHINECOS_HELLOWORLD_CONTRACTID].createInstance(PHINECOS_C.interfaces.IMyCo mponent); //Instance if(gHelloWorldSvc!=null) { alert("Success"); gHelloWorldSvc = gHelloWorldSvc.QueryInterface(PHINECOS_C.interfaces.IMyComponent); } else { alert("Fail"); return; } var res = gHelloWorldSvc.Add(6, 2); alert('Performing 6+2. Returned ' + res + '.'); alert("Exit"); } catch(ex) { alert("error"); } } 32 helloworld.xpi • 壓縮 content資料夾成helloworld.zip,接著更改檔案類型為.jar • 接著將chrome和components資料夾以及 chrome.manifest,install.rdf,install.js壓縮成helloworld.zip,接著將檔案類 型改成.xpi以進行後續的安裝 33 • • • • • • • • • • • • • • Reference http://www.cnblogs.com/phinecos/archive/2008/04/25/1171614.html Thunderbird extension(1) http://www.cnblogs.com/phinecos/archive/2008/04/21/1164466.html Thunderbird extension(2) https://developer.mozilla.org/zh_tw/XPCOM Mozilla.org XPCOM https://developer.mozilla.org/en/building_an_extension#XPCOM_Components Create a XPCOM https://developer.mozilla.org/en/Extensions/Thunderbird/Building_a_Thunderbird_extension Build thunderbird http://starkravingfinkle.org/blog/2006/10/mozilla-platform-xpcom-in-c/ XPCOM in c++ http://www.csie.ntu.edu.tw/~piaip/docs/CreateMozApp/index.html E Books for Mozilla developer http://www.cnblogs.com/chio/archive/2007/09/26/907245.html XPIDL http://rintarou.dyndns.org/2010/05/02/why-common-object-model-com/#more-441 XPCOM & COM http://blog.csdn.net/SystemBug/archive/2006/02/28/612053.aspx XPIDL https://developer.mozilla.org/zh_tw/The_Joy_of_XUL XUL http://hi.baidu.com/kinsonhe/blog/item/b39dbcefd2ad454379f0555a.html XPCOM http://kb.mozillazine.org/Getting_started_with_extension_development extension development ftp://ftp.mozilla.org/pub/ Mozilla resource 34