XPCOM

XPCOM是一個跨平台組件模型,它的全稱為Cross Platform Component Object Module。XPCOM實現了一個框架(framework),這個框架中,它允許開發者打破單一整體的軟體項目,而分解為多個更小的模組化碎片(pieces),這些碎片也即組件(components)。

XPCOM: Cross Platform Component Object Module 跨平台組件對象模組。基於Mozilla的瀏覽器現在可以通過使用跨平台組件對象模組(Cross Platform Component Object Module,XPCOM)組件添加它們自己的功能。XPCOM是一個框架,它允許對項目進行模組化設計,將整個開發劃分為多個組件。組件然後在運行時期重新裝配,創建出組件的克隆共同創建一個應用程式。
XPCOM 簡介
本文簡單介紹了 XPCOM 和組件開發的基本概念和技術. 本文的大部分內容從一個很高的角度介紹了這些概念, 這些概念將在創建一個稱為 WebLock 的 Mozilla 組件過程中逐漸透徹的講述.
XPCOM 解決方案
Cross Platform Component Object Module (XPCOM) 是一個允許開發人員把一個大的工程劃分成小的模組的框架. 這些小模組稱為組件, 它們在運行時刻組裝在一起.
XPCOM 的目標是使軟體的不同部分分別開發, 相互獨立. 為了是套用的不同組件之間能夠互操作, XPCOM 把組件的實現與接口(後面討論 接口) 分開. 同時 XPCOM 還提供了載入和操縱這些組件的庫和工具以及服務, 以幫助開發人員編寫跨平台的代碼和組件版本管理; 因此組件可以在不破壞套用或者重新生成套用的同時被替換被更新. 通過使用 XPCOM, 開發人員創建的組件可以在不同的套用中被重用, 或者替換當前套用中的組件以改變套用的功能.
XPCOM 不只提供組件軟體開發的支持, 它同時提供一個開發平台的大多數功能的支持:
組件管理
檔案抽象
對象訊息傳遞
記憶體管理
我們將在後面的章節中詳細討論上面的條目, 但是現在, 僅僅把 XPCOM 想像成一個 組件開發平台, 它提供了上面的這些特性.
Gecko
XPCOM 儘管在許多方面類似於 Microsoft COM, 但 XPCOM 被設計成主要套用於套用層. XPCOM 的最重要的套用是 Gecko, 一個開源的, 遵循標準的, 嵌入式 web 瀏覽器和 工具包.
XPCOM 是訪問 Gecko 庫和嵌入或擴展 Gecko 的方法. 本書著重於後者 - 擴展 Gecko - 但是本書中描述的基本思想對嵌入 Gecko 的開發人員也很重要.
Gecko 套用在許多 internet 程式中, 主要是瀏覽器. 包括 Gateway/AOL Instant AOL device 和 Nokia Media Terminal. Gecko 最近還被套用於的 Compuserve 客戶端, AOL for Mac OS X, Netscape 7, 當然還包括 Mozilla 客戶端. Gecko 是目前而言主流的開源瀏覽器.
組件
XPCOM 允許把一個大的工程分解為一些小部分. 這些小部分稱為組件, 通常是一些小的可重用的二進制庫(在 Windows 下表現為一個 DLL , Unix 下為一個 DSO ), 這些二進制庫可以包含一個或多個組件. 當多個相關組件被封裝到一個二進制庫, 這個庫也稱為模組.
把軟體劃分成不同的組件可以使開發和維護工作變得更容易. 除了這個好處, 模組化組件化的編程還有下面的優勢:
優點 描述
重用 模組化的代碼可以在其他套用和環境中被重用.
更新 在不需要重新編譯整個套用的情況下更新組件.
性能 代碼按照模組化組織, 模組就不必要立刻被載入, 而是以 "lazy" 方式載入, 或者根本不需要載入. 這樣就可以提升套用的整體性能.
維護 甚至在不更新組件的情況下, 按照模組化的方式設計套用也能夠使你對感興趣的部分的維護變得更容易.
Mozilla 有幾百萬行代碼, 沒有那個人能夠徹底搞明白整個代碼的細節. 面對這樣的一個系統, 最好的方式是把它劃分成一些小的, 更容易管理的部分; 同時使用組件模型來編程, 把相關組件組織到各個模組中去. 比如說, Mozilla 的網路庫就包含了 HTTP, FTP, 及其他協定的組件, 這些組件被塞到一個單獨的庫里. 這個庫就是網路模組, 也就是通常所說的 "necko."
但是把事物劃分開來並不一定就好, 有許多事物作為一個整體組織起來才是最好的方式, 或者根本就不能劃分開來. 比如說, 一個小孩就可能不吃沒有果醬的三明志, 對於他來說, 果醬和三明志是缺一不可的整體. 同樣的情形也會存在於某些軟體中, 某些需要緊耦合的僅僅在內部使用的部分就並不需要費力去把它拆開成為小的模組.
Gecko 中的 HTTP 組件並不會暴露它內部的類, 它是作為一個整體來使用. 組件內部的事物不應該暴露給 XPCOM. 在 Mozilla 早期的開發中, 有些組件的創建並不適當, 但是隨著開發的深入, 這些部分會被逐漸移出 XPCOM.
接口
把軟體劃分成組件通常一個好的解決方法, 但是我們該怎么做呢? 基本的思路是按照功能進行劃分, 理解這些功能塊之間的如何進行通信. 這些組件之間的通信通道就構成了各個組件的邊界, 這些邊界形式的描述為接口.
接口並不是編程中的一個新的概念. 從我們的第一個 "HelloWorld" 程式開始我們就一直在不知不覺的使用它, 這裡的接口就存在於我們的應用程式和列印程式之間. 應用程式使用 stdio 庫提供的接口來把 "hello world" 字元串列印到螢幕上. XPCOM 與 "HelloWorld" 程式的不同之處在於 XPCOM 會在運行時刻找到這個螢幕列印的功能, 而 XPCOM 事前根本就不需要在編譯的時刻了解 stdio 庫提供了什麼東西.
接口允許開發人員把功能的具體實現封裝在組件內部, 而客戶程式不需要了解這個功能是如何實現的, 它只需要使用它就行了.
接口與按照契約(Contract)編程
一個接口在組件與客戶程式之間達成契約. 並沒有任何強制措施保證認同這個契約, 但是忽略它會是致命的. 在基於組件的編程中, 組件保證它提供的接口是不變的 - 不同版本的組件都要提供同樣的訪問方法 - 這就與使用它的客戶程式達成了一種契約. 從這種角度來說, 基於組件的編程通常也稱為按照契約編程.
接口與封裝
組件邊界之間的抽象對軟體的可維護性與可重用性是致關重要的. 舉個例子來說, 考慮下面一個沒有很好封裝的類. 在下面的例子中, 使用可自由訪問的 public 的初始化方法可能會出問題.
SomeClass類初始化
class SomeClass{ public: // Constructor SomeClass(); // Virtual Destructor virtual ~SomeClass(); // init method void Init(); void DoSomethingUseful();};系統要工作正常, 客戶程式設計師必須注意到組件程式設計師建立的潛規則. 這就是這個未很好封裝的類的契約: 這是一套關於何時該調用一個方法, 調用這個方法之前應該做什麼的規則. 這個規則可能指出 DoSomethingUseful 方法只能在調用 Init() 之後被使用. DoSomethingUseful 方法可能會做某些檢查工作以保證條件滿足 - Init 已經被調用.
除了在代碼中給出注釋告訴客戶程式設計師關於 Init() 規則之外, 程式設計師可以使他的契約更明晰. 首先對象的構造函式可以封裝起來, 然後向客戶程式設計師提供一個聲明 DoSomethingUseful 方法的虛基類. 通過這種方式, 構造函式和初始化函式被隱藏起來. 在這種半封裝條件下, 這個類只向客戶程式暴露一些良好定義的可調用方法(或者稱為接口). 一旦按照這種方式封裝一個類, 客戶程式只能看到的是下面的接口:
SomeInterface封裝
class SomeInterface{ public: virtual void DoSomethingUseful() = 0;};實現類就可以從這個虛基類派生, 實現接口的功能. 客戶程式使用類廠(factory pattern)模式來創建對象(參看 類廠), 而封裝類的內部實現. XPCOM 以這種方式把客戶程式禁止在組件的內部工作之外, 而客戶程式也只依賴於提供所需要功能的接口.
nsISupports 基接口
組件與基於接口的編程的兩個最基本的問題是: 一個是組件生存期, 也稱為對象所屬關係; 另一個是接口查詢, 它是在運行時刻確定接口能夠提供哪些接口. 這一節介紹基接口 nsISupports - 它是 XPCOM 中所有接口的父接口, 它提供了上面兩個問題的解決方案.
對象所屬關係
在 XPCOM 中, 由於組件可以實現任意多的不同接口, 接口必須是引用計數的. 組件在內部跟蹤客戶程式對它的接口引用了多少次, 當接口計數為零的時候組件就會卸載它自己.
當一個組件創建後, 組件內部有一個整數在跟蹤這個引用計數值. 客戶程式實例化組件就會自動對這個引用計數加一; 在組件的整個生存期內, 引用計數或加或減, 總是大於零的. 如果在某個時刻, 所有的客戶程式對該組件都失去了興趣, 引用計數減到零, 組件就會卸載自己.
客戶程式使用相關接口是一個非常直接的過程. XPCOM 有一些工具讓我們更方便的使用接口, 我們會在後面講述. 如果客戶程式在使用接口的時候忘記對接口的引用計數進行相關操作, 就會對組件的維護工作帶來某些問題. 此時, 由於組件的引用計數始終不為零, 它就永遠不會釋放, 從而導致記憶體泄漏. 引用計數系統就象 XPCOM 的許多其他事物一樣, 是客戶與組件之間的契約. 如果遵守這些契約, 就會工作得很正常, 反之不然. 由創建接口指針的函式負責對初始化的接口引用加1, 這個引用也稱為所屬引用.
XPCOM中的指針
XPCOM 中的指針術語指的是接口指針. 它與常規指針相比有細微的差別, 畢竟它們都指向的是某個記憶體區域. 但是 XPCOM 指針指向的都是從 nsISupports 基接口派生而來的接口實現, 這個基接口包括三個基本的方法: AddRef, Release, 和 QueryInterface.
nsISupports 接口提供了對接口查詢與引用計數基本的支持. 這個接口的成員方法包括: QueryInterface, AddRef, 和 Release. 這些方法提供了從一個對象獲取正確接口的基本方法, 加引用計數, 釋放不再使用的對象. nsISupports 接口的聲明如下:
nsISupports 接口
class Sample: public nsISupports{ private: nsrefcnt mRefCnt; public: Sample(); virtual ~Sample(); NS_IMETHOD QueryInterface(const nsIID &aIID, void **aResult); NS_IMETHOD_(nsrefcnt) AddRef(void); NS_IMETHOD_(nsrefcnt) Release(void);};接口中使用的各種數據類型見 XPCOM 類型一節. nsISupports 接口的實現代碼如下:
nsISupports 接口實現
Sample::Sample(){ // initialize the reference count to 0 mRefCnt = 0;}Sample::~Sample(){}// typical, generic implementation of QINS_IMETHODIMP Sample::QueryInterface(const nsIID &aIID, void **aResult){ if (aResult == NULL) { return NS_ERROR_NULL_POINTER; } *aResult = NULL; if (aIID.Equals(kISupportsIID)) { *aResult = (void *) this; } if (*aResult == NULL) { return NS_ERROR_NO_INTERFACE; } // add a reference AddRef(); return NS_OK;}NS_IMETHODIMP_(nsrefcnt) Sample::AddRef() { return ++mRefCnt;}NS_IMETHODIMP_(nsrefcnt) Sample::Release(){ if (--mRefCnt == 0) { delete this; return 0; } // optional: return the reference count return mRefCnt;}對象接口的發現
繼承是面向對象編程中另一個非常重要的話題. 繼承是通過一個類派生另一個類的方法. 當一個類繼承另一個類, 繼承類可以重載基類的預設動作, 而不需要拷貝基類的代碼, 從而創建更加專有的類. 如下所示:
簡單類繼承
class Shape{ private: int m_x; int m_y; public: virtual void Draw() = 0; Shape(); virtual ~Shape();}; class Circle : public Shape{ private: int m_radius; public: virtual Draw(); Circle(int x, int y, int radius); virtual ~Circle();};Circle 從 Shape 類派生. Circle 本身也是一個 Shape, 但是 Shape 並不一定是 Circle. 在這種情況下, Shape 是基類, Circle 是 Shape 的子類.
在 XPCOM 中, 所有的類都派生自 nsISupports 接口, 這樣所有的對象都提供 nsISupports接口, 但是這些對象是更專有的類, 在運行時刻必須能找到它. 比如說在 簡單類繼承例子中, 如果對象是一個 Circle, 你就可以調用 Shape 類的方法. 就是為什麼在 XPCOM 中, 所有的對象都派生自 nsISupports 接口: 它允許客戶程式根據需要發現和訪問不同的接口.
在 C++ 中, 我們可以使用 dynamic_cast<> 來把一個 Shape 對象的指針強制轉化成一個 Circle 指針, 如果不能轉化就拋出異常. 但是在 XPCOM 中, 由於性能開銷和平台兼容性問題, 採用RTTI 的方法是不行的.
XPCOM 中的異常
XPCOM 並不直接支持 C++ 的異常處理. 在 XPCOM 中, 所有的異常必須在組件內部處理, 而不能跨越接口的邊界. 然後接口方法返回一個 nsresult 錯誤值(這些錯誤碼請參考 XPCOM API Reference). 客戶程式根據這些錯誤碼進行"異常"處理.
XPCOM 沒有採用 C++ RTTI 機制來實現對象指針的動態轉化, 它使用 QueryInterface 方法來把一個對象指針 cast 成正確的接口指針.
每個接口使用稱為 "uuidgen" 的工具來生成專有ID. 這個 ID 是一個全局唯一的 128-bit 值. 在接口的語境中, 這個 ID 又稱為 IID. (組件語境中, 這個 ID 代表的是一個契約)
當客戶程式想查詢一個對象是否支持某個接口, 它把接口的 IID 值傳遞給這個對象的 QueryInterface 方法. 如果對象支持這個接口, 它就會對自己的引用計數加1, 然後返回指向那個專有接口的指針. 反之, 如果不支持這個接口, 它會返回一個錯誤碼.
class nsISupports { public: long QueryInterface(const nsIID & uuid, void **result) = 0; long AddRef(void) = 0; long Release(void) = 0;};QueryInterface 的第一個參數是一個 nsIID 類型的引用, 它封裝了 IID. nsIID 類有三種方法: Equals, parse, 和 ToString. Equals 在接口查詢中是最重要的, 它用來比較兩個 nsIID 對象是否相同.
在客戶以 IID 調用 nsISupports 接口的 QueryInterface 方法時, 我們必須保證返回一個有效的 result 參數(在Using XPCOM Utilities to Make Things Easier 一章中, 我們將看到怎樣更方便的實現一個 nsIID 類). QueryInterface 方法應該支持該組件所有接口的查詢.
在 QueryInterface 方法的實現中, IID 參數與組件支持 nsIID 類進行比較. 如果匹配, 對象的 this 指針轉化為 void 指針, 引用計數加1, 把 void 指針返回給客戶程式.
在上面的例子中, 僅僅使用 C 方式的類型轉化就足夠了. 但是在把 void 指針 cast 成接口指針的時候, 還有更多的問題, 因為返回的接口指針必須與 vtable 相對應. 當出現菱形多重繼承的時候, 可能這種接口轉化就會有問題.
XPCOM 的ID
除了上一節中的接口 IID, XPCOM 還使用兩種 ID 來區分類與組件.
XPCOM ID類
nsIID 類實際上是一種 nsID 類. 其他的 nsID, CID 和 IID, 分別指的是一個實體類和一個專有的接口.
nsID 類提供 Equals 類似的方法, 來比較 ID. 請參考 Identifiers in XPCOM 一節, 其中對 nsID 類有更多的討論.
CID
CID 是一個唯一的 128-bit 值, 類似於 IID, 它用於全局標識唯一的類或者組件. nsISupports 的 CID 就象:
00000000-0000-0000-c000 000000000046
由於 CID 比較長, 通常我們都使用#define來定義它:
#define SAMPLE_CID \ { 0x777f7150, 0x4a2b, 0x4301, \ { 0xad, 0x10, 0x5e, 0xab, 0x25, 0xb3, 0x22, 0xaa}} 我們將會看到許多 NS_DEFINE_CID 的定義. 下面的宏用 CID 定義了一個靜態變數:
static NS_DEFINE_CID(kWebShellCID, NS_WEB_SHELL_CID);CID 有時也稱為類 ID. 如果一個類實現了多個接口, 當CID 在該類發布後, 就與該類的 IID 一起被凍結了.
契約 ID
契約 ID 是一個用於訪問組件的可讀(to humen)的字元串. 一個 CID 或者一個契約 ID 可以用於從一個組件管理器獲取組件. 下面是一個用於 LDAP 操作組件的契約 ID:
"@mozilla org/network/ldap-operation;1"契約 ID 的格式是: 用斜槓分開的組件的域, 模組, 組件名, 版本號.
與 CID 類似, 契約 ID 指的是組件實現而不是接口. 但是契約 ID 並不像CID那樣,被限定為某個專有實現, 它更通用. 一個契約 ID 只是指明需要實現的一組接口,可以通過任意數量的CID滿足這個需要. 契約 ID 與 CID 的這種不同, 使得組件重寫成為可能.
類廠
把代碼劃分成組件, 客戶代碼通常使用 new 操作符來構造實例對象:
SomeClass* component = new SomeClass();這種模式或多或少地需要客戶對組件有一定的了解,至少要知道組件的大小. 類廠設計模式此時可以用來封裝對象的構造過程. 類廠模式的目的是在不暴露對象的實現和初始化的前提下創建對象. 在 SomeClass 例子中, 可以按照類廠模式把 SomeClass 對象的構造和初始化封裝在 New_SomeInterface 函式中:
封裝構造函式
int New_SomeInterface(SomeInterface** ret){ // create the object SomeClass* out = new SomeClass(); if (!out) return -1; // init the object if (out->Init() == FALSE) { delete out; return -1; } // cast to the interface *ret = static_cast<SomeInterface*>(out); return 0; } 類廠本身是一個管理組件實例化的類. 在 XPCOM 中, 類廠要實現 nsIFactory 接口, 它們就象上面的代碼一樣要使用類廠設計模式來封裝對象的構造和初始化.
封裝構造函式 的例子是一個簡單的無狀態的類廠版本, 實際的編程要複雜一些, 一般的類廠都需要保存狀態. 類廠至少應該保存那些對象已經被創建了的信息. 如果類廠管理的實例被存放在一個動態聯接庫中, 還需要知道什麼時候可以卸載這個動態聯接庫. 當類廠保存了這樣的信息, 就可以向類廠查詢一個對象是否已經被創建.
另一個需要保存的信息是關於單件(singleton). 如果一個類廠已經創建了一個單件類型的類, 後續的創建該單件的函式調用將返回已經創建的對象. 儘管有更好的工具和方式來管理單件(在討論 nsIServiceManager 會看到), 開發人員可能仍然需要通過這種方式來保證只有一個單件對象被創建.
廠模式可以完全利用函式來做, 狀態可以保存在全局變數中; 但是使用類的方式來實現廠模式還有更多的好處. 其一是: 我們可以管理從 nsISupports 接口派生而來的類廠本身的生存期. 當我們試圖把多個類廠劃分成一組, 然後確定是否能卸載這一組類廠的時候, 這一點非常重要. 另一個好處是: 類廠可以引入其他需要支持的接口. 在我們後面討論 nsIClassInfo 接口的時候, 我們會看到某些類廠使用這個接口支持信息查詢, 諸如這個對象是用什麼語言寫的, 對象支持的接口等等. 這種派生自 nsISupports 的 "future-proofing" 特性非常關鍵.
XPIDL 與類型庫
定義接口的簡單而強勁的方法是使用接口定義語言(IDL) - 這實際上是在一個跨平台而語言無關開發環境下定義接口的需求. XPCOM 使用的是源自於 CORBA OMG 接口定義語言(IDL)的變體, 稱為 XPIDL, 來定義接口, XPIDL 可以定義接口的方法, 屬性, 常量, 以及接口繼承.
採用 XPIDL 定義接口還存在一些缺陷. 它不支持多繼承, 同時 XPIDL 定義的方法名不能相同,你不能有兩個相同名字但是所接受的參數不同的函式. - 不能像 C++ 語言的成員函式一樣通過參數不同重載, 畢竟接口同時要支持類似於 C 這樣的語言.
void FooWithInt(in int x);void FooWithString(in string x);void FooWithURI(in nsIURI x);然而儘管有這些問題, XPIDL 的功能仍然是非常強大的. XPIDL 能自動生成以 .xpt 為後綴的類型庫, 或者說 typelibs. 類型庫是接口的二進制表示, 它向非 C++ 語言提供接口的訪問與控制. 非 C++ 語言通過類型庫來了解接口支持哪些方法, 如何調用這些方法, 這稱為 XPConnect. XPConnect 是 XPCOM 向類似於 JavaScript 這樣的語言提供組件訪問的 Wrapper. 參看Connecting to Components from the Interface獲取更多關於 XPConnect 的信息.
從其他類型的語言訪問接口, 常常說成是接口被反射(reflected)到這種語言. 每一個被反射的接口必須提供相應的類型庫. 當前可以使用 C, C++, 和 JavaScript 來編寫組件.
使用其他語言編寫組件
在使用其他語言創建組件的時候, 不需要利用 XPCOM 提供給 C++ 程式設計師的工具(諸如一些宏, 智慧型指針等等, 我們可以方便的利用到這種語言本身來創建組件. 比如說, 基於 Python 的 XPCOM 組件可以從 JavaScript 來調用.
參看 Resources 獲取更多使用其他語言來創建組件的信息.
所有的 XPCOM 接口都用 XPIDL 語法來定義. xpidl 編譯器會從這個 IDL 檔案產生類型庫和 C++ 頭檔案. 在Defining the WebLock Interface in XPIDL 一節詳細描述了 XPIDL 語法.
XPCOM 服務
當客戶需要某個組件提供的功能的時候, 通常都是實例化一個新的組件對象. 比如說, 客戶程式需要某些處理檔案, 這裡每個組件就代表一個檔案, 客戶可能會同時處理多個這樣的組件.
但是在某些情況下對象表示的是一種服務, 這種服務只能有一個拷貝(儘管會有多個服務同時運行). 每次客戶程式訪問服務提供的功能時, 客戶程式都是與同一個服務實例在打交道. 比如說, 一個用戶查詢公司的電話號碼資料庫, 資料庫作為一個對象對用戶來說都是同一的. 如若不然的話, 就需要維護兩個資料庫拷貝, 這種開銷將非常大, 而且還存在數據內容不一致的問題. 單件設計模式就是提供系統中需要的這種單點訪問功能.
XPCOM 不僅提供了對組件的支持和管理服務, 它還包含了許多編寫跨平台組件所需要的其他服務. 其中包括: 跨平台檔案抽象, 向 XPCOM 開發人員提供同一而強大的檔案訪問功能. 目錄服務, 提供套用和特定系統定位信息. 記憶體管理, 保證所有對象使用同樣的記憶體分配器. 事件通知機制, 允許傳遞簡單訊息. 本教程將在後面展現如何使用這些服務, XPCOM API Reference 一節有完整的接口索引列表.
XPCOM 類型
XPCOM 聲明了許多數據類型和簡單宏, 這些東西將在我們後面的例子中看到. 大多數的宏都是簡單的重定義, 下一節我們會描述一些最常用的數據類型.
方法類型
下面的類型用在 XPCOM 方法調用的參數和返回值定義中.
NS_IMETHOD 聲明方法返回值. XPCOM 的方法預設的返回值聲明.
NS_IMETHODIMP 方法實現返回值. XPCOM 方法函式返回的時候缺省採用這種類型的返回值.
NS_IMETHODIMP_(type) 特定類型的方法實現返回值. 諸如 AddRef 和 Release 的方法不返回預設類型, 這種返回值的不一致雖然有點不舒服, 但是必需的.
NS_IMPORT 共享庫內部使用的符號局部聲明
NS_EXPORT 共享庫導出的符號聲明.
引用計數
下面的宏提供對引用計數的基本操作.
NS_ADDREF 調用 nsISupports 對象的 AddRef 方法.
NS_IF_ADDREF 與上一個方法類似, 不同之處在於這個宏在AddRef之前會檢查對象指針是否為空(虛函式指針).
NS_RELEASE 調用 nsISupports 對象的 Release 方法.
NS_IF_RELEASE 與上一個方法類似, 不同之處在於這個宏在調用Release之前會檢查空指針.
狀態碼
下面的宏測試狀態碼.
NS_FAILED 如果傳遞的狀態碼為失敗, 則返回真.
NS_SUCCEEDED 如果傳遞的狀態碼為成功, 則返回真.
變數映射
nsrefcnt 預設的引用計數類型, 是一個 32-bit 整數.
nsresult 預設數據類型, 是一個 32-bit 整數.
nsnull 預設 null 類型.
通用 XPCOM 錯誤碼
NS_ERROR_NOT_INITIALIZED 如果實例未初試化, 返回該值.
NS_ERROR_ALREADY_INITIALIZED 如果實例已初試化, 返回該值.
NS_ERROR_NOT_IMPLEMENTED 如果方法未實現, 返回該值.
NS_ERROR_NO_INTERFACE 如果組件不支持某種類型接口, 返回該值.
NS_ERROR_NULL_POINTER 如果指針指向 nsnull, 返回該值 .
NS_ERROR_FAILURE 如果某個方法失效, 返回該值, 這時一個通用的錯誤值.
NS_ERROR_UNEXPECTED 如果一個未預料的錯誤發生, 返回該值.
NS_ERROR_OUT_OF_MEMORY 如果無法進行記憶體分配, 返回該值.
NS_ERROR_FACTORY_NOT_REGISTERED 如果一個請求的類型未註冊, 返回該值.

相關詞條

相關搜尋

熱門詞條

聯絡我們