diff options
Diffstat (limited to 'files/zh-cn/mozilla/tech/xpcom/guide')
17 files changed, 0 insertions, 6306 deletions
diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/arrays/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/arrays/index.html deleted file mode 100644 index 53939ba6c0..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/arrays/index.html +++ /dev/null @@ -1,573 +0,0 @@ ---- -title: Array -slug: Mozilla/Tech/XPCOM/Guide/Arrays -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Arrays ---- -<p> </p> -<h2 id="Introduction" name="Introduction">Introduction</h2> -<h4 id="Array_types" name="Array_types">Array types</h4> -<p>Mozilla has many array classes because each array is optimized for a particular usage pattern. This guide describes the available arrays as well as the enumerator classes that can be used to get to them. In this document the term Array refers to a container for multiple objects with a numeric, zero-based index.</p> -<p>The standard array classes are:</p> -<ul> - <li><code><a href="#nsIArray_.2F_nsIMutableArray">nsIArray</a></code> - a scriptable container for scriptable XPCOM objects. This array is read-only, and the interface does not provide any methods that will allow adding and removing members.</li> - <li><code>nsIMutableArray</code> - a scriptable container for scriptable XPCOM objects, which allows addition and removal of member objects. This interface actually derives from nsIArray.</li> - <li><code>nsCOMArray<span class="nowiki"><T></span></code> - a C++ class which provides a typesafe, reference-counted container for pointers to a single type of COM object. This class is more or less a wrapper around nsVoidArray and thus shares most of its semantics.</li> - <li><code>nsTArray<span class="nowiki"><T></span></code> - a C++ class which provides a typesafe container for objects or primitive types (pointers, integers, etc). The objects must define a default constructor and a copy constructor. To use <code>IndexOf</code> without providing a comparator, they must also define an <code>operator==</code>. For sorting without providing a comparator they must define an <code><span class="nowiki">operator<</span></code>. Note that this class differs from the other array types by using unsigned indices.</li> - <li><code>nsVoidArray</code> - a C++ class which provides a generic container for any objects using the generic void * type.</li> - <li><code>nsStringArray</code> / <code>nsCStringArray</code> - a set of C++ classes for holding lists of string objects. Derived from nsVoidArray</li> - <li><code>nsAutoVoidArray</code> - a version of nsVoidArray which includes 8 entries of internal storage for the array data.</li> - <li><code>nsSmallVoidArray</code> - a replacement for nsVoidArray which is optimized to hold zero or one element.</li> -</ul> -<p>This handy chart may make it easier to understand the different arrays:</p> -<table class="fullwidth-table"> - <tbody> - <tr> - <th>Class</th> - <th>Data Type</th> - <th>Scriptable?</th> - <th>Typesafe?</th> - <th>Can be modified?</th> - <th>Built in buffer?</th> - <th>Ownership</th> - </tr> - <tr class="even"> - <td><code><a href="#nsIArray_.2F_nsIMutableArray">nsIArray</a></code></td> - <td>XPCOM object</td> - <td>Yes</td> - <td>No</td> - <td>No</td> - <td>No</td> - <td>Reference Counted, Weak/Strong</td> - </tr> - <tr class="odd"> - <td><code>nsIMutableArray</code></td> - <td>XPCOM object</td> - <td>Yes</td> - <td>No</td> - <td>Yes</td> - <td>No</td> - <td>Reference Counted, Weak/Strong</td> - </tr> - <tr class="even"> - <td><code>nsCOMArray<T></code></td> - <td>XPCOM object</td> - <td>No</td> - <td>Yes</td> - <td>Yes*</td> - <td>No</td> - <td>Reference Counted, Strong</td> - </tr> - <tr class="odd"> - <td><code>nsTArray<T></code></td> - <td>Any that has a default constructor and copy constructor</td> - <td>No</td> - <td>Yes</td> - <td>Yes*</td> - <td>No</td> - <td>Can hold objects directly, in which case it owns them. When holding pointers, doesn't own the pointer.</td> - </tr> - <tr class="even"> - <td><code>nsVoidArray</code></td> - <td>Any</td> - <td>No</td> - <td>No</td> - <td>Yes*</td> - <td>No</td> - <td>Weak / None</td> - </tr> - <tr class="odd"> - <td><code>nsStringArray</code><br> - <code>nsCStringArray</code></td> - <td><code>nsString</code><br> - <code>nsCString</code></td> - <td>No</td> - <td>Yes</td> - <td>Yes*</td> - <td>No</td> - <td>Private (copies strings)</td> - </tr> - <tr class="even"> - <td><code>nsAutoVoidArray</code></td> - <td>Any</td> - <td>No</td> - <td>No</td> - <td>Yes*</td> - <td>Yes</td> - <td>Weak / None</td> - </tr> - <tr class="odd"> - <td><code>nsSmallVoidArray</code></td> - <td>Any</td> - <td>No</td> - <td>No</td> - <td>Yes*</td> - <td>No</td> - <td>Weak / None</td> - </tr> - <tr class="even"> - <td><code>nsISupportsArray</code></td> - <td>XPCOM Object</td> - <td>Yes</td> - <td>No</td> - <td>Yes*</td> - <td>No</td> - <td>Reference Counted, Strong</td> - </tr> - </tbody> -</table> -<p>(*) Note: Concrete C++ arrays can be made read-only by declaring them const. For example:</p> -<pre class="eval">// HandleList cannot modify the array because of const -void HandleList(const nsVoidArray&); -</pre> -<h4 id="In-place_enumeration" name="In-place_enumeration">In-place enumeration</h4> -<p>Most of the arrays presented here provide callback-style means to enumerate members of an array. Instead of incrementally accessing each element of the array by its index, the arrays provide a way to pass in a callback function that will be called for each element in the array.</p> -<p>For most concrete C++ classes like <code>nsVoidArray</code> and <code>nsCOMArray<T></code>, indexing should be faster than the callback-style enumeration, because accessing an indexed member of such an array is usually very fast, while enumeration has slight function call overhead. In the case of scriptable arrays like nsIArray however, the enumeration mechanism is often preferred because it avoids the AddRef / Release overhead that comes from accessing each object.</p> -<p>The only functional drawback to in-place enumeration is that you cannot manipulate the array itself during the enumeration. For example, you should not delete elements of an array during the enumeration as this will often confuse the loop which is enumerating the array.</p> -<h4 id="Enumerators" name="Enumerators">Enumerators</h4> -<p>Most arrays provide access to an object which is used to enumerate members of the array. These Enumerators maintain state about the current position in the array. Enumerators are used to access the elements in an ordered way, without relying on the underlying array type. These enumerators include:</p> -<ul> - <li><code>nsISimpleEnumerator</code> - an enumerator for COM objects.</li> - <li><code>nsIStringEnumerator</code> / <code>nsIUTF8StringEnumerator</code> - enumerators for strings</li> -</ul> -<h4 id="Obsolete_arrays_.2F_enumerators" name="Obsolete_arrays_.2F_enumerators">Obsolete arrays / enumerators</h4> -<p>There are some deprecated classes which <b>should not be used by new code</b>.</p> -<ul> - <li><code>nsISupportsArray</code> - obsoleted by <code><a href="#nsIArray_.2F_nsIMutableArray">nsIArray</a></code>, use that instead.</li> - <li><code>nsIEnumerator</code> - obsoleted by <code>nsISimpleEnumerator</code>, use that instead.</li> - <li><code>nsIBidirectionalEnumerator</code> - obsoleted by <code>nsISimpleEnumerator</code>, use that instead.</li> - <li><code>nsVoidArray</code> - <code>nsTArray<span class="nowiki"><T></span></code> is preferred. Using <code>nsAutoVoidArray</code> is still ok, since that saves an allocation over using <code>nsTArray<span class="nowiki"><T></span>(8)</code>.</li> -</ul> -<h2 id="Which_Array_should_I_use.3F" name="Which_Array_should_I_use.3F">Which Array should I use?</h2> -<p>Do not use <code>nsISupportsArray</code>; it is deprecated.</p> -<p>Does your array need to be scriptable? If so, use <code>nsIArray</code>.</p> -<p>Example: an array attribute in an IDL file would be <code>nsIArray</code>.</p> -<p>Will your array store non-refcounted objects and need automatic resizing? If so, use <code>nsTArray<span class="nowiki"><T></span></code>.</p> -<p>Example: an array of integers or an array of strings.</p> -<p>Will your array store non-refcounted objects and be a fixed size? If so, just use a native C++ array unless you need the enumeration options on <code>nsTArray<span class="nowiki"><T></span></code>.</p> -<p>Example: an array of error message static const char* pointers.</p> -<p>Are all the things you are storing interface pointers to instances of the same interface? If so, use <code>nsCOMArray</code>.</p> -<p>Example: a content node's list of <code>nsIContent</code> children.</p> -<p>Otherwise use <code>nsIArray</code> and make liberal use of <code>QueryElementAt()</code>.</p> -<p>The point of <code>nsCOMArray</code> is that it's a template, and all the pointers in it must be pointers to the same type; it's nice to be able to use it because you get type-safety and don't have to spend time and code QIing (like you have to with <code>nsIArray</code>).</p> -<h2 id="Array_Guidelines" name="Array_Guidelines">Array Guidelines</h2> -<p>Here are a few simple rules which will keep your code clean and your developers happy:</p> -<ul> - <li>Use typesafe arrays like <code>nsCOMArray<span class="nowiki"><T></span></code> <code>nsTArray<span class="nowiki"><T></span></code> wherever possible.</li> - <li>Avoid all obsolete arrays and enumerators.</li> - <li>Avoid creating temporary arrays.</li> -</ul> -<h2 id="Scriptable_Arrays" name="Scriptable_Arrays">Scriptable Arrays</h2> -<h3 id="nsIArray_.2F_nsIMutableArray" name="nsIArray_.2F_nsIMutableArray">nsIArray / nsIMutableArray</h3> -<h4 id="Usage" name="Usage">Usage</h4> -<p><code>nsIArray</code> is useful if you need to pass arrays of COM objects through interfaces or require a scriptable array. It can hold strong or weak references to its container objects. This basic interface only allows querying of existing elements in the array. The methods that modify the array have been broken out into <code>nsIMutableArray</code>.</p> -<p>An <code>nsIArray</code> implementation can be created from C++ with the function <code>NS_NewArray(nsIMutableArray**);</code>. The created array implements <code>nsIMutableArray</code> and <code>nsIArray</code>. Since <code>nsIArray</code> derives from <code>nsIMutableArray</code>, the resulting array can be cast to a read-only array.</p> -<pre class="eval">void GetList(nsIArray** aResult) { - nsCOMPtr<nsIMutableArray> array; - NS_NewArray(getter_AddRefs(array)); - - // append some elements - ... - - // return it to the caller - *aResult = array; - NS_ADDREF(*aResult); -} -</pre> -<h4 id="Access_to_elements" name="Access_to_elements">Access to elements</h4> -<p>Since <code>nsIArray</code> is a regular XPCOM object, its interfaces follows the standard conventions of ownership. Access to specific elements is through <code>QueryElementAt</code>, which is similar to <code>QueryInterface</code>, but it takes a specific index.</p> -<pre class="eval">void NotifyObservers(nsIArray* aArray) { - PRUint32 length; - aArray->GetLength(&length); - for (PRUint32 i=0; i<length; ++i) { - nsCOMPtr<nsIMyObserver> element; - aArray->QueryElementAt(i, NS_GET_IID(nsIElement), - getter_AddRefs(element)); - element->Observe(); - } -} -</pre> -<p>A simpler option is to use the helper <code>do_QueryElementAt</code> which is typesafe.</p> -<pre class="eval">void NotifyObservers(nsIArray* aArray) { - PRUint32 length; - aArray->GetLength(&length); - for (PRUint32 i=0; i<length; ++i) { - nsCOMPtr<nsIMyObserver> element = - do_QueryElementAt(aArray, i); - element->Observe(); - } -} -</pre> -<h4 id="Passing_as_a_parameter" name="Passing_as_a_parameter">Passing as a parameter</h4> -<p>Since <code>nsIArray</code> is an XPCOM object, it should be passed as a pointer. To distinguish between read-only arrays and writable arrays, you should make sure to pass a nsIArray or <code>nsIMutableArray</code> as appropriate.</p> -<p>When the array can or should be modified, then use nsIMutableArray:</p> -<pre class="eval">// array is read-only because it uses nsIArray -void PrintSize(nsIArray* elements) { - PRUint32 count; - elements->GetLength(&count); - printf("There are %d elements.\n", count); -} - -// using nsIMutableArray, so callee may modify -void TweakArray(nsIMutableArray* elements) { - elements->RemoveElementAt(0); - elements->AppendElement(newElement, PR_FALSE); -} -</pre> -<p>While it is usually possible to call <code>QueryInterface</code> on an <code>nsIArray</code> to get access to the <code>nsIMutableArray</code> interface, this is against convention and it should be avoided.</p> -<pre class="eval">// no need for the double-pointer, and this violates XPCOM rules -// which expect acess to a new object -void TweakArray(nsIMutableArray** elements) { - // ugh, extra indirection! - *elements->RemoveElementAt(0); - *elements->AppendElement(newElement, PR_FALSE); -} -</pre> -<h4 id="In-place_enumeration_2" name="In-place_enumeration_2">In-place enumeration</h4> -<p>When accessing all members of an <code>nsIArray</code>, in-place enumeration is preferred over indexed access. However, I seem to have forgotten to implement that. Good thing the interface is under review. Sorry!</p> -<h4 id="Enumerators_2" name="Enumerators_2">Enumerators</h4> -<p>Creating an enumerator from an <code>nsIArray</code> is easy. The method <code>Enumerate()</code> returns a <code>nsISimpleEnumerator</code> which accesses all the elements in the array. Often, simply accessing an array by index, using <code>QueryElementAt</code> is faster. See the section on Enumerators to learn when to properly use enumerators.</p> -<p>For example, if you need to iterate an array returned from another object, you might use <code>Enumerate()</code>.</p> -<pre class="eval">... -// get the array -nsCOMPtr<nsIArray> array; -foo->GetElements(getter_AddRefs(array)); - -// make an enumerator -nsCOMPtr<nsISimpleEnumerator> enumerator; -array->Enumerate(getter_AddRefs(enumerator)); - -// now enumerate the elements -... -</pre> -<h2 id="Typesafe_Arrays" name="Typesafe_Arrays">Typesafe Arrays</h2> -<h3 id="nsCOMArray.3CT.3E" name="nsCOMArray.3CT.3E">nsCOMArray<T></h3> -<p><code>nsCOMArray<T></code> is a typesafe wrapper around <code>nsVoidArray</code>, so it has a similar API. It enforces both typesafety and XPCOM reference counting by keeping an owning reference to each element in the array.</p> -<h4 id="Usage_2" name="Usage_2">Usage</h4> -<p>It is most often used as a member of a C++ class to store a list of well-typed XPCOM objects. It is also usually declared as an inline member rather than a pointer. As a class member, <code>nsCOMArray<T></code> is preferred over <code>nsIArray</code> when access to the array is confined to the class itself.</p> -<p>For example, here is its use in a class:</p> -<pre class="eval">class NodeContainer { -public: - void AddNode(nsINode* node); - -private: - nsCOMArray<nsINode> mNodes; -}; - -// typesafety of mNodes ensures that we only append an nsINode* -void NodeContainer::AddNode(nsINode* node) { - mNodes.AppendObject(node); -} - -</pre> -<p><code>nsCOMArray<T></code> can also be declared on the stack to collect a temporary list of objects and manipulate them. When the object goes out of scope, all its members are released.</p> -<pre class="eval">void ProcessVisibleItems() -{ - // temporary stack-based nsCOMArray - nsCOMArray<nsIFoo> fooItems; - GetCompleteList(fooItems); - - // now filter out non visible objects - // doing this backwards - PRUint32 i = fooItems.Count(); - while (i > 0) { - --i; - PRBool isVisible; - fooItems[i]->GetIsVisible(&isVisible); - if (!isVisible) { - fooItems.RemoveObjectAt(i); - } - } - - // now deal with the processed list - ProcessList(fooItems); - - // fooItems will release all its members - // when it goes out of scope -} -</pre> -<h4 id="Access_to_elements_2" name="Access_to_elements_2">Access to elements</h4> -<p><code>nsCOMArray<T></code> is a concrete C++ class, and so the [] operator is used to access its members. When using the [] operator, the reference count is unchanged. This allows direct processing of array elements without worrying about calling <code>Release()</code>.</p> -<p>For example, this code calls the same method on each member:</p> -<pre class="eval">void NotifyObservers(const nsCOMArray<nsIMyObserver>& observers) { - // Using [] doesn't leak! - for (PRInt32 i = observers.Count() - 1; i >= 0 ; i--) - observers[i]->Observe(); -} -</pre> -<p>Be careful with this though, you could end up with a weak pointer if you're converting from non-nsCOMArray code.</p> -<pre class="eval">// old version, relied on automatic addref -// mElements is an nsISupportsArray* -void GetFirstObject(nsIElement** aResult) { - // no need to call NS_ADDREF - this does it for you - mElements->QueryElementAt(0, NS_GET_IID(nsIElement), - (void**)aResult); -} - -// new version, make sure to call NS_ADDREF() -// mElements is now a nsCOMArray<nsIElement> -void GetFirstObject(nsIElement** aResult) { - *aResult = mElements[0]; - NS_ADDREF(*aResult); -} -</pre> -<h4 id="Passing_as_a_parameter_2" name="Passing_as_a_parameter_2">Passing as a parameter</h4> -<p>When passing <code>nsCOMArray<T></code> among functions, the convention is to pass by reference. Also be sure to use const if you want to enforce that the array is read-only.</p> -<p>Here is an example with a read-only and a writable array:</p> -<pre class="eval">// array is read-only because of const -void PrintSize(const nsCOMArray<nsIElements>& elements) { - printf("There are %d elements.\n", elements.Count()); -} - -// no const, so we can modify the array -void TweakArray(nsCOMArray<nsIElement>& elements, nsIElement* newElement) { - elements.RemoveObjectAt(0); - elements.AppendObject(newElement); -} -</pre> -<h4 id="In-place_enumeration_3" name="In-place_enumeration_3">In-place enumeration</h4> -<p>The callback-based enumeration in <code>nsCOMArray<T></code> is about as fast as, if not faster than, standard loop-based iteration. The callback mechanism can be useful when integrating with existing callback-style code however.</p> -<p>One particularly nice thing about the callback mechanism is that it is typesafe. For instance:</p> -<pre class="eval">PR_CALLBACK PRBool getFirstVisible(nsIElement* element, void* closure) { - PRBool isVisible; - element->IsVisible(&isVisible); - - // stop at first object - if (isVisible) { - NS_STATIC_CAST(ClosureObject*,closure)->element = element; - return PR_FALSE; - } - return PR_TRUE; -} - -... -// enumerate to find the object -ClosureObject closureObject = { 0 }; -if (!mElements.EnumerateForwards(getFirstVisible, closureObject)) - processElement(closureObject->element); -... -</pre> -<h4 id="Enumerators_3" name="Enumerators_3">Enumerators</h4> -<p>A <code>nsISimpleEnumerator</code> can be created to provide access to a <code>nsCOMArray<T></code>. When the enumerator is created, it takes a snapshot of the elements in the array, so that the enumerator can outlive the array.</p> -<p>To create the enumerator, use <code>NS_NewArrayEnumerator(nsISimpleEnumerator**, const nsCOMArray<T>&)</code>. For example:</p> -<pre class="eval">// mElements is an nsCOMArray<nsIElement> -nsFoo::GetElements(nsISimpleEnumerator** aResult) { - return NS_NewArrayEnumerator(aResult, mElements); -} -</pre> -<h3 id="nsTArray.3CT.3E" name="nsTArray.3CT.3E">nsTArray<T></h3> -<p><code>nsTArray<T></code> is a typesafe array for holding various objects. It can be used to hold objects directly, not just pointers to objects.</p> -<h4 id="Usage_3" name="Usage_3">Usage</h4> -<p>It is most often used as a member of a C++ class to store a list of well-typed objects. It is also usually declared as an inline member rather than a pointer. As a class member, <code>nsTArray<T></code> is preferred over <code>nsVoidArray</code>.</p> -<p>For example, here is its use in a class:</p> -<pre class="eval">class MediaList { -public: - void AddMedium(const nsString& aMedium); - -private: - nsTArray<nsString> mMedia; -}; - -// typesafety of mMedia ensures that we only append an nsString -void NodeContainer::AddMedium(const nsString& aMedium) { - mMedia.AppendElement(aMedium); -} - -</pre> -<p><code>nsTArray<T></code> can also be declared on the stack to collect a temporary list of objects and manipulate them. When the object goes out of scope, all its members have their destructors called. Note that if the <code>nsTArray<T></code> holds pointers to objects, the objects will not be deleted (and hence not have their destructors called).</p> -<pre class="eval">void ProcessVisibleItems() -{ - // temporary stack-based nsTArray - nsTArray<FooStruct> fooItems; - GetCompleteList(fooItems); - - // now filter out non visible objects - // doing this backwards - PRUint32 i = fooItems.Length(); - while (i > 0) { - --i; - PRBool isVisible; - fooItems[i]->GetIsVisible(&isVisible); - if (!isVisible) { - fooItems.RemoveElementAt(i); - } - } - - // now deal with the processed list - ProcessList(fooItems); - - // fooItems will call the destructors of all the FooStruct objects - // when it goes out of scope -} -</pre> -<h4 id="Access_to_elements_3" name="Access_to_elements_3">Access to elements</h4> -<p><code>nsTArray<T></code> is a concrete C++ class, and so the [] operator is used to access its members.</p> -<p>For example, this code calls the same method on each member:</p> -<pre class="eval">void NotifyObservers(const nsTArray<ObserverClass*>& observers) { - for (PRUint32 i = observers.Length(); i > 0 ; ) { - --i; - observers[i]->Observe(); - } -} -</pre> -<h4 id="Passing_as_a_parameter_3" name="Passing_as_a_parameter_3">Passing as a parameter</h4> -<p>When passing <code>nsTArray<T></code> among functions, the convention is to pass by reference. Also be sure to use <code>const</code> if you want to enforce that the array is read-only.</p> -<p>Here is an example with a read-only and a writable array:</p> -<pre class="eval">// array is read-only because of const -void PrintSize(const nsTArray<nsElement>& elements) { - printf("There are %d elements.\n", elements.Length()); -} - -// no const, so we can modify the array -void TweakArray(nsTArray<nsElement>& elements, - const nsElement& newElement) { - elements.RemoveElementAt(0); - elements.AppendElement(newElement); -} -</pre> -<h4 id="In-place_enumeration_4" name="In-place_enumeration_4">In-place enumeration</h4> -<p>There are no enumerator objects that work on an <code>nsTArray<T></code>.</p> -<h2 id="C.2B.2B_Arrays" name="C.2B.2B_Arrays">C++ Arrays</h2> -<h3 id="nsVoidArray" name="nsVoidArray">nsVoidArray</h3> -<p><code>nsVoidArray</code> is a concrete C++ class that allows for storage of any arbitrary object. The base type for all objects is void *. When converting to/from a void *, use <code>NS_STATIC_CAST</code> to ensure that no const-ness is lost.</p> -<p>Note that <code>nsVoidArray</code> defines no semantics of ownership of its objects. Depending on its use, the array may either own the objects that it points to, or its member may be pointers to existing objects that are owned by another data structure. Because nsVoidArray itself does not define any ownership rules, it is up to the consumer to know when it is appropriate to free objects out of the array.</p> -<p>This implies that when an <code>nsVoidArray</code> goes out of scope, seperate code must free any memory that is semantically owned by the array. This should always be documented in the declaration of the array instance.</p> -<p><code>nsCOMArray<T></code> was designed to eliminate some of the overhead of using nsVoidArray when using COM objects. If your code is using <code>nsVoidArray</code> to keep references to COM objects, consider converting it to <code>nsCOMArray<T></code>.</p> -<h4 id="Usage_4" name="Usage_4">Usage</h4> -<p><code>nsVoidArray</code> is often used as a member variable in a class. Remember to document ownership!</p> -<pre class="eval">struct FooElement { - ... -}; - -class nsFoo : nsIFoo { - ... - virtual ~nsFoo(); - ... - - private: - // mElements owns a list of FooElement structs, - // which must be deleted when this object goes away - nsVoidArray mElements; - - // mVisibleElements contains weak (non-owning) references - // to elements in mElements, and does not need to be cleaned up - nsVoidArray mVisibleElements; -}; - -nsFoo::~nsFoo() { - // mVisibleElements is fine, but - // don't forget to clean up mElements! - PRUint32 i, count = mElements.Count(); - for (i=0; i<count; ++i) - delete NS_STATIC_CAST(FooElement*, mElements[i]); - } - -</pre> -<p>As you can see, <code>nsVoidArray</code> has some context-specific overhead to make sure memory is cleaned up appropriately.</p> -<h4 id="Access_to_elements_4" name="Access_to_elements_4">Access to elements</h4> -<p>The [] operator is used to access member variables. Don't forget to use <code>NS_STATIC_CAST()</code>.</p> -<pre class="eval">for (i=0; i<count; ++i) { - FooElement* element = NS_STATIC_CAST(FooElement*,mElements[i]); - // now manipulate element -} - -</pre> -<h4 id="Passing_as_a_parameter_4" name="Passing_as_a_parameter_4">Passing as a parameter</h4> -<p>Like other concrete C++ classes, passing by reference using the & syntax is preferred.</p> -<h4 id="In-place_enumeration_5" name="In-place_enumeration_5">In-place enumeration</h4> -<h4 id="Enumerators_4" name="Enumerators_4">Enumerators</h4> -<h3 id="nsStringArray_.2F_nsCStringArray" name="nsStringArray_.2F_nsCStringArray">nsStringArray / nsCStringArray</h3> -<h4 id="Usage_5" name="Usage_5">Usage</h4> -<h4 id="Access_to_elements_5" name="Access_to_elements_5">Access to elements</h4> -<h4 id="Passing_as_a_parameter_5" name="Passing_as_a_parameter_5">Passing as a parameter</h4> -<h4 id="In-place_enumeration_6" name="In-place_enumeration_6">In-place enumeration</h4> -<h4 id="Enumerators_5" name="Enumerators_5">Enumerators</h4> -<h3 id="nsAutoVoidArray" name="nsAutoVoidArray">nsAutoVoidArray</h3> -<h4 id="Usage_6" name="Usage_6">Usage</h4> -<h4 id="Access_to_elements_6" name="Access_to_elements_6">Access to elements</h4> -<h4 id="Passing_as_a_parameter_6" name="Passing_as_a_parameter_6">Passing as a parameter</h4> -<h4 id="In-place_enumeration_7" name="In-place_enumeration_7">In-place enumeration</h4> -<h4 id="Enumerators_6" name="Enumerators_6">Enumerators</h4> -<h3 id="nsSmallVoidArray" name="nsSmallVoidArray">nsSmallVoidArray</h3> -<h4 id="Usage_7" name="Usage_7">Usage</h4> -<h4 id="Access_to_elements_7" name="Access_to_elements_7">Access to elements</h4> -<h4 id="Passing_as_a_parameter_7" name="Passing_as_a_parameter_7">Passing as a parameter</h4> -<h4 id="In-place_enumeration_8" name="In-place_enumeration_8">In-place enumeration</h4> -<h4 id="Enumerators_7" name="Enumerators_7">Enumerators</h4> -<h2 id="Enumerators_8" name="Enumerators_8">Enumerators</h2> -<p>Enumerators are very simple, structure-free objects for visiting each member of a set of objects. The enumerators are used as a generic interface for arrays, hashtables, and other constructs which contain one or more objects. When designing public interfaces, enumerators are the preferred mechanism for accessing these structures because they hide the details of the implementation behind the interface.</p> -<h3 id="nsISimpleEnumerator" name="nsISimpleEnumerator">nsISimpleEnumerator</h3> -<p><code>nsISimpleEnumerator</code> is a generic enumerator for enumerating a list of any XPCOM object. There are many implementations of <code>nsISimpleEnumerator</code>, including one that enumerates <code>nsIArray</code> objects, and another one for <code>nsCOMArray</code>. It is very common for other interfaces which support <code>nsISimpleEnumerator</code> to make their own implementations.</p> -<h3 id="nsIStringEnumerator" name="nsIStringEnumerator">nsIStringEnumerator</h3> -<p>String enumerators provide an easy way to pass a list of strings around with minimal copying. Both unicode strings and UTF8-encoded strings are supported. For more information about the different types of strings, see the String Guide.</p> -<p>String enumerators can be created from <code>nsStringArray</code> or <code>nsCStringArray</code> objects. The implementation of the string enumerator interfaces for <code>nsStringArray</code> and <code>nsCStringArray</code> supports conversion between UTF8 and Unicode, and can be QueryInterface'd back and forth between <code>nsIStringEnumerator</code> and <code>nsIUTF8StringEnumerator</code>.</p> -<p>To create an nsIStringEnumerator for an <code>nsStringArray</code>, you can use one of the variations of <code>NS_NewStringEnumerator</code>. There are also corresponding enumerators and helpers for UTF8 strings. In the examples below, <code>NS_NewUTF8StringEnumerator</code> can be used along with <code>nsIUTF8StringEnumerator</code> and <code>nsCStringArray</code>.</p> -<p>This first example demonstrates the case where a class which owns an <code>nsStringArray</code>, and are returns an <code>nsIStringEnumerator</code> to a caller. You can use the variation of <code>NS_NewStringEnumerator</code> that ensures the owner of the array outlives the enumerator. This is necessary because nsStringArray is not reference counted. Without holding a reference to the owner, the enumerator could be left with a dangling pointer to a deleted <code>nsStringArray</code>.</p> -<pre class="eval">class nsFoo : nsIFoo { -... -private: - nsStringArray mElementNames; -}; - -nsFoo::GetElementNames(nsIStringEnumerator** aResult) -{ - // pass in "this" to make sure the enumerator - // holds a reference to "this" - return NS_NewStringEnumerator(aResult, mElementNames, this); -} -</pre> -<p>One variant of <code>NS_NewStringEnumerator</code> does not require an owner, but should only be used when the lifetime of the enumerator is known to be shorter than that of the array. Often this is used when a method must take a <code>nsIStringEnumerator</code> rather than an <code>nsStringArray</code>, due to some sort of interface constraint.</p> -<pre class="eval">class nsFoo : nsIFoo { - ... - // when ProcessElements returns, the enumerator is at the - // end of the list, and can be released. - NS_IMETHODIMP ProcessNames(nsIStringEnumerator*); - private: - - nsStringArray mElementNames; -}; - -... -nsCOMPtr<nsIStringEnumerator> enumerator; -NS_NewStringEnumerator(getter_AddRefs(enumerator), mElementNames); - -// now call a method on "this" that has a known behavior -ProcessNames(enumerator); -// now enumerator is used up, and can be released -... -</pre> -<p>The last version of <code>nsIStringEnumerator</code> takes ownership of an <code>nsStringArray</code> and is responsible for freeing the array when the enumerator is used up.</p> -<pre class="eval">void GetNames(nsIStringEnumerator** aResult) -{ - nsStringArray *resultArray = new nsStringArray; - resultArray->AppendString(str1); - resultArray->AppendString(str2); - - // enumerator will free resultArray - return NS_NewAdoptingStringEnumerator(aResult, resultArray); -} -</pre> -<p>As noted above, these implementations of <code>nsIStringEnumerator</code> can also be QueryInterface'd between nsIStringEnumerator and <code>nsIUTF8StringEnumerator</code>. The implementations will properly convert back and forth between UTF8 and Unicode. To ensure that you get the right implementation and the conversion is done in the right direction, make sure that you call the version of <code>NS_NewStringEnumerator</code> or <code>NS_NewUTF8StringEnumerator</code> that corresponds to the array type, not the enumerator type.</p> -<p>For example, if a class has an internal <code>nsCStringArray</code> of UTF8 strings, but needs to implement an interface which returns an nsIStringEnumerator, it should use <code>NS_NewStringEnumerator</code>:</p> -<pre class="eval">class nsFoo : nsIFoo { - ... - NS_IMETHOD GetStrings(nsIStringEnumerator** aResult); -</pre> -<pre class="eval"> private: - nsCStringArray mElementNames; -}; - -NS_IMETHODIMP -nsFoo::GetStrings(nsIStringEnumerator** aResult) { - nsresult rv; - nsCOMPtr<nsIUTF8StringEnumerator> enumerator - rv = NS_NewUTF8StringEnumerator(getter_AddRefs(enumerator), - mElementNames, this); - return CallQueryInterface(enumerator, aResult); -} -</pre> -<h2 id="Obsolete_Arrays_and_Enumerators" name="Obsolete_Arrays_and_Enumerators">Obsolete Arrays and Enumerators</h2> -<h3 id="nsISupportsArray" name="nsISupportsArray">nsISupportsArray</h3> -<h3 id="nsIEnumerator_.28includes_nsIBidirectionalEnumerator.29" name="nsIEnumerator_.28includes_nsIBidirectionalEnumerator.29">nsIEnumerator (includes nsIBidirectionalEnumerator)</h3> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/an_overview_of_xpcom/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/an_overview_of_xpcom/index.html deleted file mode 100644 index 64bf41704f..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/an_overview_of_xpcom/index.html +++ /dev/null @@ -1,535 +0,0 @@ ---- -title: 创建_XPCOM_组件/XPCOM_简介 -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/An_Overview_of_XPCOM -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/An_Overview_of_XPCOM ---- -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/创建_XPCOM_组件:前言" style="float: left;">« 上一页</a><a href="/zh-CN/docs/创建_XPCOM_组件:使用_XPCOM_组件">下一页 »</a></p> -</div><p></p> - -<p>这是一本关于 XPCOM 的书. 这本书是以编写一个 XPCOM 组件的方式来组织的, 但是这个过程涵盖了 XPCOM 组件模型主要的出发点, 概念和术语.</p> - -<p>本章以 XPCOM 的快速导览开始, 简单介绍了 XPCOM 和组件开发的基本概念和技术. 本章的大部分内容从一个很高的角度介绍了这些概念, 这些概念将在创建一个称为 <strong>WebLock</strong> 的 Mozilla 组件过程中逐渐透彻的讲述.</p> - -<h3 id="XPCOM_.E8.A7.A3.E5.86.B3.E6.96.B9.E6.A1.88" name="XPCOM_.E8.A7.A3.E5.86.B3.E6.96.B9.E6.A1.88">XPCOM 解决方案</h3> - -<p>Cross Platform Component Object Module (XPCOM) 是一个允许开发人员把一个大的工程划分成小的模块的框架. 这些小模块称为<em>组件</em>, 它们在运行时刻组装在一起.</p> - -<p>XPCOM 的目标是使软件的不同部分分别开发, 相互独立. 为了是应用的不同组件之间能够互操作, XPCOM 把组件的<em>实现</em>与<em>接口</em>(后面讨论<a href="#接口">接口</a>)分开. 同时 XPCOM 还提供了加载和操纵这些组件的库和工具以及服务, 以帮助开发人员编写跨平台的代码和组件版本管理; 因此组件可以在不破坏应用或者重新生成应用的同时被替换被更新. 通过使用 XPCOM, 开发人员创建的组件可以在不同的应用中被重用, 或者替换当前应用中的组件以改变应用的功能.</p> - -<p>XPCOM 不只提供组件软件开发的支持, 它同时提供一个开发平台的大多数功能的支持:</p> - -<ul> - <li>组件管理</li> - <li>文件抽象</li> - <li>对象消息传递</li> - <li>内存管理</li> -</ul> - -<p>我们将在后面的章节中详细讨论上面的条目, 但是现在, 仅仅把 XPCOM 想象成一个 <em>组件开发平台</em>, 它提供了上面的这些特性.</p> - -<h3 id="Gecko" name="Gecko">Gecko</h3> - -<p>XPCOM 尽管在许多方面类似于 Microsoft COM, 但 XPCOM 被设计成主要应用于应用层. XPCOM 的最重要的应用是 <em>Gecko</em>, 一个开源的, 遵循标准的, 嵌入式 web 浏览器和 工具包.</p> - -<p>XPCOM 是访问 Gecko 库和嵌入或扩展 Gecko 的方法. 本书着重于后者 - 扩展 Gecko - 但是本书中描述的基本思想对嵌入 Gecko 的开发人员也很重要.</p> - -<p>Gecko 应用在许多 internet 程序中, 主要是浏览器. 包括 Gateway/AOL Instant AOL device 和 Nokia Media Terminal. Gecko 最近还被应用于的 Compuserve 客户端, AOL for Mac OS X, Netscape 7, 当然还包括 Mozilla 客户端. Gecko 是目前而言主流的开源浏览器.</p> - -<h3 id=".E7.BB.84.E4.BB.B6" name=".E7.BB.84.E4.BB.B6">组件</h3> - -<p>XPCOM 允许把一个大的工程分解为一些小部分. 这些小部分称为组件, 通常是一些小的可重用的二进制库(在 Windows 下表现为一个 DLL (动态联接库), Unix 下为一个 DSO (分布式共享对象), 这些二进制库可以包含一个或多个组件. 当多个相关组件被封装到一个二进制库, 这个库也称为<em>模块</em>.</p> - -<p>把软件划分成不同的组件可以使开发和维护工作变得更容易. 除了这个好处, 模块化组件化的编程还有下面的优势:</p> - -<table class="standard-table"> - <tbody> - <tr> - <td class="header">优点</td> - <td class="header">描述</td> - </tr> - <tr> - <td>重用</td> - <td>模块化的代码可以在其他应用和环境中被重用.</td> - </tr> - <tr> - <td>更新</td> - <td>在不需要重新编译整个应用的情况下更新组件.</td> - </tr> - <tr> - <td>性能</td> - <td>代码按照模块化组织, 模块就不必要立刻被加载, 而是以 "lazy" 方式加载, 或者根本不需要加载. 这样就可以提升应用的整体性能.</td> - </tr> - <tr> - <td>维护</td> - <td>甚至在不更新组件的情况下, 按照模块化的方式设计应用也能够使你对感兴趣的部分的维护变得更容易.</td> - </tr> - </tbody> -</table> - -<p>Mozilla 有几百万行代码, 没有那个人能够彻底搞明白整个代码的细节. 面对这样的一个系统, 最好的方式是把它划分成一些小的, 更容易管理的部分; 同时使用组件模型来编程, 把相关组件组织到各个模块中去. 比如说, Mozilla 的网络库就包含了 HTTP, FTP, 及其他协议的组件, 这些组件被塞到一个单独的库里. 这个库就是网络模块, 也就是通常所说的 "necko."</p> - -<p>但是把事物划分开来并不一定就好, 有许多事物作为一个整体组织起来才是最好的方式, 或者根本就不能划分开来. 比如说, 一个小孩就可能不吃没有果酱的三明志, 对于他来说, 果酱和三明志是缺一不可的整体. 同样的情形也会存在于某些软件中, 某些需要紧耦合的仅仅在内部使用的部分就并不需要费力去把它拆开成为小的模块.</p> - -<p>Gecko 中的 HTTP (超文本传输协议) 组件并不会暴露它内部的类, 它是作为一个整体来使用. 组件内部的事物不应该暴露给 XPCOM. 在 Mozilla 早期的开发中, 有些组件的创建并不适当, 但是随着开发的深入, 这些部分会被逐渐移出 XPCOM.</p> - -<h3 id=".E6.8E.A5.E5.8F.A3" name=".E6.8E.A5.E5.8F.A3">接口</h3> - -<p>把软件划分成组件通常一个好的解决方法, 但是我们该怎么做呢? 基本的思路是按照功能进行划分, 理解这些功能块之间的如何进行通信. 这些组件之间的通信通道就构成了各个组件的边界, 这些边界形式的描述为<em>接口</em>.</p> - -<p>接口并不是编程中的一个新的概念. 从我们的第一个 "HelloWorld" 程序开始我们就一直在不知不觉的使用它, 这里的接口就存在于我们的应用程序和打印程序之间. 应用程序使用 <code>stdio</code> 库提供的接口来把 "hello world" 字符串打印到屏幕上. XPCOM 与 "HelloWorld" 程序的不同之处在于 XPCOM 会在运行时刻找到这个屏幕打印的功能, 而 XPCOM 事前根本就不需要在编译的时刻了解 <code>stdio</code> 库提供了什么东西.</p> - -<p>接口允许开发人员把功能的具体实现<em>封装</em>在组件内部, 而客户程序不需要了解这个功能是如何实现的, 它只需要使用它就行了.</p> - -<div class="side-note"> -<p><span id="%E6%8E%A5%E5%8F%A3%E4%B8%8E%E6%8C%89%E7%85%A7%E5%A5%91%E7%BA%A6(Contract)%E7%BC%96%E7%A8%8B"><a id="%E6%8E%A5%E5%8F%A3%E4%B8%8E%E6%8C%89%E7%85%A7%E5%A5%91%E7%BA%A6(Contract)%E7%BC%96%E7%A8%8B"></a><strong>接口与按照契约(Contract)编程</strong></span></p> - -<p>一个接口在组件与客户程序之间达成契约. 并没有任何强制措施保证认同这个契约, 但是忽略它会是致命的. 在基于组件的编程中, 组件保证它提供的接口是<em>不变的</em> - 不同版本的组件都要提供同样的访问方法 - 这就与使用它的客户程序达成了一种契约. 从这种角度来说, 基于组件的编程通常也称为<em>按照契约编程</em>.</p> -</div> - -<h4 id=".E6.8E.A5.E5.8F.A3.E4.B8.8E.E5.B0.81.E8.A3.85" name=".E6.8E.A5.E5.8F.A3.E4.B8.8E.E5.B0.81.E8.A3.85">接口与封装</h4> - -<p>组件边界之间的抽象对软件的可维护性与可重用性是致关重要的. 举个例子来说, 考虑下面一个没有很好封装的类. 在下面的例子中, 使用可自由访问的 public 的初始化方法可能会出问题.</p> - -<p><span id="SomeClass%E7%B1%BB%E5%88%9D%E5%A7%8B%E5%8C%96"><a id="SomeClass%E7%B1%BB%E5%88%9D%E5%A7%8B%E5%8C%96"></a><strong>SomeClass类初始化</strong></span></p> - -<pre>class SomeClass -{ - public: - // Constructor - SomeClass(); - - // Virtual Destructor - virtual ~SomeClass(); - - // init method - void Init(); - - void DoSomethingUseful(); -}; -</pre> - -<p>系统要工作正常, 客户程序员必须注意到组件程序员建立的潜规则. 这就是这个未很好封装的类的契约: 这是一套关于何时该调用一个方法, 调用这个方法之前应该做什么的规则. 这个规则可能指出 <code>DoSomethingUseful</code> 方法只能在调用 <code>Init()</code> 之后被使用. <code>DoSomethingUseful</code> 方法可能会做某些检查工作以保证条件满足 - <code>Init</code> 已经被调用.</p> - -<p>除了在代码中给出注释告诉客户程序员关于 <code>Init()</code> 规则之外, 程序员可以使他的契约更明晰. 首先对象的构造函数可以封装起来, 然后向客户程序员提供一个声明 <code>DoSomethingUseful</code> 方法的<em>虚基类</em>. 通过这种方式, 构造函数和初始化函数被隐藏起来. 在这种<em>半封装</em>条件下, 这个类只向客户程序暴露一些良好定义的可调用方法(或者称为接口). 一旦按照这种方式封装一个类, 客户程序只能看到的是下面的接口:</p> - -<p><span id="SomeInterface%E5%B0%81%E8%A3%85"><a id="SomeInterface%E5%B0%81%E8%A3%85"></a><strong>SomeInterface封装</strong></span></p> - -<pre>class SomeInterface -{ - public: - virtual void DoSomethingUseful() = 0; -}; -</pre> - -<p>实现类就可以从这个虚基类派生, 实现接口的功能. 客户程序使用类厂(factory pattern)模式来创建对象(参看<a href="#类厂">类厂</a>), 而封装类的内部实现. XPCOM 以这种方式把客户程序屏蔽在组件的内部工作之外, 而客户程序也只依赖于提供所需要功能的接口.</p> - -<h4 id="nsISupports_.E5.9F.BA.E6.8E.A5.E5.8F.A3" name="nsISupports_.E5.9F.BA.E6.8E.A5.E5.8F.A3"><code>nsISupports</code> 基接口</h4> - -<p>组件与基于接口的编程的两个最基本的问题是: 一个是<em>组件生存期</em>, 也称为<em>对象所属关系</em>; 另一个是<em>接口查询</em>, 它是在运行时刻确定接口能够提供哪些接口. 这一节介绍基接口 <code>nsISupports</code> - 它是 XPCOM 中所有接口的父接口, 它提供了上面两个问题的解决方案.</p> - -<h5 id=".E5.AF.B9.E8.B1.A1.E6.89.80.E5.B1.9E.E5.85.B3.E7.B3.BB" name=".E5.AF.B9.E8.B1.A1.E6.89.80.E5.B1.9E.E5.85.B3.E7.B3.BB">对象所属关系</h5> - -<p>在 XPCOM 中, 由于组件可以实现任意多的不同接口, 接口必须是<em>引用计数的</em>. 组件在内部跟踪客户程序对它的接口引用了多少次, 当接口计数为零的时候组件就会卸载它自己.</p> - -<p>当一个组件创建后, 组件内部有一个整数在跟踪这个引用计数值. 客户程序实例化组件就会自动对这个引用计数加一; 在组件的整个生存期内, 引用计数或加或减, 总是大于零的. 如果在某个时刻, 所有的客户程序对该组件都失去了兴趣, 引用计数减到零, 组件就会卸载自己.</p> - -<p>客户程序使用相关接口是一个非常直接的过程. XPCOM 有一些工具让我们更方便的使用接口, 我们会在后面讲述. 如果客户程序在使用接口的时候忘记对接口的引用计数进行相关操作, 就会对组件的维护工作带来某些问题. 此时, 由于组件的引用计数始终不为零, 它就永远不会释放, 从而导致内存泄漏. 引用计数系统就象 XPCOM 的许多其他事物一样, 是客户与组件之间的契约. 如果遵守这些契约, 就会工作得很正常, 反之不然. 由创建接口指针的函数负责对初始化的接口引用加1, 这个引用也称为<em>所属引用</em>.</p> - -<div class="side-note"> -<p><span id="XPCOM%E4%B8%AD%E7%9A%84%E6%8C%87%E9%92%88"><a id="XPCOM%E4%B8%AD%E7%9A%84%E6%8C%87%E9%92%88"></a><strong>XPCOM中的指针</strong></span></p> - -<p>XPCOM 中的<em>指针</em>术语指的是接口指针. 它与常规指针相比有细微的差别, 毕竟它们都指向的是某个内存区域. 但是 XPCOM 指针指向的都是从 nsISupports 基接口派生而来的接口实现, 这个基接口包括三个基本的方法: <code>AddRef</code>, <code>Release</code>, 和 <code>QueryInterface</code>.</p> -</div> - -<p><code>nsISupports</code> 接口提供了对接口查询与引用计数基本的支持. 这个接口的成员方法包括: <code>QueryInterface</code>, <code>AddRef</code>, 和 <code>Release</code>. 这些方法提供了从一个对象获取正确接口的基本方法, 加引用计数, 释放不再使用的对象. <code>nsISupports</code> 接口的声明如下:</p> - -<p><span id="%3Ccode%3EnsISupports%3C/code%3E_%E6%8E%A5%E5%8F%A3"><a id="%3Ccode%3EnsISupports%3C/code%3E_%E6%8E%A5%E5%8F%A3"></a><strong><code>nsISupports</code> 接口</strong></span></p> - -<pre>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); -}; -</pre> - -<p>接口中使用的各种数据类型见<a href="#XPCOM_类型">XPCOM 类型</a>一节. <code>nsISupports</code> 接口的实现代码如下:</p> - -<p><span id="%3Ccode%3EnsISupports%3C/code%3E_%E6%8E%A5%E5%8F%A3%E5%AE%9E%E7%8E%B0"><a id="%3Ccode%3EnsISupports%3C/code%3E_%E6%8E%A5%E5%8F%A3%E5%AE%9E%E7%8E%B0"></a><strong><code>nsISupports</code> 接口实现</strong></span></p> - -<pre>Sample::Sample() -{ - // initialize the reference count to 0 - mRefCnt = 0; -} -Sample::~Sample() -{ -} - -// typical, generic implementation of QI -NS_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; -} -</pre> - -<h5 id=".E5.AF.B9.E8.B1.A1.E6.8E.A5.E5.8F.A3.E7.9A.84.E5.8F.91.E7.8E.B0" name=".E5.AF.B9.E8.B1.A1.E6.8E.A5.E5.8F.A3.E7.9A.84.E5.8F.91.E7.8E.B0">对象接口的发现</h5> - -<p><em>继承</em>是面向对象编程中另一个非常重要的话题. 继承是通过一个类派生另一个类的方法. 当一个类继承另一个类, 继承类可以<em>重载</em>基类的缺省动作, 而不需要拷贝基类的代码, 从而创建更加专有的类. 如下所示:</p> - -<p><span id="%E7%AE%80%E5%8D%95%E7%B1%BB%E7%BB%A7%E6%89%BF"><a id="%E7%AE%80%E5%8D%95%E7%B1%BB%E7%BB%A7%E6%89%BF"></a><strong>简单类继承</strong></span></p> - -<pre>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(); -}; -</pre> - -<p><code>Circle</code> 从 <code>Shape</code> 类派生. <code>Circle</code> 本身也是一个 <code>Shape</code>, 但是 <code>Shape</code> 并不一定是 <code>Circle</code>. 在这种情况下, <code>Shape</code> 是<em>基类</em>, <code>Circle</code> 是 <code>Shape</code> 的子类.</p> - -<p>在 XPCOM 中, 所有的类都派生自 <code>nsISupports</code> 接口, 这样所有的对象都提供 <code>nsISupports</code>接口, 但是这些对象是更专有的类, 在运行时刻必须能找到它. 比如说在<a href="#简单类继承">简单类继承</a>例子中, 如果对象是一个 <code>Circle</code>, 你就可以调用 <code>Shape</code> 类的方法. 就是为什么在 XPCOM 中, 所有的对象都派生自 <code>nsISupports</code> 接口: 它允许客户程序根据需要发现和访问不同的接口.</p> - -<p>在 C++ 中, 我们可以使用 <code>dynamic_cast<></code> 来把一个 <code>Shape</code> 对象的指针强制转化成一个 <code>Circle</code> 指针, 如果不能转化就抛出异常. 但是在 XPCOM 中, 由于性能开销和平台兼容性问题, 采用 RTTI (运行时刻类型信息) 的方法是不行的.</p> - -<div class="side-note"> -<p><span id="XPCOM_%E4%B8%AD%E7%9A%84%E5%BC%82%E5%B8%B8"><a id="XPCOM_%E4%B8%AD%E7%9A%84%E5%BC%82%E5%B8%B8"></a><strong>XPCOM 中的异常</strong></span></p> - -<p>XPCOM 并不直接支持 C++ 的异常处理. 在 XPCOM 中, 所有的异常必须在组件内部处理, 而不能跨越接口的边界. 然后接口方法返回一个 <code>nsresult</code> 错误值(这些错误码请参考 <a href="/cn/XPCOM_API_Reference" title="cn/XPCOM_API_Reference">XPCOM API Reference</a>). 客户程序根据这些错误码进行"异常"处理.</p> -</div> - -<p>XPCOM 没有采用 C++ RTTI 机制来实现对象指针的动态转化, 它使用 <code>QueryInterface</code> 方法来把一个对象指针 cast 成正确的接口指针.</p> - -<p>每个接口使用称为 "uuidgen" 的工具来生成专有ID. 这个 ID 是一个全局唯一的 128-bit 值. 在接口的语境中, 这个 ID 又称为 <em>IID</em>. (组件语境中, 这个 ID 代表的是一个契约)</p> - -<p>当客户程序想查询一个对象是否支持某个接口, 它把接口的 IID 值传递给这个对象的 <code>QueryInterface</code> 方法. 如果对象支持这个接口, 它就会对自己的引用计数加1, 然后返回指向那个专有接口的指针. 反之, 如果不支持这个接口, 它会返回一个错误码.</p> - -<pre>class nsISupports { - public: - long QueryInterface(const nsIID & uuid, - void **result) = 0; - long AddRef(void) = 0; - long Release(void) = 0; -}; -</pre> - -<p><code>QueryInterface</code> 的第一个参数是一个 <code>nsIID</code> 类型的引用, 它封装了 IID. <code>nsIID</code> 类有三种方法: <code>Equals</code>, <code>Parse</code>, 和 <code>ToString</code>. <code>Equals</code> 在接口查询中是最重要的, 它用来比较两个 <code>nsIID</code> 对象是否相同.</p> - -<p>在客户以 IID 调用 <code>nsISupports</code> 接口的 <code>QueryInterface</code> 方法时, 我们必须保证返回一个有效的 result 参数(在<a href="/cn/Creating_XPCOM_Components/Using_XPCOM_Utilities_to_Make_Things_Easier" title="cn/Creating_XPCOM_Components/Using_XPCOM_Utilities_to_Make_Things_Easier">Using XPCOM Utilities to Make Things Easier</a> 一章中, 我们将看到怎样更方便的实现一个 <code>nsIID</code> 类). <code>QueryInterface</code> 方法应该支持该组件所有接口的查询.</p> - -<p>在 <code>QueryInterface</code> 方法的实现中, IID 参数与组件支持 <code>nsIID</code> 类进行比较. 如果匹配, 对象的 <code>this</code> 指针转化为 <code>void</code> 指针, 引用计数加1, 把 <code>void</code> 指针返回给客户程序.</p> - -<p>在上面的例子中, 仅仅使用 C 方式的类型转化就足够了. 但是在把 <code>void</code> 指针 cast 成接口指针的时候, 还有更多的问题, 因为返回的接口指针必须与 vtable (virtual table) 相对应. 当出现菱形多重继承的时候, 可能这种接口转化就会有问题.</p> - -<h3 id="XPCOM_.E7.9A.84ID" name="XPCOM_.E7.9A.84ID">XPCOM 的ID</h3> - -<p>除了上一节中的接口 IID, XPCOM 还使用两种 ID 来区分类与组件.</p> - -<div class="side-note"> -<p><span id="XPCOM_ID%E7%B1%BB"><a id="XPCOM_ID%E7%B1%BB"></a><strong>XPCOM ID类</strong></span></p> - -<p><code>nsIID</code> 类实际上是一种 <code>nsID</code> 类. 其他的 <code>nsID</code>, CID 和 IID, 分别指的是一个实体类和一个专有的接口.</p> - -<p><code>nsID</code> 类提供 <code>Equals</code> 类似的方法, 来比较 ID. 请参考 <a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#Identifiers_in_XPCOM" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#Identifiers_in_XPCOM">Identifiers in XPCOM</a> 一节, 其中对 <code>nsID</code> 类有更多的讨论.</p> -</div> - -<h4 id="CID" name="CID">CID</h4> - -<p>CID 是一个唯一的 128-bit 值, 类似于 IID, 它用于全局标识唯一的类或者组件. <code>nsISupports</code> 的 CID 就象:</p> - -<p><code>00000000-0000-0000-c000-000000000046</code></p> - -<p>由于 CID 比较长, 通常我们都使用#define来定义它:</p> - -<pre>#define SAMPLE_CID \ -{ 0x777f7150, 0x4a2b, 0x4301, \ -{ 0xad, 0x10, 0x5e, 0xab, 0x25, 0xb3, 0x22, 0xaa}} -</pre> - -<p>我们将会看到许多 <code>NS_DEFINE_CID</code> 的定义. 下面的宏用 CID 定义了一个静态变量:</p> - -<pre>static NS_DEFINE_CID(kWebShellCID, NS_WEB_SHELL_CID); -</pre> - -<p>CID 有时也称为<em>类 ID</em>. 如果一个类实现了多个接口, 当CID 在该类发布后, 就与该类的 IID 一起被冻结了.</p> - -<h4 id=".E5.A5.91.E7.BA.A6_ID" name=".E5.A5.91.E7.BA.A6_ID">契约 ID</h4> - -<p>契约 ID 是一个用于访问组件的可读(to humen)的字符串. 一个 CID 或者一个契约 ID 可以用于从一个组件管理器获取组件. 下面是一个用于 LDAP 操作组件的契约 ID:</p> - -<pre>"@mozilla.org/network/ldap-operation;1" -</pre> - -<p>契约 ID 的格式是: 用斜杠分开的组件的<em>域</em>, <em>模块</em>, <em>组件名</em>, <em>版本号</em>.</p> - -<p>与 CID 类似, 契约 ID 指的是组件实现而不是接口. 但是契约 ID 并不像CID那样,被限定为某个专有实现, 它更通用. 一个契约 ID 只是指明需要实现的一组接口,可以通过任意数量的CID满足这个需要. 契约 ID 与 CID 的这种不同, 使得组件重写成为可能.</p> - -<h3 id=".E7.B1.BB.E5.8E.82" name=".E7.B1.BB.E5.8E.82">类厂</h3> - -<p>把代码划分成组件, 客户代码通常使用 <code>new</code> 操作符来构造实例对象:</p> - -<pre>SomeClass* component = new SomeClass(); -</pre> - -<p>这种模式或多或少地需要客户对组件有一定的了解,至少要知道组件的大小. <em>类厂设计模式</em>此时可以用来封装对象的构造过程. 类厂模式的目的是在不暴露对象的实现和初始化的前提下创建对象. 在 <code>SomeClass</code> 例子中, 可以按照类厂模式把 <code>SomeClass</code> 对象的构造和初始化封装在 <code>New_SomeInterface</code> 函数中:</p> - -<p><span id="%E5%B0%81%E8%A3%85%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0"><a id="%E5%B0%81%E8%A3%85%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0"></a><strong>封装构造函数</strong></span></p> - -<pre>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; -} -</pre> - -<p>类厂本身是一个管理组件实例化的类. 在 XPCOM 中, 类厂要实现 <code>nsIFactory</code> 接口, 它们就象上面的代码一样要使用类厂设计模式来封装对象的构造和初始化.</p> - -<p><a href="#封装构造函数">封装构造函数</a> 的例子是一个简单的无状态的类厂版本, 实际的编程要复杂一些, 一般的类厂都需要保存状态. 类厂至少应该保存那些对象已经被创建了的信息. 如果类厂管理的实例被存放在一个动态联接库中, 还需要知道什么时候可以卸载这个动态联接库. 当类厂保存了这样的信息, 就可以向类厂查询一个对象是否已经被创建.</p> - -<p>另一个需要保存的信息是关于<em>单件(singleton)</em>. 如果一个类厂已经创建了一个单件类型的类, 后续的创建该单件的函数调用将返回已经创建的对象. 尽管有更好的工具和方式来管理单件(在讨论 <code>nsIServiceManager</code> 会看到), 开发人员可能仍然需要通过这种方式来保证只有一个单件对象被创建.</p> - -<p>厂模式可以完全利用函数来做, 状态可以保存在全局变量中; 但是使用类的方式来实现厂模式还有更多的好处. 其一是: 我们可以管理从 <code>nsISupports</code> 接口派生而来的类厂本身的生存期. 当我们试图把多个类厂划分成一组, 然后确定是否能卸载这一组类厂的时候, 这一点非常重要. 另一个好处是: 类厂可以引入其他需要支持的接口. 在我们后面讨论 <code>nsIClassInfo</code> 接口的时候, 我们会看到某些类厂使用这个接口支持信息查询, 诸如这个对象是用什么语言写的, 对象支持的接口等等. 这种派生自 <code>nsISupports</code> 的 "future-proofing" 特性非常关键.</p> - -<h4 id="XPIDL_.E4.B8.8E.E7.B1.BB.E5.9E.8B.E5.BA.93" name="XPIDL_.E4.B8.8E.E7.B1.BB.E5.9E.8B.E5.BA.93">XPIDL 与类型库</h4> - -<p>定义接口的简单而强劲的方法是使用<em>接口定义语言</em>(IDL) - 这实际上是在一个跨平台而语言无关开发环境下定义接口的需求. XPCOM 使用的是源自于 CORBA OMG 接口定义语言(IDL)的变体, 称为 XPIDL, 来定义接口, XPIDL 可以定义接口的方法, 属性, 常量, 以及接口继承.</p> - -<p>采用 XPIDL 定义接口还存在一些缺陷. 它不支持多继承, 同时 XPIDL 定义的方法名不能相同,你不能有两个相同名字但是所接受的参数不同的函数. - 不能像 C++ 语言的成员函数一样通过参数不同重载, 毕竟接口同时要支持类似于 C 这样的语言.</p> - -<pre>void FooWithInt(in int x); -void FooWithString(in string x); -void FooWithURI(in nsIURI x); -</pre> - -<p>然而尽管有这些问题, XPIDL 的功能仍然是非常强大的. XPIDL 能自动生成以 <em>.xpt</em> 为后缀的<em>类型库</em>, 或者说 typelibs. 类型库是接口的二进制表示, 它向非 C++ 语言提供接口的访问与控制. 非 C++ 语言通过类型库来了解接口支持哪些方法, 如何调用这些方法, 这称为 <em>XPConnect</em>. XPConnect 是 XPCOM 向类似于 JavaScript 这样的语言提供组件访问的 Wrapper. 参看<a href="/cn/Creating_XPCOM_Components/Using_XPCOM_Components#Connecting_to_Components_from_the_Interface" title="cn/Creating_XPCOM_Components/Using_XPCOM_Components#Connecting_to_Components_from_the_Interface">Connecting to Components from the Interface</a>获取更多关于 XPConnect 的信息.</p> - -<p>从其他类型的语言访问接口, 常常说成是接口被<em>反射(reflected)</em>到这种语言. 每一个被反射的接口必须提供相应的类型库. 当前可以使用 C, C++, 和 JavaScript 来编写组件.</p> - -<div class="side-note"> -<p><span id="%E4%BD%BF%E7%94%A8%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%BC%96%E5%86%99%E7%BB%84%E4%BB%B6"><a id="%E4%BD%BF%E7%94%A8%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%BC%96%E5%86%99%E7%BB%84%E4%BB%B6"></a><strong>使用其他语言编写组件</strong></span></p> - -<p>在使用其他语言创建组件的时候, 不需要利用 XPCOM 提供给 C++ 程序员的工具(诸如一些宏, 智能指针等等, 我们可以方便的利用到这种语言本身来创建组件. 比如说, 基于 Python 的 XPCOM 组件可以从 JavaScript 来调用.</p> - -<p>参看 <a href="/cn/Creating_XPCOM_Components/Resources" title="cn/Creating_XPCOM_Components/Resources">Resources</a> 获取更多使用其他语言来创建组件的信息.</p> -</div> - -<p>所有的 XPCOM 接口都用 XPIDL 语法来定义. <em>xpidl 编译器</em>会从这个 IDL 文件产生类型库和 C++ 头文件. 在<a href="/cn/Creating_XPCOM_Components/Starting_WebLock#Defining_the_WebLock_Interface_in_XPIDL" title="cn/Creating_XPCOM_Components/Starting_WebLock#Defining_the_WebLock_Interface_in_XPIDL">Defining the WebLock Interface in XPIDL</a> 一节详细描述了 XPIDL 语法.</p> - -<h3 id="XPCOM_.E6.9C.8D.E5.8A.A1" name="XPCOM_.E6.9C.8D.E5.8A.A1">XPCOM 服务</h3> - -<p>当客户需要某个组件提供的功能的时候, 通常都是<em>实例化</em>一个新的组件对象. 比如说, 客户程序需要某些处理文件, 这里每个组件就代表一个文件, 客户可能会同时处理多个这样的组件.</p> - -<p>但是在某些情况下对象表示的是一种<em>服务</em>, 这种服务只能有一个拷贝(尽管会有多个服务同时运行). 每次客户程序访问服务提供的功能时, 客户程序都是与同一个服务实例在打交道. 比如说, 一个用户查询公司的电话号码数据库, 数据库作为一个<em>对象</em>对用户来说都是同一的. 如若不然的话, 就需要维护两个数据库拷贝, 这种开销将非常大, 而且还存在数据内容不一致的问题. 单件设计模式就是提供系统中需要的这种单点访问功能.</p> - -<p>XPCOM 不仅提供了对组件的支持和管理服务, 它还包含了许多编写跨平台组件所需要的其他服务. 其中包括: 跨平台文件抽象, 向 XPCOM 开发人员提供同一而强大的文件访问功能. 目录服务, 提供应用和特定系统定位信息. 内存管理, 保证所有对象使用同样的内存分配器. 事件通知机制, 允许传递简单消息. 本教程将在后面展现如何使用这些服务, <a href="/cn/XPCOM_API_Reference" title="cn/XPCOM_API_Reference">XPCOM API Reference</a> 一节有完整的接口索引列表.</p> - -<h3 id="XPCOM_.E7.B1.BB.E5.9E.8B" name="XPCOM_.E7.B1.BB.E5.9E.8B">XPCOM 类型</h3> - -<p>XPCOM 声明了许多数据类型和简单宏, 这些东西将在我们后面的例子中看到. 大多数的宏都是简单的重定义, 下一节我们会描述一些最常用的数据类型.</p> - -<h4 id=".E6.96.B9.E6.B3.95.E7.B1.BB.E5.9E.8B" name=".E6.96.B9.E6.B3.95.E7.B1.BB.E5.9E.8B">方法类型</h4> - -<p>下面的类型用在 XPCOM 方法调用的参数和返回值定义中.</p> - -<table class="standard-table"> - <tbody> - <tr> - <td><code>NS_IMETHOD</code></td> - <td>声明方法返回值. XPCOM 的方法缺省的返回值声明.</td> - </tr> - <tr> - <td><code>NS_IMETHODIMP</code></td> - <td>方法实现返回值. XPCOM 方法函数返回的时候缺省采用这种类型的返回值.</td> - </tr> - <tr> - <td><code>NS_IMETHODIMP_(type)</code></td> - <td>特定类型的方法实现返回值. 诸如 <code>AddRef</code> 和 <code>Release</code> 的方法不返回缺省类型, 这种返回值的不一致虽然有点不舒服, 但是必需的.</td> - </tr> - <tr> - <td><code>NS_IMPORT</code></td> - <td>共享库内部使用的符号局部声明</td> - </tr> - <tr> - <td><code>NS_EXPORT</code></td> - <td>共享库导出的符号声明.</td> - </tr> - </tbody> -</table> - -<h4 id=".E5.BC.95.E7.94.A8.E8.AE.A1.E6.95.B0" name=".E5.BC.95.E7.94.A8.E8.AE.A1.E6.95.B0">引用计数</h4> - -<p>下面的宏提供对引用计数的基本操作.</p> - -<table class="standard-table"> - <tbody> - <tr> - <td><code>NS_ADDREF</code></td> - <td>调用 <code>nsISupports</code> 对象的 <code>AddRef</code> 方法.</td> - </tr> - <tr> - <td><code>NS_IF_ADDREF</code></td> - <td>与上一个方法类似, 不同之处在于这个宏在<code>AddRef之前</code>会检查对象指针是否为空(虚函数指针).</td> - </tr> - <tr> - <td><code>NS_RELEASE</code></td> - <td>调用 <code>nsISupports</code> 对象的 <code>Release</code> 方法.</td> - </tr> - <tr> - <td><code>NS_IF_RELEASE</code></td> - <td>与上一个方法类似, 不同之处在于这个宏<code>在调用Release</code>之前会检查空指针.</td> - </tr> - </tbody> -</table> - -<h3 id=".E7.8A.B6.E6.80.81.E7.A0.81" name=".E7.8A.B6.E6.80.81.E7.A0.81">状态码</h3> - -<p>下面的宏测试状态码.</p> - -<table class="standard-table"> - <tbody> - <tr> - <td><code>NS_FAILED</code></td> - <td>如果传递的状态码为失败, 则返回真.</td> - </tr> - <tr> - <td><code>NS_SUCCEEDED</code></td> - <td>如果传递的状态码为成功, 则返回真.</td> - </tr> - </tbody> -</table> - -<h3 id=".E5.8F.98.E9.87.8F.E6.98.A0.E5.B0.84" name=".E5.8F.98.E9.87.8F.E6.98.A0.E5.B0.84">变量映射</h3> - -<table class="standard-table"> - <tbody> - <tr> - <td><code>nsrefcnt</code></td> - <td>缺省的引用计数类型, 是一个 32-bit 整数.</td> - </tr> - <tr> - <td><code>nsresult</code></td> - <td>缺省数据类型, 是一个 32-bit 整数.</td> - </tr> - <tr> - <td><code>nsnull</code></td> - <td>缺省 null 类型.</td> - </tr> - </tbody> -</table> - -<h3 id=".E9.80.9A.E7.94.A8_XPCOM_.E9.94.99.E8.AF.AF.E7.A0.81" name=".E9.80.9A.E7.94.A8_XPCOM_.E9.94.99.E8.AF.AF.E7.A0.81">通用 XPCOM 错误码</h3> - -<table class="standard-table"> - <tbody> - <tr> - <td><code>NS_ERROR_NOT_INITIALIZED</code></td> - <td>如果实例未初试化, 返回该值.</td> - </tr> - <tr> - <td><code>NS_ERROR_ALREADY_INITIALIZED</code></td> - <td>如果实例已初试化, 返回该值.</td> - </tr> - <tr> - <td><code>NS_ERROR_NOT_IMPLEMENTED</code></td> - <td>如果方法未实现, 返回该值.</td> - </tr> - <tr> - <td><code>NS_ERROR_NO_INTERFACE</code></td> - <td>如果组件不支持某种类型接口, 返回该值.</td> - </tr> - <tr> - <td><code>NS_ERROR_NULL_POINTER</code></td> - <td>如果指针指向 <code>nsnull</code>, 返回该值 .</td> - </tr> - <tr> - <td><code>NS_ERROR_FAILURE</code></td> - <td>如果某个方法失效, 返回该值, 这时一个通用的错误值.</td> - </tr> - <tr> - <td><code>NS_ERROR_UNEXPECTED</code></td> - <td>如果一个未预料的错误发生, 返回该值.</td> - </tr> - <tr> - <td><code>NS_ERROR_OUT_OF_MEMORY</code></td> - <td>如果无法进行内存分配, 返回该值.</td> - </tr> - <tr> - <td><code>NS_ERROR_FACTORY_NOT_REGISTERED</code></td> - <td>如果一个请求的类型未注册, 返回该值.</td> - </tr> - </tbody> -</table> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/创建_XPCOM_组件:前言" style="float: left;">« 上一页</a><a href="/zh-CN/docs/创建_XPCOM_组件:使用_XPCOM_组件">下一页 »</a></p> -</div> <p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> - -<p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/building_the_weblock_ui/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/building_the_weblock_ui/index.html deleted file mode 100644 index 51f544fb16..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/building_the_weblock_ui/index.html +++ /dev/null @@ -1,297 +0,0 @@ ---- -title: Building the WebLock UI -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/Building_the_WebLock_UI -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/Building_the_WebLock_UI ---- -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Finishing_the_Component" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Packaging_WebLock">下一页 »</a></p> -</div><p></p> - -<p>到目前为止我们建立了一个可以安装到Gecko应用中的组件。你所使用的XPCOM接口和工具是通用的跨平台的,可以被Gecko Runtime Environment或者任何Mozilla1.2以后任何基于Gecko的应用(这时GRE已经可用)。</p> - -<p>本章,我们将建立<strong>WebLock</strong>组件的用户接口,这就意味着添加到<em>现有的</em> Mozilla 浏览器<sup><a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components/Building_the_WebLock_UI#endnote_other-mozlike-browsers">[other-mozlike-browsers]</a></sup>. 他使用 <abbr title="XML UI Language">XUL</abbr>, 这是一个Gecko知道如何呈现用户界面的XML语言, 同时它也跟特定的Mozilla用户界面交互, 为此它要把自己作为UI的扩展安装起来. Specifically, the user interface we create in this chapter will be<em>overlaid</em> into the statusbar of the browser component, where it will provide a small icon the user can click to access the web lock interface.</p> - -<p><span id="WebLock_Indicator_in_Browser"><a id="WebLock_Indicator_in_Browser"></a><strong>WebLock Indicator in Browser</strong></span></p> - -<p><img alt="Image:web-lock-ui.png"></p> - -<h3 id="User_Interface_Package_List" name="User_Interface_Package_List">User Interface Package List</h3> - -<p>本章所描述的用户界面包括4个文件:</p> - -<ul> - <li><code>webLockOverlay.xul</code> is the file that defines the little status icon in the browser.</li> - <li><code>weblock.xul</code> defines the web lock manager dialog.</li> - <li><code>weblock.css</code> provides style rules for both of the XUL files.</li> - <li><code>weblock.js</code> provides JavaScript functions for both of the XUL files.</li> -</ul> - -<p>下面章节描述每个文件的功能。. In the following chapter we'll describe how you can take these files and create a<em>package</em> , an installable archive that includes the <strong>WebLock</strong> component and the new UI.</p> - -<p>因为这些步骤 (特别是 overlay section) 与Mozilla非常相关, the chapter is divided up into a couple of different sections. 第二部分, <a href="#XUL">XUL</a>, 描述XML-based 用户接口语言 (XUL) 以及他如何创建一个对话框访问<strong>WebLock</strong> 组件和它的服务. 第三部分, <a href="#Overlaying_New_User_Interface_Into_Mozilla">Overlaying New User Interface Into Mozilla</a>, 描述如何建立一个overlay到浏览器以便Mozilla build能访问这个对话框. 在overlay section, 我们讨论如何从Mozilla导入scripts, images, 和其他资源到你的 UI, 这会是比较复杂的部分.</p> - -<p>If the <strong>WebLock</strong> component is being installed in Mozilla or another Gecko-based browser, then this third section shows you how to create the entry point in the browser for controlling the web locking. If you are planning on deploying the <strong>WebLock</strong> component in some other application, you'll have to devise a different means of access (e.g., native widgetry that instantiates and controls the <strong>WebLock</strong> component).</p> - -<h3 id="Client_Code_Overview" name="Client_Code_Overview">Client Code Overview</h3> - -<p>在我们开始实际用户界面以前,我们应该首先建立访问<strong>WebLock</strong>组件和它的接口来控制browser的Web locking的客户代码.</p> - -<p>首先, it's important to be able to 表达Lock的基本状态as soon as it's loaded. 如同安全网页icon, weblock icon 在browser右下角,提示browser是否当前是锁定的. Since the <strong>WebLock</strong> component is always initialized as unlocked, we can have the 客户代码 - 接口中的JavaScript代码 - 表达并跟踪状态 as the user manipulates the <code>iWebLock</code> interface. A boolean <code>wLocked</code> variable can do this:</p> - -<pre>// initialize the wLocked variable as unlocked -var wLocked = 0; -</pre> - -<p>Then the functions that get called from the interface and call through to the <code>lock</code> and <code>unlock</code> methods of the <strong>WebLock</strong> component must also adjust this variable accordingly:</p> - -<pre>function wLock() -{ - // check to see if locking is on or off - weblock.lock(); - wLocked = 1; -} - -function wUnLock() -{ - // check to see if locking is on or off - weblock.unlock(); - wLocked = 0; -} -</pre> - -<p>这些函数的前提是<strong>WebLock</strong> 组件对于 JavaScript可见,in the form of the <code>weblock</code> object being used in the snippets above. As you can see, <code>weblock</code> is initialized as a global JavaScript variable, available in the scope of these functions and others:</p> - -<pre>var weblock = Components.classes["@dougt/weblock"] - .getService() - .QueryInterface(Components.interfaces.iWebLock); -</pre> - -<p>In addition to this basic setup, you must also write JavaScript that uses the <code>AddSite</code> method to add new sites to the white list. This is a bit more complicated, because it requires that you work with the currently loaded page or provide other UI (e.g., a textfield where you can enter an arbitrary URL) for specifying URLs. In the <a href="#XUL">XUL</a> section we'll go into how the user interface is defined. This section describes the functions that are called from the interface and how they interact with the <strong>WebLock</strong> component.</p> - -<p>The URL that the <code>AddSite</code> method expects is a string, so we can pass a string directly in from the user interface, or we can do a check on the string and verify that it's a valid URL. In this tutorial, focusing as it is on the <strong>WebLock</strong> functionality (rather than the UI), we'll assume the strings we get from the UI itself are URLs we actually want to write to the white list:</p> - -<pre>function addThisSite() -{ - var tf = document.getElementById("dialog.input"); - // weblock is global and declared above - weblock.AddSite(tf.value); -} -</pre> - -<p>这段javascript可以直接被 XUL widget调用, where the input string is retrieved as the <code>value</code> property of the <code>textbox</code> element.</p> - -<p>你还需要建立一个函数当用户点击weblock icon的时候来显示<strong>WebLock</strong> 窗口. That function uses the <code>openDialog</code> method from the <code>window</code> object and takes the URL to the XUL file in which the dialog is defined:</p> - -<pre>function loadWebLock() -{ - window.openDialog("chrome://weblock/weblock.xul"); -} -</pre> - -<h3 id="XUL" name="XUL">XUL</h3> - -<p>The entire user interface of the Mozilla browser and all of the applications that go with it, including the mail client, the IRC client, and others, have been defined in an XML language called XUL. Elements in the XUL markup map to widgets in the interface that Gecko renders in a fairly straightforward way - so, for instance, the root element of an application window is the element <code><window/></code>, the root element of the dialog we'll be creating here is <code><dialog/></code>, and so forth. Within a XUL application file, elements like <code><button/></code>, <code>menu/></code>, and <code>checkbox/></code> can be hooked up to an event model, to scripts, and to the XPCOM interfaces that carry out a lot of the browser functionality in Mozilla.</p> - -<p>In <a href="cn/Creating_XPCOM_Components/Using_XPCOM_Components">Using XPCOM Components</a> you saw how XPCOM objects are reflected into the interface layer as JavaScript objects. In this chapter, now that we've created the <strong>WebLock</strong> component and made it available to XPCOM, we create the UI that actually instantiates the <strong>WebLock</strong> component and uses its methods to control page loading in the browser.</p> - -<p>In the previous section, we outlined the JavaScript that interacts with the <strong>WebLock</strong> component. In this section, we are going to create the XUL interface that calls the JavaScript methods when the user interacts with it.</p> - -<h4 id="The_XUL_Document" name="The_XUL_Document">The XUL Document</h4> - -<p>The first thing to do is create the actual XUL document in which the user interface for the dialog and the events that initiate interaction with the web locking are defined. At the top of all XUL documents, an XML declaration is followed by the root element for the document, which is usually <code><window/></code> 对于对话框,也可以是<code><dialog/></code>. The "shell" for the XUL file, then, looks like this:</p> - -<pre><?xml version="1.0"?> -<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> - -<dialog id="weblock_ui" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - title="Web Lock Manager" - persist="screenX screenY" - screenX="24" screenY="24"> - -</dialog> -</pre> - -<p>注意这部分XUL文件也包含了stylesheet declaration, which imports CSS rules and applies them to particular parts of the interface. In Gecko, CSS 被用来几乎控制所有的XUL界面表现 - its color, position, style, and to some extent its behavior as well. The web lock manager dialog does not deviate from the look of a standard dialog, so it can use a single declaration to import the "global" skin from the browser and make it available to the widgets you define in <code>weblock.xul</code>.</p> - -<p>You can save this first, 最外层的web lock dialog部分称为<code>weblock.xul</code>, 你要把它放在附录B所描述的安装包里.</p> - -<div class="side-note"> -<p>注意这个文件包含了当用户/管理员点击web locking icon的时候弹出的对话框. 这部分UI - 需要动态地装载到Mozilla runtime - 在<a href="#Overlaying_New_User_Interface_Into_Mozilla">Overlaying New User Interface Into Mozilla</a>.</p> -</div> - -<p>描述</p> - -<p>最终的对话框看起来是.</p> - -<p><span id="Web_Lock_Manager_Dialog"><a id="Web_Lock_Manager_Dialog"></a><strong>Web Lock Manager Dialog</strong></span></p> - -<p><img alt="Image:Weblock-sitelist-ui.png"></p> - -<p>As you can see, it's a simple interface, providing just enough widgetry to lock and unlock the browser and to add new sites to the list. The entire XUL file for the web lock manager dialog is defined in <a href="#weblock.xul">weblock.xul</a> below.</p> - -<h4 id="The_Locking_UI" name="The_Locking_UI">The Locking UI</h4> - -<p>Once you have the basic XUL wrapper set up for your interface, the next step is to define that part of the interface that locks and unlocks the browser. One of the most efficient ways to expose this is to use radio buttons, which allow the user to toggle a particulart state, as the figure above illustrates.</p> - -<p>In XUL individual <code><radio/></code> elements are contained within a parent element called <code><radiogroup/></code>. Grouping radio elements together creates the toggling UI by requiring that one or another of the elements be selected, but not both.</p> - -<p>The XUL that defines the radiogroup in the web lock manager dialog is this:</p> - -<pre><radiogroup> - <radio label="lock"/> - <radio label="unlock" selected="true"/> -</radiogroup> -</pre> - -<p>Since the <strong>WebLock</strong> component always starts up in the unlocked position, you can add the <code>selected="true"</code> attribute and value on the unlock radio button and reset it dynamically as the user takes action.</p> - -<h4 id="Site_Adding_UI" name="Site_Adding_UI">Site Adding UI</h4> - -<p>The next step is to create that part of the user interface that lets you add a new site to the white list. There are other, more sophisticated ways to do this; you may also want to include some UI that lets you view the white list or edit it as a list. In this part of the tutorial, however, we only provide the means of adding an URL provided as a string (which is not checked for validity) and passing it through to the <code>AddSite</code> API we defined in the earlier part of the tutorial.</p> - -<pre><separator class="thin"/> - -<hbox align="center"> - <textbox id="url.input" flex="1"/> - <button label="Add this URL" oncommand="addThisSite();"/> -</hbox> -</pre> - -<p>This snippet introduces a couple of new general layout widgets in XUL. The separator that appears at the top of this snippet creates a little divider between widgets like the kind you see in menus that divide sets of functionality available there. The parent of the textbox that users enter an URL into is something called an <code><hbox/></code>, which is a layout widget - often invisible - that controls the way its child elements are rendered. In this case the <code><hbox/></code> centers the textbox and the button children, and it orients them horizontally (in contrast to the <code><vbox/></code>, which orients its children vertically).</p> - -<p>Notice also that when it's clicked, the button executes a JavaScript function called <code>addThisSite()</code>, which we've already defined in the <code>weblock.js</code> file in <a href="#Client_Code_Overview">Client Code Overview</a> above.</p> - -<h4 id="weblock.xul" name="weblock.xul"><code>weblock.xul</code></h4> - -<pre><?xml version="1.0"?> -<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> - -<dialog id="weblock_mgg" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - title="Web Lock Manager" - style="width: 30em;" - persist="screenX screenY" - screenX="24" screenY="24"> - - <script src="chrome://weblock/content/weblock.js"/> - - <hbox> - <separator orient="vertical" class="thin"/> - <vbox flex="1"> - <separator class="thin"/> - <hbox align="center"> - <textbox id="dialog.input" flex="1"/> - <button label="Add this URL" - oncommand="addThisSite();"/> - </hbox> - <hbox align="center"> - <radiogroup onchange="toggleLock();"> - <radio label="lock"/> - <radio label="unlock"/> - </radiogroup> - <spacer flex="1"/> - </hbox> - </vbox> - </hbox> - -</dialog> -</pre> - -<h3 id="Overlaying_New_User_Interface_Into_Mozilla" name="Overlaying_New_User_Interface_Into_Mozilla">Overlaying New User Interface Into Mozilla</h3> - -<p>你已经有了一个可以跟<strong>WebLock</strong>组件交互的对话框, 但是你怎么把它装到browser中? 然后你怎么访问它呢? 当安装和准备好以后,<strong>WebLock</strong> 组件已经可以用了: XPCOM finds it and adds it to the list of registered components, and then WebLock observes the XPCOM startup event and initializes itself.</p> - -<p>But you still have to add your new UI into the browser so it can call the component, and the Mozilla overlay mechanism is the way to do this. Overlays 是 XUL文件可以用来注册他们自己以便动态地嵌入到Browser UI合适的位置.</p> - -<h4 id="webLockOverlay.xul" name="webLockOverlay.xul"><code>webLockOverlay.xul</code></h4> - -<p>The XUL that defines the new icon is small: 这是一个调用JavaScript function来装载前面我们定义的<code>weblock.xul</code> 文件的小图表. The icon is actually a separate <code><statusbarpanel/></code> element that gets overlaid into the main browser, along with some JavaScript and some CSS to control the behavior and appearance of the element, respectively. Here is that XUL file in its entirety:</p> - -<p><span id="The_WebLock_Overlay"><a id="The_WebLock_Overlay"></a><strong>The WebLock Overlay</strong></span></p> - -<pre><?xml version="1.0"?> -<?xml-stylesheet href="chrome://navigator/content/weblock.css" type="text/css"?> - -<overlay id="weblockOverlay" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - - <script type="application/x-javascript" - src="chrome://weblock/content/weblock.js"/> - - <statusbar id="status-bar"> - <statusbarpanel class="statusbarpanel-iconic" - id="weblock-status" - insertbefore="offline-status" - oncommand="loadWebLock();" - status="none"/> - </statusbar> - -</overlay> -</pre> - -<p>文件的根元素不是<code><window/></code> 而是<code><overlay/></code>. In overlays 被 XUL elements用来把他们和其他元素相区分的<code>id</code>属性被设置称为browser中他们要嵌入部分的值. In this case, the weblock <code><statusbarpanel/></code> appears as a child of the <code><statusbar/></code> element with <code>id</code> "status-bar". This <code>id</code> is the same one used by the <code><statusbar/></code> in <code>navigator.xul</code>, which means that the overlay mechanism will merge the new UI here (i.e., the weblock statusbarpanel) and the UI already defined within that browser <code><statusbar/></code> at runtime.</p> - -<h3 id="Other_Resources" name="Other_Resources">Other Resources</h3> - -<p>这部分描述剩下的需要添加和打包到<strong>WebLock</strong>组件来提供web locking用户界面的文件。</p> - -<div class="side-note"> -<p><span id="Other_Front_End_Resources"><a id="Other_Front_End_Resources"></a><strong>Other Front End Resources</strong></span></p> - -<p>在某些UI包中, 本地化 resources are also defined. These include DTDs in which the language in which the UI is labelled can be extracted into external files, which are swapped with DTDs for other languages. For example, user interface packages often include an English DTD that defines labels and strings for button and menus and other elements in the interface. When the user selects a different<em>language pack</em> , all of the English that's been externalized in these files is dynamically replaced with the new choice. In addition to DTDs, the localization parts of a user interface may also include string bundles in which strings that are used in the interface JavaScript can be similarly replaced. 有一些技术通过单独的文件来提供这种功能. 包含<em>bindings</em> in XML files,<em>metadata</em> in RDF files, whole collections of CSS files called<em>skins</em> , and others.</p> -</div> - -<h4 id="weblock.css" name="weblock.css">weblock.css</h4> - -<p>The following style rules are defined in <code>weblock.css</code>, a CSS file that is loaded by the overlay and applied to the icon in the browser that reflects the current status of the web lock and provides access to the web lock manager dialog.</p> - -<pre>statusbarpanel#weblock-status -{ - list-style-image: url("chrome://weblock/wlock.gif"); -} - -statusbarpanel#weblock-status[status="locked"] -{ - list-style-image: url("chrome://weblock/wl-lock.gif"); -} - -statusbarpanel#weblock-status[status="unlocked"] -{ - list-style-image: url("chrome://weblock/wl-un.gif"); -} -</pre> - -<p>The style rules are distinguished by the state of the <code>status</code> attribute on the element in the XUL with the <code>id</code> "weblock-status." As you can see above, when the status of the element is set to "locked", the image <code>wl-lock.gif</code> is used to show the state, and when the web locking is unlocked, it uses <code>wl-un.gif</code>. (Note: We include three images to represent the state of the weblock, but <code>wlock.gif</code> and <code>wl-lock.gif</code> are identical, since weblock is presumed to be unlocked when it's loaded. This tutorial makes use of only two different states, but you can further customize the look of the weblock using the three images if you wish.)</p> - -<p>Since the presentation of the weblock manager dialog itself doesn't require any special styles, these are all the rules you need in the <code>weblock.css</code>. Note that the <code>weblock.xul</code> file in which the manager is defined imports only the global skin:</p> - -<pre><?xml-stylesheet href="chrome://global/skin/" type="text/css"?> -</pre> - -<p>Save <code>weblock.css</code> in your working directory.</p> - -<p>You should now have the four files listed at the top of this chapter as the "packing list" for the <strong>WebLock</strong> package (see <a href="#User_Interface_Package_List">User Interface Package List</a>). Don't worry for now about where these files are. 下一章, <a href="cn/Creating_XPCOM_Components/Packaging_WebLock">Packaging WebLock</a>, 我们讨论如何打包这些文件以便 <strong>WebLock</strong> 组件或者别的资源利用它们.</p> - -<h4 id="Image_Resources" name="Image_Resources">Image Resources</h4> - -<p>如果你学习本教程并且希望使用<strong>WebLock</strong>组件在statusbar中的图片,你可以从 <a class="external" href="http://www.brownhen.com/weblock下载他们和其他" rel="freelink">http://www.brownhen.com/weblock下载他们和其他</a><strong>weblock</strong>相关资源. The GIF files that represent the various states are:</p> - -<ul> - <li><code>wlock.gif</code></li> - <li><code>wl-lock.gif</code></li> - <li><code>wl-un.gif</code></li> -</ul> - -<ol> - <li><div class="blockIndicator note"><strong>Note:</strong> other-mozlike-browsers</div> 或者你可能会很喜欢这些东西. 还有一些基于 Gecko的browsers ,例如Beonex 和 IBM Web Browser 也会共享很多Mozilla用户界面成分, 你也可能装载 <strong>WebLock</strong> 组件和用户界面到其中. 不过请注意, <strong>WebLock</strong>有可能还不能保证完全安装到Mozilla Firefox,因为firefox有一些新的变化 (这本书是2003的版本).</li> -</ol> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Finishing_the_Component" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Packaging_WebLock">下一页 »</a></p> -</div> <p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/component_internals/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/component_internals/index.html deleted file mode 100644 index d29da9a71d..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/component_internals/index.html +++ /dev/null @@ -1,217 +0,0 @@ ---- -title: Component Internals -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/Component_Internals -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/Component_Internals ---- -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/创建_XPCOM组件/使用XPCOM组件" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components/Creating_the_Component_Code">下一页 »</a></p> -</div> 前几章以组件使用者的角度介绍了XPCOM 组件, 本章将以软件开发者的角度讨论XPCOM.您可以继续阅读以明白XPCOM的一般实现方式, 或者您也可以跳到下一章, 在下一章,以WebLock为例向一步一步您介绍 组件的开发过程。 <span class="comment">XXX mediawiki...</span><span class="comment">XXX sucks</span><p></p> - -<h3 id="Creating_Components_in_C.2B.2B" name="Creating_Components_in_C.2B.2B">使用C++创建组件</h3> - -<p>让我们开始研究怎样用c++创建XPCOM组件. 最常见的组件是以C++编写并编译成共享库(如Windows平台的DLL或者Unix平台的DSO)。</p> - -<p>The illustration below shows the basic relationship between the shared library containing the component implementation code you write and the XPCOM framework itself. In this diagram, the outer boundary is that of the module, the shared library in which a component is defined.</p> - -<p><span id="A_Component_in_the_XPCOM_Framework"><a id="A_Component_in_the_XPCOM_Framework"></a><strong>A Component in the XPCOM Framework</strong></span></p> - -<p><img alt="Image:component-internals-framework.png" class="internal" src="/@api/deki/files/615/=Component-internals-framework.png"></p> - -<p>When you build a component or module and compile it into a library, it must export a single method named <code>NSGetModule</code>. This <code>NSGetModule</code> function is the entry point for accessing the library. It gets called during registration and unregistration of the component, and when XPCOM wants to discover what interfaces or classes the module/library implements. In this chapter we will outline this entire process.</p> - -<p>As <a href="#A_Component_in_the_XPCOM_Framework">A Component in the XPCOM Framework</a> illustrates, in addition to the <code>NSGetModule</code> entry point, there are <code>nsIModule</code> and <code>nsIFactory</code> interfaces that control the actual creation of the component, and also the string and XPCOM glue parts, which we'll discuss in some detail in the next section (see <a href="/en/Creating_XPCOM_Components/Component_Internals#XPCOM_Glue" title="en/Creating_XPCOM_Components/Component_Internals#XPCOM_Glue">XPCOM Glue</a>). These latter supply ease-of-development utilities like smart pointers, generic modules support, and simple string implementations. The largest and possibly most complex part of a component is the code specific to the component itself.</p> - -<div class="side-note"> -<p><span id="But_Where_Are_the_Components?"><a id="But_Where_Are_the_Components?"></a><strong>But Where Are the Components?</strong></span></p> - -<p>Components reside in modules, and those modules are defined in shared library files that typically sit in the <em>components</em> directory of an XPCOM application.</p> - -<p>A set of default libraries stored in this components directory makes up a typical Gecko installation, providing functionality that consists of networking, layout, composition, a cross-platform user interface, and others.</p> - -<p>Another, even more basic view of this relationship of components to the files and interfaces that define them is shown in <a href="/en/Creating_XPCOM_Components/Creating_the_Component_Code" title="en/Creating_XPCOM_Components/Creating_the_Component_Code">Onion Peel View of XPCOM Component Creation</a> in the next chapter. The component is an abstraction sitting between the actual module in which it is implemented and the objects that its factory code creates for use by clients.</p> -</div> - -<h3 id="XPCOM_Initialization" name="XPCOM_Initialization">XPCOM Initialization</h3> - -<p>To understand why and when your component library gets called, it is important to understand the XPCOM initalization process. When an application starts up, that application may <em>initialize</em> XPCOM. The sequence of events that kicks off this XPCOM initialization may be triggered by user action or by the application startup itself. A web browser that embeds Gecko, for example, may initialize XPCOM at startup through the embedding APIs. Another application may delay this startup until XPCOM is needed for the first time. In either case, the initialization sequence within XPCOM is the same.</p> - -<p>XPCOM starts when the application makes a call to initialize it. Parameters passed to this startup call allow you to configure some aspects of XPCOM, including the customization of location of specific directories. The main purpose of the API at this point is to change which <em>components</em> directory XPCOM searches when it looks for XPCOM components. This is how the API is used, for example, in the <em>Gecko Runtime Environment</em> (GRE).</p> - -<div class="side-note"> -<p><span id="XPCOM_Startup"><a id="XPCOM_Startup"></a><strong>XPCOM Startup</strong></span></p> - -<p>The six basic steps to XPCOM startup are as follows:</p> - -<ol> - <li>Application starts XPCOM.</li> - <li>XPCOM sends a notification that it's beginning startup.</li> - <li>XPCOM finds and processes the <em>component manifest</em> (see <a href="#Component_Manifests">Component Manifests</a> below).</li> - <li>XPCOM finds and processes the <em>type library manifest</em> (see <a href="#Type_Library_Manifests">Type Library Manifests</a> below).</li> - <li>If there are new components, XPCOM registers them: - <ol> - <li>XPCOM calls autoregistration start.</li> - <li>XPCOM registers new components.</li> - <li>XPCOM calls autoregistration end.</li> - </ol> - </li> - <li>Complete XPCOM startup: XPCOM notifies that it's begun.</li> -</ol> - -<p>Component manifests and type library manifests are described in the following section, <a href="#XPCOM_Registry_Manifests">XPCOM Registry Manifests</a>.</p> -</div> - -<h4 id="XPCOM_Registry_Manifests" name="XPCOM_Registry_Manifests">XPCOM Registry Manifests</h4> - -<p>XPCOM uses special files called manifests to track and persist information about the components to the local system. There are two types of manifests that XPCOM uses to track components:</p> - -<h5 id="Component_Manifests" name="Component_Manifests">Component Manifests</h5> - -<p>When XPCOM first starts up, it looks for the <em>component manifest</em>, which is a file that lists all registered components, and stores details on exactly what each component can do. XPCOM uses the component manifest to determine which components have been overridden. Starting with Mozilla 1.2, this file is named <code>compreg.dat</code> and exists in the <em>components</em> directory, but there are efforts to move it out of this location to a less application-centric (and thus more user-centric) location. Any Gecko-based application may choose to locate it elsewhere. XPCOM reads this file into an in-memory database.</p> - -<div class="side-note"> -<p><span id="Component_Manifests"><a id="Component_Manifests"></a><strong>Component Manifests</strong></span></p> - -<p>The component manifest is a mapping of files to components and components to classes. It specifies the following information:</p> - -<ul> - <li>Location on disk of registered components with file size</li> - <li>Class ID to Location Mapping</li> - <li>Contract ID to Class ID Mapping</li> -</ul> - -<p>The component manifest maps component files to unique identifiers for the specific implementations (class IDs), which in turn are mapped to more general component identifiers (contract IDs).</p> -</div> - -<h5 id="Type_Library_Manifests" name="Type_Library_Manifests">Type Library Manifests</h5> - -<p>Another important file that XPCOM reads in is the <em>type library manifest</em> file. This file is also located in the <em>components</em> directory and is named <code>xpti.dat</code>. It includes the location and search paths of all type library files on the system. This file also lists all known interfaces and links to the type library files that define these interface structures. These type library files are at the core of XPCOM scriptablity and the binary component architecture of XPCOM.</p> - -<div class="side-note"> -<p><span id="Type_Library_Manifests"><a id="Type_Library_Manifests"></a><strong>Type Library Manifests</strong></span></p> - -<p>Type library manifests contain the following information:</p> - -<ul> - <li>location of all type library files</li> - <li>mapping of all known interfaces to type libraries where these structures are defined</li> -</ul> -</div> - -<p>Using the data in these two manifests, XPCOM knows exactly which component libraries have been installed and what implementations go with which interfaces. Additionally, it relates the components to the type libraries in which the binary representations of the interfaces they support are defined.</p> - -<p>The next section describes how to hook into the XPCOM startup and registration process and make the data about your component available in these manifests, so that your component will be found and registered at startup.</p> - -<h4 id="Registration_Methods_in_XPCOM" name="Registration_Methods_in_XPCOM">Registration Methods in XPCOM</h4> - -<div class="side-note"> -<p><span id="What_Is_XPCOM_Registration?"><a id="What_Is_XPCOM_Registration?"></a><strong>What Is XPCOM Registration?</strong></span></p> - -<p>In a nutshell, registration is the process that makes XPCOM aware of your component(s). As this section and the next describe, you can register your component explicitly during installation, or with the <code>regxpcom</code> program, or you can use the autoregistration methods in the Service Manager to find and register components in a specified components directory:</p> - -<ul> - <li>XPInstall APIs</li> - <li><code>regxpcom</code> command-line tool</li> - <li><code>nsIComponentRegistrar</code> APIs from Service Manager</li> -</ul> - -<p>The registration process is fairly involved. This section introduces it in terms of XPCOM initialization, and the next chapter describes what you have to do in your component code to register your component with XPCOM.</p> -</div> - -<p>Once the manifest files are read in, XPCOM checks to see if there are any components that need to be registered. There are two supported ways to go about registering your XPCOM component. The first is to use <em>XPInstall</em>, which is an installation technology that may or may not come with a Gecko application and provides interfaces for registering your component during installation. Another, more explicit way to register your component is to run the application <code>regxpcom</code>, which is built as part of Mozilla and is also available in the Gecko SDK. <code>regxpcom</code> registers your component in the default component registry.</p> - -<p>A Gecko embedding application may also provide its own way of registering XPCOM components using the interface that is in fact used by both XPInstall and <code>regxpcom</code>, <code>nsIComponentRegistrar</code>. An application, for example, could provide a "registration-less" component directory whose components are automatically registered at startup and unregistered at shutdown. Component discovery does not currently happen automatically in non-debug builds of Gecko, however.</p> - -<p>When the registration process begins, XPCOM broadcasts to all registered observers a notification that says XPCOM has begun the registration of new components. After all components are registered, another notification is fired saying that XPCOM is done with the registration step. The <code>nsIObserver</code> interface that handles this notification is discussed in <a href="/en/Creating_XPCOM_Components/Starting_WebLock" title="en/Creating_XPCOM_Components/Starting_WebLock">Starting WebLock</a>.</p> - -<p>Once registration is complete and the notifications have fired, XPCOM is ready to be used by the application. If XPCOM registered your component, then it will be available to other parts of the XPCOM system. The <a href="#XPCOM_Initialization">XPCOM Initialization</a> section in this chapter describes registration in more detail.</p> - -<h4 id="Autoregistration" name="Autoregistration">Autoregistration</h4> - -<p>The term <em>autoregistration</em> is sometimes used synonymously with registration in XPCOM. In the <a href="#What_Is_XPCOM_Registration?">What Is XPCOM Registration?</a> note, we describe the three ways you can register components with XPCOM. Sometimes, applications use the <code>nsIComponentRegistrar</code> interface and create their own code for watching a particular directory and registering new components that are added there, which is what's often referred to as <em>autoregistration</em>. You should always know what the installation and registration requirements are for the applications that will be using your component.</p> - -<h4 id="The_Shutdown_Process" name="The_Shutdown_Process">The Shutdown Process</h4> - -<p>When the application is ready to shutdown XPCOM, it calls <code>NS_ShutdownXPCOM</code>. When that method is called, the following sequence of events occurs:</p> - -<ol> - <li>XPCOM fires a shutdown notification to all registered observers.</li> - <li>XPCOM closes down the Component Manager, the Service Manager and associated services.</li> - <li>XPCOM frees all global services.</li> - <li>NS_ShutdownXPCOM returns and the application may exit normally.</li> -</ol> - -<div class="side-note"> -<p><span id="The_Unstoppable_Shutdown"><a id="The_Unstoppable_Shutdown"></a><strong>The Unstoppable Shutdown</strong></span></p> - -<p>Note that shutdown observation is unstoppable. In other words, the event you observe cannot be used to implement something like a "Are you sure you want to Quit?" dialog. Rather, the shutdown event gives the component or embedding application a last chance to clean up any leftovers before they are released. In order to support something like an "Are you sure you want to quit" dialog, the application needs to provide a higher-level event (e.g., <code>startShutdown()</code>) which allows for cancellation.</p> - -<p>Note also that XPCOM services may deny you access once you have received the shutdown notification. It is possible that XPCOM will return an error if you access the <code>nsIServiceManager</code> at that point, for example, so you may have to keep a reference-counted pointer to the service you are interested in using during this notification.</p> -</div> - -<h4 id="Component_Loaders" name="Component_Loaders">Component Loaders</h4> - -<p>Components can be written in many languages. So far this book has been focusing on "native components," shared libraries exporting a <code>NSGetModule</code> symbol. But if there is a <em>component loader</em> for Javascript installed, then you can also write a JavaScript component.</p> - -<p>To register, unregister, load and manage various component types, XPCOM abstracts the interface between the XPCOM component and XPCOM with the Component Loader. This loader is responsible for initialization, loading, unloading, and supporting the <code>nsIModule</code> interface on behalf of each component. It is the Component Loader's responsibility to provide scriptable component support.</p> - -<p>When building a "native" component, the component loader looks for an exported symbol from the components shared library. "Native" here includes any language that can generate a platform native dynamically loaded library. Scripting languages and other "non-native" languages usually have no way to build native libraries. In order to have "non-native" XPCOM components work, XPCOM must have a special component loader which knows how to deal with these type of components.</p> - -<p>XPConnect, for example, provides a component loader that makes the various types, including the interfaces and their parameters, available to JavaScript. Each language supported by XPCOM must have a component loader.</p> - -<h4 id="Three_parts_of_a_XPCOM_Component_Library" name="Three_parts_of_a_XPCOM_Component_Library">Three parts of a XPCOM Component Library</h4> - -<p>XPCOM is like an onion<span class="comment">or a parfait! Everybody likes parfaits</span>. XPCOM components have at least three layers. From the innermost and moving outward these layers include:</p> - -<ul> - <li>The core XPCOM object</li> - <li>The factory code</li> - <li>The module code</li> -</ul> - -<p>The core XPCOM object is the object that will implement the functionality you need. For example, this is the object that may start a network download and implement interfaces that will listen to the progress. Or the object may provide a new content type handler. Whatever it does, this object is at the core of the XPCOM component, and the other layers are supporting it, plugging it into the XPCOM system. A single library may have many of these core objects.</p> - -<p>One layer above the core object is the factory code. The factory object provides a basic abstraction of the core XPCOM object. <a href="/en/Creating_XPCOM_Components/An_Overview_of_XPCOM" title="en/Creating_XPCOM_Components/An_Overview_of_XPCOM">An Overview of XPCOM</a> discussed the factory design pattern that's used in a factory object. At this layer of the XPCOM Component Library, the factory objects are factories for the core XPCOM objects of the layer below.</p> - -<p>One more layer outward is the module code. The module interface provides yet another abstraction - this time of the factories - and allows for multiple factory objects. From the outside of the component library, there is only the single entry point, <code>NSGetModule()</code>. This point of entry may fan out to any number of factories, and from there, to any number of XPCOM objects.</p> - -<p>The factory design pattern in XPCOM is represented by the <code>nsIFactory</code> interface. The module layer is represented by the <code>nsIModule</code> interface. Most component libraries only need these two interfaces, along with the <code>nsISupports</code> interface, to have XPCOM load, recognize, and use their core object code.</p> - -<p>In the next section, we'll be writing the code that actually compiles into a component library, and you will see how each layer is implemented and how each interface is used. Following this initial, verbose demonstration of the APIs, we will introduce a faster more generic way of implementing the module and factory code using macros, which can make components much easier to create.</p> - -<h3 id="XPCOM_Glue" name="XPCOM_Glue">XPCOM Glue</h3> - -<p>XPCOM contains a lot of stuff. Most XPCOM interfaces are not frozen and are only meant to be used by the Gecko internals and not by clients. XPCOM provides many data structures from linked lists to <a class="external" href="http://en.wikipedia.org/wiki/AVL_tree">AVL trees</a>. It's tempting to reuse <code>nsVoidArray</code> or another publicly available class instead of writing your own linked list, but this may prove to be a fatal mistake. The class can change at any time and give you unexpected behavior.</p> - -<p>XPCOM makes for a very open environment. At runtime you can acquire any service or component by merely knowing a CID or Contract ID along with an IID. At last count there were over 1300 interfaces defined in XPIDL. Of those 1300 interfaces, less than 100 were frozen, which means that a developer is likely to stumble upon useful interfaces that aren't frozen. Unless an interface is explicitly marked "FROZEN" in the IDL comments, your component may possibly break or crash along with a version change.</p> - -<h4 id="The_Glue_Library" name="The_Glue_Library">The Glue Library</h4> - -<p>In general, you should avoid any interfaces, symbols in XPCOM, or other part of Gecko libraries that aren't frozen. However, there are some unfrozen tools in XPCOM that are used so often they are practically required parts of component programming.</p> - -<p>The smart pointer class, <code>nsCOMPtr</code>, for example, which makes reference counting less tedious and error-prone, is not actually frozen, and neither is <code>nsDebug</code>, a class for aiding in tracking down bugs, nor is <code>nsMemory</code>, a class to ensure that everyone uses the same heap, generic factory, and module. Instead of asking every developer to find and copy these various files into their own application, XPCOM provides a single library of "not-ready-to-freeze-but-really-helpful" classes that you can link into your application, as the following figure demonstrates.</p> - -<p><span id="XPCOM_Glue_and_Tools"><a id="XPCOM_Glue_and_Tools"></a><strong>XPCOM Glue and Tools</strong></span></p> - -<p><img alt="Image:xpcom-glue-tools.png" class="internal" src="/@api/deki/files/978/=Xpcom-glue-tools.png"></p> - -<p>This is the glue library. It provides a bridge, or "glue" layer, between your component and XPCOM.</p> - -<p>A version of the glue library is built into XPCOM, and when your component uses it, it links a snapshot of this library: it includes a copy of these unfrozen classes directly, which allows the XPCOM library version to change without affecting the software. There is a slight footprint penalty to linking directly, but this gives your component freedom to work in any recent environment. If footprint is a big issue in your component or application, you can trim out the pieces you don't need.</p> - -<h4 id="XPCOM_String_Classes" name="XPCOM_String_Classes">XPCOM String Classes</h4> - -<p>The base string types that XPCOM uses are <code>nsAString</code> and <code>nsACString</code>. These classes are described in the Mozilla String Guide (see <a href="/en/Creating_XPCOM_Components/Resources#Gecko_Resources" title="en/Creating_XPCOM_Components/Resources#Gecko_Resources">Gecko Resources</a>).</p> - -<p>The string classes that implement these abstract classes are another set of helpful, unfrozen classes in XPCOM. Most components and embedding applications need to link to some string class or other in order to utilize certain Gecko APIs, but the string code that Mozilla uses is highly complex and even more expensive than the glue code in terms of footprint (~100k). <code>nsEmbedString</code> and <code>nsEmbedCString</code> are available as very lightweight string implementations for component development, especially in small embedded applications. This string implementation does the bare minimum to support the <code>nsAString</code>/<code>nsACString</code> functionality.</p> - -<p>In your own component, you can go "slim" and restrict yourself to the <code>nsEmbedString</code> or go "hog wild" and use any of the the other strings. WebLock restricts itself to using the simple <code>nsEmbedString</code> family of classes.</p> - -<p><span id="String_Classes_and_XPCOM"><a id="String_Classes_and_XPCOM"></a><strong>String Classes and XPCOM</strong></span></p> - -<p><img alt="Image:strings-in-xpcom.png" class="internal" src="/@api/deki/files/867/=Strings-in-xpcom.png"></p> - -<p>The glue library provides stub functions for the public functions that XPCOM provides (see <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/build/nsXPCOM.h" rel="custom">xpcom/build/nsXPCOM.h</a></code>). When the glue library is initialized, it dynamically loads these symbols from the XPCOM library, which allows the component to avoid linking directly with the XPCOM library. You shouldn't have to link to the XPCOM library to create a XPCOM component - in fact, if your component has to, then something is wrong. </p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components/Using_XPCOM_Components" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components/Creating_the_Component_Code">下一页 »</a></p> -</div><p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/creating_the_component_code/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/creating_the_component_code/index.html deleted file mode 100644 index a4aa535eca..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/creating_the_component_code/index.html +++ /dev/null @@ -1,727 +0,0 @@ ---- -title: Creating the Component Code -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/Creating_the_Component_Code -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/Creating_the_Component_Code ---- -<p> </p> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Component_Internals" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Using_XPCOM_Utilities_to_Make_Things_Easier">下一页 »</a></p> -</div><p></p> - -<p>这一章叙述处理你的组件和XPCOM之间关联的基本代码。让组件被找到和注册是这个章节的目的。在后续章节中,我们开始建立<strong>WebLock</strong>组件本身的功能。</p> - -<p>注:有些部分采用英汉对照的方式。避免翻译的不准确!</p> - -<div class="side-note"> -<p><span id="Use_the_Calculator_(After_Learning_Long_Division)"><a id="Use_the_Calculator_(After_Learning_Long_Division)"></a><strong>Use the Calculator (After Learning Long Division)</strong></span></p> - -<p>You have to write a fair amount of code to create a component library that gets loaded into XPCOM. 一个XPCOM组件起码要实现三个XPCOM要求的接口, 通常还有其他一些. 这一章包含了可能你不会需要的更多代码,不过<a href="/cn/Creating_XPCOM_Components/Using_XPCOM_Utilities_to_Make_Things_Easier" title="cn/Creating_XPCOM_Components/Using_XPCOM_Utilities_to_Make_Things_Easier">Using XPCOM Utilities to Make Things Easier</a>会教你一些更简单和优雅的使用通用宏建立XPCOM组件的方式, 本章主要讲述基本的内容。 As in grade school when you learned long division, better tools like calculators come <em>after</em> you figure out what's actually happening. In this case, the long-hand implementation gives us an opportunity to talk about various features of XPCOM.</p> -</div> - -<h3 id="What_We.27ll_Be_Working_On" name="What_We.27ll_Be_Working_On">What We'll Be Working On</h3> - -<p>The component we'll be working on in this book controls a special mode in your browser that prevents users from leaving the current domain or a set of safe domains. Once enabled, this weblock mode is password protected and persists until it is turned off by the password holder. It can be used to make the browser into a safe viewer for children, or for targeted "kiosk browsing," where the content is restricted to a particular server. <a href="#Web_Lock_User_Interface">Web Lock User Interface</a> shows the icon that is used to activate the web lock mode (leftmost in the status bar) once you have installed the <strong>WebLock</strong> component and the extra user interface.</p> - -<h3 id="接下来的内容"> 接下来的内容</h3> - -<p>文章后续的内容,将向读者描述一个使浏览器处在受控模式(web lock mode)的组件,该组件采用密码保护的方式防止用户从当前域或者一组安全的域中离开。这个组件可以使用在为未成年人提供受限内容或者是在一些小型电子浏览器中防止页面跳出特定服务内容。在用户安装了WebLock组件和额外的用户接口后,在状态栏的最左边,如图<a href="#Web_Lock_User_Interface">Web Lock User Interface</a>,可以用图标来激活受控模式(web lock mode)</p> - -<p><span id="Web_Lock_User_Interface"><a id="Web_Lock_User_Interface"></a><strong>Web Lock User Interface</strong></span></p> - -<p><img alt="Image:web-lock-ui.png" class="internal" src="/@api/deki/files/2727/=Web-lock-ui.png"></p> - -<p>实际上组件<strong>WebLock</strong>做的大多数事情是准备组件本身,找到需要的XPCOM接口, 并且挂接到现有的Gecko Browser功能.</p> - -<h3 id="Component_Registration" name="Component_Registration">Component Registration 组件注册</h3> - -<p>All XPCOM components - whether they're stored in shared libraries (DLLs, DSOs or dylibs), JavaScript files, or some other file - need to be <em>registered</em> before they can be used. Registration is a process that happens in all XPCOM applications, whether they're embedded Gecko clients, Mozilla, Netscape 7, Compuserve, or any other software that uses XPCOM. Registration provides the information that applications need in order to use components properly.</p> - -<p>所有的XPCOM 组件- 无论是存储在shared libraries (<abbr title="Dynamic Link Library (Windows)">DLLs</abbr>, <abbr title="Dynamic Shared Object (Linux)">DSOs</abbr> 还是 <abbr title="Dynamically linked library (OS X)">dylibs</abbr>), JavaScript文件,或者其他文件 - 使用前需要被<em>注册. </em>使用XPCOM的Gecko clients, Mozilla, Netscape 7, Compuserve, 或者其他程序,都需要注册,才能获得合适的组件信息。</p> - -<p>The <strong>WebLock</strong> component must do a number of things to register itself. Specifically, the component library has to contain implementations for the component-related interfaces described in this chapter: <code>nsIModule</code> and <code>nsIFactory</code>, which are entry points for your implementation code.</p> - -<p>想要注册 WebLock 组件必须做许多事情. 特别是, 组件库需要包含本章介绍的组件定义的接口: <code>nsIModule</code> and <code>nsIFactory</code>, 这是你的代码入口.</p> - -<p>Once your component implements these interfaces, the rest of the registration process itself is simple. Applications typically use <code>regxpcom</code>, described in the next section.</p> - -<p>如果你的组件实现了这些接口,注册将变的很容易. 应用中通常使用<code>regxpcom</code>注册, 在下一节描述.</p> - -<h4 id="regxpcom_.E7.A8.8B.E5.BA.8F" name="regxpcom_.E7.A8.8B.E5.BA.8F"><code>regxpcom</code> 程序</h4> - -<p>一个明确的注册组件方法是运行<code>regxpcom</code>. 不带任何参数启动<code>regxpcom</code>时, 程序把组件注册在缺省的组件注册表. 我们建议你如果是运行应用, 你可以拷贝你的组件到对应程序安装目录下的<code>components</code>目录. 拷贝好以后,运行<code>regxpcom</code>将注册包含你的组件在内的所有那个目录中的组件.</p> - -<p><code>regxpcom</code>在1.4 或更高版本有一些新的参数. 参看 <code>regxpcom 加<code>-h</code> 选项。</p> - -<h4 id=".E5.8F.A6.E5.A4.96.E7.9A.84.E6.B3.A8.E5.86.8C.E6.96.B9.E6.B3.95" name=".E5.8F.A6.E5.A4.96.E7.9A.84.E6.B3.A8.E5.86.8C.E6.96.B9.E6.B3.95">另外的注册方法</h4> - -<p>Gecko embedding 应用可能提供其他注册组件的方法. XPInstall, 是一个跨平台的安装技术,Mozilla用来安装浏览器和其他组件,这是一个选择。参看<a href="/cn/Creating_XPCOM_Components/Packaging_WebLock" title="cn/Creating_XPCOM_Components/Packaging_WebLock">Packaging WebLock</a>. 你可以询问你想要扩展的应用的作者看是否有其他扩展方法.</p> - -<h3 id="WebLock_Module_.E6.BA.90.E4.BB.A3.E7.A0.81.E6.A6.82.E8.A7.88" name="WebLock_Module_.E6.BA.90.E4.BB.A3.E7.A0.81.E6.A6.82.E8.A7.88">WebLock Module 源代码概览</h3> - -<p>As we mentioned in the previous section, components have layers. There are three main parts to every XPCOM component. From the innermost and moving outward, the first object is the XPCOM object. This is the object that contains the business logic, that implements functionality such as starting a network download, implementing interfaces that listen to the download progress, or providing a new content type handler. In <strong>Weblock</strong>, this is the part that brings together various Gecko services and prevents users from leaving the list of acceptable domains. In a way, the factory and module layers are glue to plug the XPCOM object into the larger XPCOM system.</p> - -<p>在前面的章节我们提到,组件是分层的.每一个XPCOM组件都有三部分.从内到外, 第一个对象是XPCOM对象. 这个对象包含了交互逻辑, 负责载入network, 执行一个监听载入过程或新content type的接口。. 在<strong>Weblock</strong>中, 这部分综合了各种Gecko服务并且防止用户离开允许的一些domain. In a way, the factory and module layers are glue to plug the XPCOM object into the larger XPCOM system.</p> - -<p>One layer above the object itself is the <code>nsIFactory</code> object. This object provides basic abstraction of the XPCOM object itself. As you can see in <span class="lang lang-en"><a href="/en/Creating_XPCOM_Components/Creating_the_Component_Code#Onion_Peel_View_of_XPCOM_Component_Creation" title="en/Creating_XPCOM_Components/Creating_the_Component_Code#Onion_Peel_View_of_XPCOM_Component_Creation"><font color="#638fa2">Onion Peel View of XPCOM Component Creation</font></a> </span>, the main accessor for the XPCOM object is <code>CreateInstance</code>, which is expected to return the object that matches a given CID and IID pair.</p> - -<p>XPCOM的上层是 <code>nsIFactory</code> 对象. nsIFactory是对XPCOM的基本抽象. 如同你在 <a href="#Onion_Peel_View_of_XPCOM_Component_Creation">Onion Peel View of XPCOM Component Creation</a>中看到的, 通过CreateInstance与XPCOM对象进行交互, 返回一个匹配给定的CID 和IID 的两个对象.</p> - -<p>Moving another layer outward is the <code>nsIModule</code>. This interface provides yet another abstraction of the <code>nsIFactory</code> object, and may allow for multiple <code>nsIFactory</code> objects. The key to this interface is that the return type of <code>getClassObject</code> does not have to be an <code>nsIFactory</code>. Instead, the <code>nsIModule</code> can ask for implementation details about the XPCOM object. This is very useful if the caller is required to know information about the component like its threading module, whether or not it's a singleton, its implementation language, and so forth. The interface used in this case is <code>nsIClassInfo</code>. Starting from the outside in, <span class="lang lang-en"><a href="/en/Creating_XPCOM_Components/Creating_the_Component_Code#Onion_Peel_View_of_XPCOM_Component_Creation" title="en/Creating_XPCOM_Components/Creating_the_Component_Code#Onion_Peel_View_of_XPCOM_Component_Creation"><font color="#638fa2">Onion Peel View of XPCOM Component Creation</font></a> </span>represents the sequence for constructing an XPCOM object.</p> - -<p>最外层是<code>nsIModule对象</code>. 他提供了对<code>nsIFactory</code> 的进一步抽象, 而且可能允许多个<code>nsIFactory</code>对象. 关键点是这个接口的方法<code>getClassObject</code>返回的不一定非要是<code>nsIFactory</code>. <code>nsIModule</code> 也可以用来询问 XPCOM 对象的细节. This is very useful if the caller is required to know information about the component like its threading module, whether or not it's a singleton, its implementation language, and so forth. 这是可以使用接口<code>nsIClassInfo</code>. 从外到内, <a href="#Onion_Peel_View_of_XPCOM_Component_Creation">Onion Peel View of XPCOM Component Creation</a> 表示了建立XPCOM对象的顺序.</p> - -<p><span id="Onion_Peel_View_of_XPCOM_Component_Creation"><a id="Onion_Peel_View_of_XPCOM_Component_Creation"></a><strong>Onion Peel View of XPCOM Component Creation</strong></span></p> - -<p><img alt="Image:xpcom-is-an-onion.png" class="internal" src="/@api/deki/files/2732/=Xpcom-is-an-onion.png"></p> - -<p>Before we begin looking at the various parts of the component and how they'll be implemented in the source, let's look at the module in <code>weblock.cpp</code> as a whole to see where we're going. The source we're referring to is listed in its entirety at the end of this chapter (see <a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#webLock1.cpp" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#webLock1.cpp">webLock1.cpp</a>).</p> - -<p><strong>WebLock</strong> 组件的源代码包含三个类. 为了让<strong>WebLock</strong>组件工作在 Mozilla中, 你要为<strong>WebLock</strong>组件建立一个接口, <code>iWebLock</code>, where the actual work specific to the the web locking features happens. 建立 <code>WebLockModule</code> 实现<code>nsIModule</code>接口, 你也要建立 <code>WebLockFactory</code>实现 <code>nsIFactory</code>来建立一个为你的客户处理组件实例的工厂. These three interface implementations - of the component functionality, of the <code>nsIModule</code> interface, and of the <code>nsIFactory</code> interface that creates and manages instances for clients - are the basic sets of code you need to write to create an XPCOM component.</p> - -<div class="side-note"> -<p><span id="Basic_Structure_of_the_WebLock_Component_Source"><a id="Basic_Structure_of_the_WebLock_Component_Source"></a><strong>Basic Structure of the WebLock Component Source</strong></span></p> - -<p>The <code>weblock1.cpp</code> source file that defines these classes and the code you need to create a basic component has the following structure:</p> - -<pre class="eval"> * required includes and constants - * <strong>WebLock</strong>: public <code>iWebLock</code> - * <strong>WebLockFactory</strong>: public <code>nsIFactory</code> - * <strong>WebLockModule</strong>: public <code>nsIModule</code> -</pre> - -<p>在XPCOM中, 所有这些类要实现 <code>nsISupports</code>.</p> -</div> - -<h3 id=".E6.9B.B4.E8.BF.9B.E4.B8.80.E6.AD.A5:_.E9.9C.80.E8.A6.81.E7.9A.84_Includes_and_Constants" name=".E6.9B.B4.E8.BF.9B.E4.B8.80.E6.AD.A5:_.E9.9C.80.E8.A6.81.E7.9A.84_Includes_and_Constants">更进一步: 需要的 Includes and Constants</h3> - -<p>Let's take a look at the first several lines of code in the component and discuss what they mean in XPCOM. The includes and definitions at the top of an XPCOM source file can give you an idea about some of the data types and techniques we'll be discussing more in the upcoming chapters.</p> - -<p>介绍一下XPCOM的component代码里面前几行的意思。</p> - -<p>例如,<code>MOZILLA_STRICT_API</code>是一个变量,它用来遮蔽某些私有的、非XPCOM的头文件。 For example, <code>MOZILLA_STRICT_API</code> is a variable that shields you from certain private, non-XPCOM headers. For example, including <a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/components/nsIComponentManager.idl" rel="custom">nsIComponentManager.idl</a> without <code>MOZILLA_STRICT_API</code> defined will include the following headers, which are not supported across versions (unfrozen):</p> - -<ul> - <li><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsComponentManagerUtils.h" rel="custom">nsComponentManagerUtils.h</a></li> - <li><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/components/nsComponentManagerObsolete.h" rel="custom">nsComponentManagerObsolete.h</a></li> -</ul> - -<p>These variables are picked up by files that do not specify themselves as <code>MOZILLA_STRICT_API</code>.</p> - -<p><span id="Includes_and_Constants_in_%3Ccode%3Eweblock1.cpp%3C/code%3E"><a id="Includes_and_Constants_in_%3Ccode%3Eweblock1.cpp%3C/code%3E"></a><strong>Includes and Constants in <code>weblock1.cpp</code></strong></span></p> - -<pre>#include <stdio.h> - -// may be defined at the project level -// in the makefile -#define MOZILLA_STRICT_API - -#include "nsIModule.h" -#include "nsIFactory.h" - -#include "nsIComponentManager.h" -#include "nsIComponentRegistrar.h" - -// use classes to handle IIDs -// classes provide methods for comparison: Equals, etc. -static const nsIID kIModuleIID = NS_IMODULE_IID; -static const nsIID kIFactoryIID = NS_IFACTORY_IID; -static const nsIID kISupportsIID = NS_ISUPPORTS_IID; -static const nsIID kIComponentRegistrarIID = NS_ICOMPONENTREGISTRAR_IID; - - -// generate unique ID here with uuidgen -#define SAMPLE_CID \ -{ 0x777f7150, 0x4a2b, 0x4301, \ -{ 0xad, 0x10, 0x5e, 0xab, 0x25, 0xb3, 0x22, 0xaa}} - -static const nsCID kSampleCID = SAMPLE_CID; -</pre> - -<p><code>nsIModule.h</code> and <code>nsIFactory.h</code> are required to build your module successfully. They define the module and factory interfaces, and they contain a couple of important macros as well (see the following chapter for information about using these macros). The two other includes, <code>nsIComponentManager.h</code> and <code>nsIComponentRegistrar.h</code>, provide functions such as <code>RegisterFactoryLocation</code> that are required to implement the module and factory classes in your code.</p> - -<h4 id=".E6.A0.87.E8.AF.86.E7.AC.A6_in_XPCOM" name=".E6.A0.87.E8.AF.86.E7.AC.A6_in_XPCOM">标识符 in XPCOM</h4> - -<p>一组 <code>nsIID</code> 变量实际上是一些处理XPCOM用来支持客户和组件之间关系的128-bit标识符. The variable <code>kIFactoryIID</code>, for example, provides methods like <code>Equals()</code> that can be used to facilitate comparisons in the code, as in the following example from the Mozilla source:</p> - -<p><span id="Using_Class_Methods_to_Handle_Identifiers"><a id="Using_Class_Methods_to_Handle_Identifiers"></a><strong>Using Class Methods to Handle Identifiers</strong></span></p> - -<pre>if (aIID.Equals(NS_GET_IID(nsISupports))) -{ - *aInstancePtr = (void*)(nsISupports*)this; - NS_ADDREF_THIS(); - return NS_OK; -} -</pre> - -<p>最后, <code>SAMPLE_CID</code> 是一个唯一标示组件的 CID . 所有的XPCOM中使用的128-bit数字 - 类和接口 IDs - 都是 UUIDs的例子, or <em>universal unique identifiers</em>, which were discussed in <a href="/cn/Creating_XPCOM_Components/What_is_XPCOM%3f#Object_Interface_Discovery" title="cn/Creating_XPCOM_Components/What_is_XPCOM?#Object_Interface_Discovery">Object Interface Discovery</a>.</p> - -<div class="side-note"> -<p>Generating CIDs</p> - -<p>为组件建立一个CID,你可以使用大多数Unix版本以及Miscrosoft Visual C++都包含的<code>uuidgen</code> 工具. <code>uuidgen</code> is a command-line tool that returns a unique 128-bit number when you call it with no arguments:</p> - -<pre>$ uuidgen -ce32e3ff-36f8-425f-94be-d85b26e634ee -</pre> - -<p>On Windows, a program called <code>guidgen.exe</code> does the same thing and also provides a graphical user interface if you'd rather point and click. Or you can use one of the special "bots" on IRC in <a class="link-irc" href="irc://irc.mozilla.org/mozilla">#developers</a>, where you can also get help from human beings.</p> - -<pre>irc irc.mozilla.org -/join #developers -/msg mozbot uuid -</pre> - -<p>This command makes the bot generate and return a UUID, which you can then copy into your component source code.</p> -</div> - -<p>Now that we've looked at the preliminaries, it's time to discuss the classes that this module provides and the way that they define the relationships of the component in XPCOM.</p> - -<h4 id="Coding_for_the_Registration_Process" name="Coding_for_the_Registration_Process">Coding for the Registration Process</h4> - -<p>当 XPCOM 第一次发现你的组件(via XPInstall or <code>regxpcom</code>, both of which are discussed in <a href="#Component_Installation_Overview">Component Installation Overview</a>), 第一件事是装载你的库并找到符号<code>NSGetModule</code>. 当这个专用的入口被调用, 它被传送XPCOM's Component Manager和组件存在的共享库位置.</p> - -<p>Component Manager是一个是XPCOM实现的用来包含建立对象和提供一些所有组件的综合信息的接口。磁盘的位置是通过另外一个接口 <code>nsIFile</code>传送的. This interface is XPCOM's abstraction of files and directories. An <code>nsIFile</code> object is usually a file or directory on a local volume, but it may represent something on a network volume as well.</p> - -<pre>nsresult NSGetModule(nsIComponentManager *servMgr, - nsIFile* location, - nsIModule** result); -</pre> - -<p>XPCOM 需要成功调用 <code>NSGetModule</code>并返回接口<code>nsIModule</code>. 当你写一个 XPCOM 组件, 你实现了 <code>nsIModule</code> to do all of the necessary registration, unregistration, and object creation. <code>nsIModule</code> 有4个方法必须实现.<code>nsIModule</code> has four methods that must be implemented.</p> - -<h4 id="The_Registration_Methods" name="The_Registration_Methods">The Registration Methods</h4> - -<p>Two closely related registration methods are declared below.</p> - -<pre>NS_IMETHOD RegisterSelf(nsIComponentManager *aCompMgr, - nsIFile *aLocation, - const char *aLoaderStr, - const char *aType) = 0; - -NS_IMETHOD UnregisterSelf(nsIComponentManager *aCompMgr, - nsIFile *aLocation, - const char *aLoaderStr) = 0; -</pre> - -<p><code>RegisterSelf</code> 在组件第一次被XPCOM注册的时候调用. 他只执行一次, which gives you a chance to add any one time setup functionality. The <code>RegisterSelf</code> 允许你的组件告诉XPCOM 你将支持什么功能. 注意所有你在 <code>RegisterSelf</code> 中做的都应该在 <code>UnregisterSelf</code>中撤销.</p> - -<p>首先, <code>NSGetModule</code>入口从你的库中被调用, 返回一个指向<code>nsIModule</code>的实现. 然后XPCOM调用<code>RegisterSelf</code>, passing parameters that we'll examine here.</p> - -<h5 id="The_RegisterSelf_Method" name="The_RegisterSelf_Method">The RegisterSelf Method</h5> - -<p>The first parameter is the <code>nsIComponentManager</code>, which provides a kind of entry point into managing the registration process. 你可以调用<code>QueryInterface</code> 来查找访问下面所述的其他组件管理接口.</p> - -<div class="side-note"> -<p><span id="The_Many_Faces_of_the_XPCOM_Component_Manager"><a id="The_Many_Faces_of_the_XPCOM_Component_Manager"></a><strong>The Many Faces of the XPCOM Component Manager</strong></span></p> - -<p>三个主要的组件管理接口, <code>nsIComponentManager</code>, <code>nsIServiceManager</code>, and <code>nsIComponentRegistrar</code>, are described below:</p> - -<ul> - <li><code>nsIComponentManager</code> - 建立组件并且返回组件实现细节。</li> - <li><code>nsIServiceManager</code> - 提供访问单根组件并且返回单根状态信息。</li> - <li><code>nsIComponentRegistrar</code> - 注册和注销工厂和组件;处理自动注册和发现已经注册的组件列表。</li> -</ul> -</div> - -<p>Your <code>RegisterSelf</code> method may call <code>QueryInterface</code> on the <code>nsIComponentManager</code> interface parameter to obtain the <code>nsIComponentRegistrar</code> or <code>nsIServiceManager</code>. <code>nsIServiceManager</code> can be used to obtain a singleton service, which can be useful if you have to register with a service other than the <code>nsIComponentRegistrar</code> if necessary. For example, you may want to get the service that is responsible for an event you want to be notified about. See <a href="/cn/Creating_XPCOM_Components/Starting_WebLock#Getting_Called_at_Startup" title="cn/Creating_XPCOM_Components/Starting_WebLock#Getting_Called_at_Startup">Getting Called at Startup</a> for an example of this.</p> - -<p>第二个参数<code>RegisterSelf</code>是正在注册组件的位置. This parameter is useful when the component needs to know where it has been installed or registered - as, for example, when other files must be stored or accessed relative to the component. This method is only called once, so you have to persist the location if you are going to use it later.</p> - -<p>The next two parameters are usually passed into the <code>nsIComponentRegistrar</code> methods and used by XPCOM to determine how to handle the component's registration. The <code>aLoaderStr</code> parameter, which is opaque and should not be modified, distinguishes components that are loaded from the same location specified by the <code>nsIFile</code> parameter. A single ZIP archive may store several XPCOM components, where every component in the archive has the same <code>nsIFile</code> parameter but the <code>aLoaderStr</code> parameter can be used to refer to the location within the ZIP archive.</p> - -<p>The last parameter specifies what kind of loader to use on the component. This is reserved as an optimization, for the most part, but it can be a useful way to extend XPCOM. Since XPCOM already knows internally what kind of file it has just loaded and called <code>RegisterSelf</code> on, passing this value to the registration methods is a shortcut for determining what kind of component is being registered.</p> - -<h5 id="nsIComponentRegistrar_Methods" name="nsIComponentRegistrar_Methods">nsIComponentRegistrar Methods</h5> - -<p>为了告诉XPCOM这个组件库实现了什么,调用方法:</p> - -<pre>NS_IMETHOD RegisterFactoryLocation(const nsCID & aClass, - const char *aClassName, - const char *aContractID, - nsIFile *aFile, - const char *aLoaderStr, - const char *aType) = 0; -</pre> - -<p>The last three parameters are the same as the three passed into the <code>RegisterSelf</code> method of <code>nsIModule</code> objects. All you have to do is forward these parameters from your <code>RegisterSelf</code> call into this method, leaving just the first three parameters.</p> - -<p>For any class that implements an XPCOM interface, the implementation must have a class identifier if it is to be shared with other parts of code via XPCOM. This identifier, called a CID, uniquely specifies the implementation. This CID can be created via the tool <code>uuidgen</code> on most operating systems, as in <a href="#The_Many_Faces_of_the_XPCOM_Component_Manager">The Many Faces of the XPCOM Component Manager</a> above. Given a CID and an IID, you can refer to any class in XPCOM. Consider the following:</p> - -<p><span id="Referencing_Objects_by_ID"><a id="Referencing_Objects_by_ID"></a><strong>Referencing Objects by ID</strong></span></p> - -<p><img alt="Image:referencing-objects-by-id.png" class="internal" src="/@api/deki/files/2676/=Referencing-objects-by-id.png"></p> - -<p>In this case, you have two implementations of the <code>nsISupports</code> interface. Each implementation has a separate CID. The interface also as an IID which is the same for both implementations. When specifying implementation A, the two required pieces of information are the CID of A and the IID of the interface that A supports. The code to register such an object is simple:</p> - -<pre>NS_IMETHODIMP -SampleModule::RegisterSelf(nsIComponentManager *aCompMgr, - nsIFile* aPath, - const char* registryLocation, - const char* componentType) -{ - printf("Hello Mozilla Registration!\n\n"); - nsIComponentRegistrar* compReg = nsnull; - nsresult rv = - aCompMgr->QueryInterface(kIComponentRegistrarIID,(void**)& compReg); - if (NS_FAILED(rv)) - return rv; - rv = compReg->RegisterFactoryLocation(kSampleCID, - "Sample Class", - nsnull, - aPath, - registryLocation, - componentType); - compReg->Release(); - return rv; -} -</pre> - -<p>Unregistration follows the same logic. To unregister, all you have to do is pass the CID and the file which is passed into <code>UnregisterSelf</code>.</p> - -<h4 id=".E5.BB.BA.E7.AB.8B.E4.BD.A0.E7.9A.84.E7.BB.84.E4.BB.B6.E7.9A.84.E4.B8.80.E4.B8.AA.E5.AE.9E.E4.BE.8B" name=".E5.BB.BA.E7.AB.8B.E4.BD.A0.E7.9A.84.E7.BB.84.E4.BB.B6.E7.9A.84.E4.B8.80.E4.B8.AA.E5.AE.9E.E4.BE.8B">建立你的组件的一个实例</h4> - -<p>上面的例子用了 CID, 一旦注册以后,任何使用 XPCOM 的客户都可以访问你的组件,通过contract ID or CID. (Note that <code>RegisterSelf</code> method above does not register a contract ID - it simply passes null. This prevents clients from ever accessing the component with a contract ID.)</p> - -<p>为了让其他人访问, 你要公开组件包括它支持的接口的 CID 和/或者 contract ID. 上面的例子中,某人可能通过下面的方法建立一个 <strong>Sample</strong>对象 :</p> - -<pre>nsIComponentManager* compManager; // assume initialized - -nsISupports* sample; -compManager->CreateInstance(kSampleCID, - nsnull, - kISupportsIID, - (void**)&sample); -</pre> - -<p>In the above snippet, we assume that the component manager has been initialized. In many cases this value is passed in or easily accessible. 如果还没有建立组件管理者,你总可以调用<code>NS_GetComponentManager()</code>来建立它. <a href="/cn/XPCOM_API_Reference" title="cn/XPCOM_API_Reference">XPCOM API Reference</a>中列出了一些全局的XPCOM方法.</p> - -<p>The first parameter of the call to <code>CreateInstance</code> specifies the component the client code is looking for, which is the same value passed to <code>RegisterFactoryLocation</code>. The next parameter is for aggregation, which the <strong>WebLock</strong> component does not support. The third parameter is the interface used to talk to the component. The last parameter is the out variable which will contain a valid object if and only if the method succeeds<sup><a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components/Creating_the_Component_Code#endnote_non-null-out">[non-null-out]</a></sup>. The implementation of <code>CreateInstance</code> will ensure that the result will support the passed IID, <code>kISupportsIID</code>. The type of the variable <code>sample</code> should match the IID passed in as <code>kISupportsIID</code>.</p> - -<p>当 <code>CreateInstance</code> 被调用, XPCOM 查询所有的注册组件来匹配CID. XPCOM然后会装载对应的匹配 CID的组件,如果他还没有被装载的话. XPCOM 然后调用库的 <code>NSGetModule</code>. 最后它调用模块上的 <code>GetClassObject</code>. 这个方法是你来实现的,返回匹配 CID/IID 对的<code>nsIFactory</code>. To prepare your component code, you need to create a factory object for each object that you have registered with XPCOM.</p> - -<p>The main function that must be implemented in the <code>nsIFactory</code> interface is <code>CreateInstance</code>. The implementation follows a simple algorithm:</p> - -<ol> - <li>Create the raw object.</li> - <li>If that fails, return an out of memory error code.</li> - <li>Call <code>QueryInterface</code> on the new object.</li> - <li>If that fails, null the out param and free the new object.</li> - <li>Return the <code>nsresult</code> value from <code>QueryInterface</code>.</li> -</ol> - -<p>Often, you don't have to create the object first because the factory implicitly knows what IIDs are supported. When this is not the case, however, doing it this way further abstracts the factories from their concrete classes. If you have a factory that knows every IID supported by the concrete base class, for example, then when you go to add a new supported interface you add this IID comparison in both the factory and the <code>QueryInterface</code> implementation in the concrete class.</p> - -<pre>NS_IMETHODIMP -SampleFactory::CreateInstance(nsISupports *aOuter, - const nsIID & iid, - void * *result) -{ - if (!result) - return NS_ERROR_INVALID_ARG; - - Sample* sample = new Sample(); - if (!sample) - return NS_ERROR_OUT_OF_MEMORY; - - nsresult rv = sample->QueryInterface(iid, result); - - if (NS_FAILED(rv)) { - *result = nsnull; - delete sample; - } - - return rv; -} -</pre> - -<h3 id="webLock1.cpp" name="webLock1.cpp"><code>webLock1.cpp</code></h3> - -<p>Before any of the improvements and XPCOM tools we describe in the following chapter are brought in, the source code for the <strong>WebLock</strong> component that implements all the necessary interfaces looks like this.</p> - -<pre>#include <stdio.h> - -#define MOZILLA_STRICT_API - -#include "nsIModule.h" -#include "nsIFactory.h" - -#include "nsIComponentManager.h" -#include "nsIComponentRegistrar.h" - -static const nsIID kIModuleIID = NS_IMODULE_IID; -static const nsIID kIFactoryIID = NS_IFACTORY_IID; -static const nsIID kISupportsIID = NS_ISUPPORTS_IID; -static const nsIID kIComponentRegistrarIID = NS_ICOMPONENTREGISTRAR_IID; - - -#define SAMPLE_CID \ -{ 0x777f7150, 0x4a2b, 0x4301, \ -{ 0xad, 0x10, 0x5e, 0xab, 0x25, 0xb3, 0x22, 0xaa}} - -static const nsCID kSampleCID = SAMPLE_CID; - -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); - -}; - -Sample::Sample() -{ - mRefCnt = 0; -} - -Sample::~Sample() -{ -} - -NS_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; - } - AddRef(); - return NS_OK; -} - -NS_IMETHODIMP_(nsrefcnt) Sample::AddRef() -{ - return ++mRefCnt; -} - -NS_IMETHODIMP_(nsrefcnt) Sample::Release() -{ - if (--mRefCnt == 0) { - delete this; - return 0; - } - return mRefCnt; -} - - - -// factory implementation class for component -class SampleFactory: public nsIFactory{ - private: - nsrefcnt mRefCnt; - public: - SampleFactory(); - virtual ~SampleFactory(); - - NS_IMETHOD QueryInterface(const nsIID &aIID, void **aResult); - NS_IMETHOD_(nsrefcnt) AddRef(void); - NS_IMETHOD_(nsrefcnt) Release(void); - - NS_IMETHOD CreateInstance(nsISupports *aOuter, const nsIID & iid, void * *result); - NS_IMETHOD LockFactory(PRBool lock); - -}; - -SampleFactory::SampleFactory() -{ - mRefCnt = 0; -} -SampleFactory::~SampleFactory() -{ -} - -NS_IMETHODIMP -SampleFactory::QueryInterface(const nsIID &aIID, - void **aResult) -{ - if (aResult == NULL) { - return NS_ERROR_NULL_POINTER; - } - *aResult = NULL; - if (aIID.Equals(kISupportsIID)) { - *aResult = (void *) this; - } - else if (aIID.Equals(kIFactoryIID)) { - *aResult = (void *) this; - } - - if (*aResult == NULL) { - return NS_ERROR_NO_INTERFACE; - } - AddRef(); - return NS_OK; -} - -NS_IMETHODIMP_(nsrefcnt) SampleFactory::AddRef() -{ - return ++mRefCnt; -} - -NS_IMETHODIMP_(nsrefcnt) SampleFactory::Release() -{ - if (--mRefCnt == 0) { - delete this; - return 0; - } - return mRefCnt; -} - - -NS_IMETHODIMP -SampleFactory::CreateInstance(nsISupports *aOuter, - const nsIID & iid, - void * *result) -{ - if (!result) - return NS_ERROR_INVALID_ARG; - - Sample* sample = new Sample(); - if (!sample) - return NS_ERROR_OUT_OF_MEMORY; - - nsresult rv = sample->QueryInterface(iid, result); - - if (NS_FAILED(rv)) { - *result = nsnull; - delete sample; - } - - return rv; -} - - -NS_IMETHODIMP -SampleFactory::LockFactory(PRBool lock) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - - - - - - -// Module implementation -class SampleModule : public nsIModule -{ - public: - SampleModule(); - virtual ~SampleModule(); - - // nsISupports methods: - NS_IMETHOD QueryInterface(const nsIID & uuid, void * *result); - NS_IMETHOD_(nsrefcnt) AddRef(void); - NS_IMETHOD_(nsrefcnt) Release(void); - - // nsIModule methods: - NS_IMETHOD GetClassObject(nsIComponentManager *aCompMgr, - const nsCID & aClass, - const nsIID & aIID, - void * *aResult); - NS_IMETHOD RegisterSelf(nsIComponentManager *aCompMgr, - nsIFile *aLocation, - const char *aLoaderStr, - const char *aType); - NS_IMETHOD UnregisterSelf(nsIComponentManager *aCompMgr, - nsIFile *aLocation, - const char *aLoaderStr); - NS_IMETHOD CanUnload(nsIComponentManager *aCompMgr, - PRBool *_retval); - - private: - nsrefcnt mRefCnt; -}; - - -//---------------------------------------------------------------------- - -SampleModule::SampleModule() -{ - mRefCnt = 0; -} - -SampleModule::~SampleModule() -{ -} - - -// nsISupports implemention -NS_IMETHODIMP_(nsrefcnt) -SampleModule::AddRef(void) -{ - return ++mRefCnt; -} - - -NS_IMETHODIMP_(nsrefcnt) -SampleModule::Release(void) -{ - if (--mRefCnt == 0) { - mRefCnt = 1; /* stabilize */ - delete this; - return 0; - } - return mRefCnt; -} - -NS_IMETHODIMP -SampleModule::QueryInterface(REFNSIID aIID, - void** aInstancePtr) -{ - if (!aInstancePtr) - return NS_ERROR_NULL_POINTER; - - nsISupports* foundInterface; - - if (aIID.Equals(kIModuleIID)) { - foundInterface = (nsIModule*) this; - } - else if ( aIID.Equals(kISupportsIID) ) { - foundInterface = (nsISupports*) this; - } - else { - foundInterface = 0; - } - - if (foundInterface) { - foundInterface->AddRef(); - *aInstancePtr = foundInterface; - return NS_OK; - } - - *aInstancePtr = foundInterface; - return NS_NOINTERFACE; -} - - -// Create a factory object for creating instances of aClass. -NS_IMETHODIMP -SampleModule::GetClassObject(nsIComponentManager *aCompMgr, - const nsCID& aClass, - const nsIID& aIID, - void** result) -{ - - if (!kSampleCID.Equals(aClass)) - return NS_ERROR_FACTORY_NOT_REGISTERED; - - if (!result) - return NS_ERROR_INVALID_ARG; - - SampleFactory* factory = new SampleFactory(); - if (!factory) - return NS_ERROR_OUT_OF_MEMORY; - - nsresult rv = factory->QueryInterface(aIID, result); - - if (NS_FAILED(rv)) { - *result = nsnull; - delete factory; - } - - return rv; -} - - -//---------------------------------------- - - -NS_IMETHODIMP -SampleModule::RegisterSelf(nsIComponentManager *aCompMgr, - nsIFile* aPath, - const char* registryLocation, - const char* componentType) -{ - - nsIComponentRegistrar* compReg = nsnull; - - nsresult rv = - aCompMgr->QueryInterface(kIComponentRegistrarIID, (void**)&compReg); - if (NS_FAILED(rv)) - return rv; - - rv = compReg->RegisterFactoryLocation(kSampleCID, - "Sample Class", - nsnull, - aPath, - registryLocation, - componentType); - - compReg->Release(); - - return rv; -} - -NS_IMETHODIMP -SampleModule::UnregisterSelf(nsIComponentManager* aCompMgr, - nsIFile* aPath, - const char* registryLocation) -{ - - nsIComponentRegistrar* compReg = nsnull; - - nsresult rv = aCompMgr->QueryInterface(kIComponentRegistrarIID, (void**)&compReg); - if (NS_FAILED(rv)) - return rv; - - rv = compReg->UnregisterFactoryLocation(kSampleCID, aPath); - - compReg->Release(); - - return rv; -} - -NS_IMETHODIMP -SampleModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload) -{ - *okToUnload = PR_FALSE; // we do not know how to unload. - return NS_OK; -} - -//---------------------------------------------------------------------- - -extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, - nsIFile* location, - nsIModule** return_cobj) -{ - nsresult rv = NS_OK; - - // Create and initialize the module instance - SampleModule *m = new SampleModule(); - if (!m) { - return NS_ERROR_OUT_OF_MEMORY; - } - - // Increase refcnt and store away nsIModule interface to m in return_cobj - rv = m->QueryInterface(kIModuleIID, (void**)return_cobj); - if (NS_FAILED(rv)) { - delete m; - } - return rv; -} -</pre> - -<ol> - <li><div class="blockIndicator note"><strong>Note:</strong> non-null-out</div> The <code>CreateInstance</code> method guarantees that if the out variable is non-null, it is valid.</li> -</ol> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Component_Internals" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Using_XPCOM_Utilities_to_Make_Things_Easier">下一页 »</a></p> -</div> <p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/finishing_the_component/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/finishing_the_component/index.html deleted file mode 100644 index 3be93d89f5..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/finishing_the_component/index.html +++ /dev/null @@ -1,337 +0,0 @@ ---- -title: Finishing the Component -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/Finishing_the_Component -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/Finishing_the_Component ---- -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Starting_WebLock" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Building_the_WebLock_UI">下一页 »</a></p> -</div><p></p> - -<p>At this point you have created most of the infrastructure of the component. The component will be recognized by XPCOM and registered with the Category Manager so that it starts up when XPCOM initializes. When the component starts up, it populates a list of URLs read in from a file stored next to the Gecko binary on the local system.</p> - -<h3 id="Using_Frozen_Interfaces" name="Using_Frozen_Interfaces">Using Frozen Interfaces</h3> - -<p>The core functionality of blocking sites is still missing, however. The interfaces needed to block certain URLs from loading are not frozen, and there is still some debate about how exactly this functionality should be exposed to embedders and component developers, so the APIs are not ready to be published. This puts you in the same situation as many developers using Mozilla - you want to use some specific functionality, but the interfaces seem to change on a daily basis.</p> - -<p>All of the Mozilla source code is publicly available, and interfaces can be used easily enough. Grab the right headers, use the Component or Service Manager to access the interface you want, and the XPCOM object(s) that implement that interface will do your bidding. With this huge amount of flexibility, however, you lose compatibility. If you use "stuff" that isn't frozen, that stuff is subject to change in future versions of Gecko.</p> - -<p>If you want to be protected against changes in Gecko, you must only use interfaces and APIs that are clearly marked as FROZEN. The marking is made in the comments above the interface declaration. For example, take a look at the <code>nsIServiceManager</code>:</p> - -<pre>/** - * The nsIServiceManager manager interface provides a means to obtain - * global services in an application. The service manager depends - * on the repository to find and instantiate factories to obtain - * services. - * - * Users of the service manager must first obtain a pointer to the - * global service manager by calling NS_GetServiceManager. After that, - * they can request specific services by calling GetService. - * When they are finished they can NS_RELEASE() the service as usual. - * - * A user of a service may keep references to particular services - * indefinitely and only must call Release when it shuts down. - * - * @status FROZEN - */ -</pre> - -<p>These frozen interfaces and functions are part of the Gecko SDK. The rule of thumb is that interfaces outside of the SDK are considered "experimental" or unfrozen. See the following sidebar for information about how frozen and unfrozen interfaces can affect your component development, and for technical details about how interface changes beneath your code can cause havoc.</p> - -<div class="side-note"> -<p><span id="The_Danger_of_Using_Unfrozen_Interfaces"><a id="The_Danger_of_Using_Unfrozen_Interfaces"></a><strong>The Danger of Using Unfrozen Interfaces</strong></span></p> - -<p>Suppose that you need to use the interface <code>nsIFoo</code> that isn't frozen. You build your component using this interface, and it works great with the version of Gecko that you have tested against. However, some point in the future, the <code>nsIFoo</code> interface requires a major change, and methods are reordered, some are added, others are removed. Moreover, since this interface was never supposed to be used by clients other than Gecko or Mozilla, the maintainers of the interface don't know that it's being used, and don't change the IID of the interface. When your component runs in a version of Gecko in which this interface is updated, your method calls will be routed through a different v-table than the one the component expected, most likely resulting in a crash.</p> - -<p>Below, the component is compiled against a version of the <code>nsIFoo</code> interface that has three methods. The component calls the method <code>TestA</code> and passes an integer, 10. This works fine in any Gecko installation where a contract guarantees that the interface that was compiled against has the same signature. However, when this same component is used in a Gecko installation where this interface has changed, the method <code>TestA</code> does not exist in the <code>nsIFoo</code> interface; the first entry in the v-table is in fact <code>IsPrime()</code>. When this method call is made, the code execution treats the <code>IsPrime</code> method as <code>TestA</code>. Needless to say, this is a bad thing. Furthermore, there is no way easy way to realize this error at runtime.</p> - -<p><img alt="Image:vtable-of-altered-interface.png"></p> - -<p>Gecko developers could change the interface's IID, and some do. This can prevent many errors like this. But unfrozen interfaces are not supported in any formal way, and relying upon a different IID for any change in the interface is not a good idea either.</p> - -<p>When using frozen interfaces, you are guaranteed compatibility with future versions of Gecko. The only trouble occurs when the compiler itself changes its v-table layout, which can happen when the compiler changes its ABI. For example, in 2002 the GNU Compiler Collection (GCC), version 3.2 changed the C++ ABI, and this caused problems between libraries compiled with GCC 3.2 and applications compiled with an earlier version and vice versa. Similar problems occurred with GCC 4.0, which underwent similar ABI changes.</p> -</div> - -<p>Before attempting to use unfrozen interfaces, you should contact the developers who are responsible for the code you're trying to use (i.e.,<em><a class="external" href="http://www.mozilla.org/owners.html">module owners</a></em> ) and ask them how best to do what you are trying to do. Be as precise you possibly can. They may be able to suggest a supported alternative, or they may be able to notify you about pending changes.</p> - -<p>The interface that we need for this project is something called <code>nsIContentPolicy</code>. At the time this book was written, this interface was under review. An interface reaches this state when a group of module owners and peers are actively engaged in discussion about how best to expose it. Usually there are only minor changes to interfaces marked with such a tag. Even with interfaces marked "under review," however, it's still a good idea to contact the module owners responsible for the interfaces you are interested in using.</p> - -<h4 id="Copying_Interfaces_into_Your_Build_Environment" name="Copying_Interfaces_into_Your_Build_Environment">Copying Interfaces into Your Build Environment</h4> - -<p>To get and implement interfaces that are not part of Gecko in your component, simply create a new directory in the Gecko SDK named <code>unfrozen</code>. Copy the headers and IDL files that you need from the <code><a href="https://dxr.mozilla.org/mozilla-central/source/content/base/public" rel="custom">content/base/public</a></code> source directory of the Gecko build into this new directory. (For <strong>WebLock</strong>, all you need are the headers for <code>nsIContentPolicy</code> and the <code>nsIContentPolicy.idl</code>.) Then, using the same steps you used to create the <code>Weblock.h</code>, create a header from this IDL file using the xpidl compiler. Once you have these interface and header files, you can modify the <code>WebLock</code> class to implement the <code>nsIContentPolicy</code> interface. The Weblock class will then support four interfaces: <code>nsISupports</code>, <code>nsIObserver</code>, <code>nsIContentPolicy</code>, and <code>iWeblock</code>.</p> - -<p><img alt="Image:weblock-implemented-ifaces.png"></p> - -<p><span id="%3Ccode%3EWebLock%3C/code%3E_Interfaces"><a id="%3Ccode%3EWebLock%3C/code%3E_Interfaces"></a><strong><code>WebLock</code> Interfaces</strong></span></p> - -<table class="standard-table"> - <tbody> - <tr> - <td class="header">Interface Name</td> - <td class="header">Defined by</td> - <td class="header">Status</td> - <td class="header">Summary</td> - </tr> - <tr> - <td><code>nsISupports</code></td> - <td>XPCOM</td> - <td>Frozen</td> - <td>Provides interface discovery, and object reference counting</td> - </tr> - <tr> - <td><code>nsIObserver</code></td> - <td>XPCOM</td> - <td>Frozen</td> - <td>Allows messaging passing between objects</td> - </tr> - <tr> - <td><code>nsIContentPolicy</code></td> - <td>Content</td> - <td>Not Frozen</td> - <td>Interface for policy control mechanism</td> - </tr> - <tr> - <td><code>iWeblock</code></td> - <td>Web Lock</td> - <td>Not Frozen</td> - <td>Enables and disables Weblock. Also, provides access to the URL that are whitelisted.</td> - </tr> - </tbody> -</table> - -<h4 id="Implementing_the_nsIContentPolicy_Interface" name="Implementing_the_nsIContentPolicy_Interface">Implementing the <code>nsIContentPolicy</code> Interface</h4> - -<p>To implement the new interface, you must <code>#include</code> the unfrozen <code><a class="internal" href="/en/nsIContentPolicy" title="en/nsIContentPolicy">nsIContentPolicy</a></code>, and you must also make sure the build system can find the file you've brought over. The location of the file and the steps for adding that location to the build system vary depending on how you build this component.</p> - -<p>Once you have made sure that your component builds with the new header file, you must derive the <code>Weblock</code> class from the interface <code>nsIContentPolicy</code>, which you can do by simply adding a public declaration when defining the class. At the same time, you can add the macro <code>NS_DECL_NSICONTENTPOLICY</code> to the class declaration that provides all of the methods defined in the interface nsIContentPolicy. The updated <code>WebLock</code> class looks as follows:</p> - -<pre>class WebLock: public nsIObserver, public iWeblock, public nsIContentPolicy -{ - public: - WebLock(); - virtual ~WebLock(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - NS_DECL_IWEBLOCK - NS_DECL_NSICONTENTPOLICY - - private: - urlNode* mRootURLNode; - PRBool mLocked; -}; -</pre> - -<p>Remember to change the <code>nsISupports</code> implementation macro to include <code>nsIContentPolicy</code> so that other parts of Gecko will know <strong>WebLock</strong> supports the <code>nsIContentPolicy</code> interface without modifying this macro.</p> - -<pre>NS_IMPL_ISUPPORTS3(WebLock, nsIObserver, iWeblock, nsIContentPolicy); -</pre> - -<h4 id="Receiving_Notifications" name="Receiving_Notifications">Receiving Notifications</h4> - -<p>To receive notifications, you must register as a new category. You have already registered as a category to receive startup notification. This time, the category name to use is "content-policy". To add the <strong>WebLock</strong> component to this category, modify the <code>WebLockRegistration</code> callback function so that it looks like this:</p> - -<pre>static NS_METHOD WebLockRegistration(nsIComponentManager *aCompMgr, - nsIFile *aPath, - const char *registryLocation, - const char *componentType, - const nsModuleComponentInfo *info) -{ - nsresult rv; - nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr<nsICategoryManager> catman; - servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID, - NS_GET_IID(nsICategoryManager), - getter_AddRefs(catman)); - if (NS_FAILED(rv)) - return rv; - - char* previous = nsnull; - rv = catman->AddCategoryEntry("xpcom-startup", - "WebLock", - WebLock_ContractID, - PR_TRUE, - PR_TRUE, - &previous); - if (previous) - nsMemory::Free(previous); - - rv = catman->AddCategoryEntry("content-policy", - "WebLock", - WebLock_ContractID, - PR_TRUE, - PR_TRUE, - &previous); - if (previous) - nsMemory::Free(previous); - return rv; -} -</pre> - -<p>This code adds a new category entry under the topic "content-policy," and it calls <code>AddCategoryEntry</code> in the same way we did in <a href="cn/Creating_XPCOM_Components/Starting_WebLock#Registering_for_Notifications">Registering for Notifications</a>. A similar step is required for unregistration.</p> - -<h3 id="Implementing_the_nsIContentPolicy" name="Implementing_the_nsIContentPolicy">Implementing the <code>nsIContentPolicy</code></h3> - -<p>At this point, you can take the <strong>WebLock</strong> component and install it into a Gecko installation. When the component is loaded, Gecko calls the <code>nsIContentPolicy</code> implementation in <strong>WebLock</strong> on every page load, and this prevents pages from displaying by returning the proper value when the load method is called.</p> - -<p>The web locking policy that we are going to put into place is quite simple: for every load request that comes through, we will ensure that the URI is in the list of "good" URLs on the white list.</p> - -<div class="side-note"> -<p>If you care to extend this implementation so that the list of URLs is held remotely on a server somewhere - as might be the case when the <strong>WebLock</strong> component is used in a corporate intranet, for example - there are Networking APIs in Gecko that will support this. Or you could implement the web lock so that instead of blocking any site, the component would simply log all URLs that are loaded. In any case, the process to make the XPCOM component is the same.</p> -</div> - -<p>The method that handles the check before page loading and the only method we care about in our own implementation of <code>nsIContentPolicy</code> is <code>ShouldLoad()</code>. The other method on the <code>nsIContentPolicy</code> interface is for blocking processing of specific elements in a document, but our policy is more restrictive: if the URL isn't on the white list, the entire page should be blocked. In the <strong>WebLock</strong> component, the <code>ShouldLoad</code> method looks like this:</p> - -<pre>NS_IMETHODIMP WebLock::ShouldLoad(PRInt32 contentType, - nsIURI *contentLocation, - nsISupports *ctxt, - nsIDOMWindow *window, - PRBool *_retval) -</pre> - -<h4 id="Uniform_Resource_Locators" name="Uniform_Resource_Locators">Uniform Resource Locators</h4> - -<p>The method passes in an interface pointer of type <code>nsIURI</code>, which is based on the Uniform Resource Identifier, or URI. This type is defined by the <a class="external" href="http://www.w3.org/">World Wide Web Consortium</a> as:</p> - -<ul> - <li>The naming scheme of the mechanism used to access the resource.</li> - <li>The name of the machine hosting the resource.</li> - <li>The name of the resource itself, given as a path.</li> -</ul> - -<p>In this context, URIs are the strings used refer to places or things on the web. This specific form of URI is called a Uniform Resource Locator, or URL. See the <a class="external" href="http://www.w3.org/TR/REC-html40/intro/intro.html">intro to the HTML 4 specification</a> for more information about URIs and URLs.</p> - -<p>Gecko encapsulates these identifiers into two interfaces, <code>nsIURI</code> and <code>nsIURL</code>. You can <code>QueryInterface</code> between these two interfaces. The networking library, Necko, deals only with these interfaces when handling requests. When you want to download a file using Necko, for example, all you probably have is a string that represents the URI of the file. When you pass that string to Necko, it creates an object that implements at least the <code>nsIURI</code> interface (and perhaps other interfaces as well).</p> - -<p>Currently, the <strong>WebLock</strong> implementation of the <code>ShouldLoad</code> method compares the in parameter with each string in the white list. But it only should do this comparison for remote URLs, because we don't want to block the application from loading local content that it requires, like files it gets via the <code><a class="external" rel="freelink">resource://</a></code> protocol. If URIs of this kind are blocked, then Gecko will not be able to start up, so we'll restrict the content policy to the HTTP and FTP protocols.</p> - -<p>Instead of extracting the string <code>spec</code> out of the <code>nsIURI</code> to do a string comparison, which would require you to do the parsing yourself, you can compare the <code>nsIURI</code> objects with each other, as in the following section. This ensures that the URLs are canonical before they are compared.</p> - -<h4 id="Checking_the_White_List" name="Checking_the_White_List">Checking the White List</h4> - -<p>The <strong>WebLock</strong> implementation of the <code>ShouldLoad</code> method starts by extracting the scheme of the incoming <code>nsIURI</code>. If the scheme isn't "http", "https", or "ftp", it immediately returns true, which continues the loading process unblocked.</p> - -<p>These three are the only kinds of URI that <strong>Weblock</strong> will try to block. When it has one, it walks the linked list and creates a new <code>nsIURI</code> object for each string URL in the list. From each object, <code>ShouldLoad()</code> extracts the host and compares it to the URI. If they match, the component allows the load to continue by returning true. If these two strings do not match, then the component returns return false and blocks the load.</p> - -<div class="side-note"> -<p><span id="URI_Caching"><a id="URI_Caching"></a><strong>URI Caching</strong></span></p> - -<p>Caching the URI would make this method implementation much faster by avoiding the need to create and destroy so many objects. This points out an important drawback of XPCOM, which is that you cannot create an object on the stack.</p> - -<p>Creating this many objects is OK in a tight loop if the buffer of memory that holds the contents of the URLs is guaranteed to be valid for the lifetime of the object. But regardless of how optimized the implementation is with respect to is memory usage, a heap allocation will be made for every XPCOM object created.</p> -</div> - -<p>The string comparison with the URL type "http", "https", and "ftp" looks like this:</p> - -<pre>nsEmbedCString scheme; -contentLocation->GetScheme(scheme); - -if (strcmp("http", scheme.get()) != 0 && - strcmp("https", scheme.get()) != 0 && - strcmp("ftp", scheme.get()) != 0) -{ - // this isn't a type of URI that we deal with. - *_retval = PR_TRUE; - return NS_OK; -} -</pre> - -<h4 id="Creating_nsIURI_Objects" name="Creating_nsIURI_Objects">Creating <code>nsIURI</code> Objects</h4> - -<p>To create an <code>nsIURI</code>, use <code>nsIIOService</code>. <code>nsIIOService</code> is the part of the networking library ("necko") that's responsible for kicking off network requests, managing protocols such as http, ftp, or file, and creating <code>nsIURI</code>s. Necko offers tremendous network functionality, but all the <strong>WebLock</strong> component needs is to create the <code>nsIURI</code> object that can be compared with the URIs on the white list.</p> - -<p>Use the Service Manager to acquire the <code>nsIIOService</code>. Since this object is going to be used for the life of the component, it can also be cached. A good place to get an <code>nsIIOService</code> is in the component's <code>Observe()</code> method, which already has a pointer to the <code>Service Manager</code>. The code for getting the IO service from the Service Manager looks like this:</p> - -<pre>// Get a pointer to the IOService -rv = servMan->GetServiceByContractID("@mozilla.org/network/io-service;1", - NS_GET_IID(nsIIOService), - getter_AddRefs(mIOService)); -</pre> - -<p>Once you have this interface pointer, you can easily create <code>nsIURI</code> objects from a string, as in the following snippet:</p> - -<pre>nsCOMPtr<nsIURI> uri; -nsEmbedCString urlString(node->urlString); -mIOService->NewURI(urlString, - nsnull, - nsnull, - getter_AddRefs(uri)); -</pre> - -<p>This code wraps a C-string with a <code>nsEmbedCString</code>, which you'll recall is a string class that many of the Gecko APIs require. See <a href="cn/Creating_XPCOM_Components/Using_XPCOM_Utilities_to_Make_Things_Easier#String_Classes_in_XPCOM">String Classes in XPCOM</a> for more information about strings.</p> - -<p>Once the URL string is wrapped in a <code>nsEmbedCString</code>, it can be passed to the method <code>NewURI</code>. This method expects to parse the incoming string and create an object which implements an <code>nsIURI</code> interface. The two <code>nsnull</code> parameters passed to <code>NewURI</code> are used to specify the charset of the string and any base URI to use, respectively. We are assuming here that the charset of the URL string is <a href="cn/UTF-8">UTF-8</a>, and also assuming that every URL string is absolute. See the <a class="external" href="http://www.w3.org/TR/REC-html40/intro/intro.html">intro to the HTML 4 specification</a> for more information about relative URLs.</p> - -<p>Here is the complete implementation of the <code>ShouldLoad()</code> method:</p> - -<pre>NS_IMETHODIMP -WebLock::ShouldLoad(PRInt32 contentType, - nsIURI *contentLocation, - nsISupports *ctxt, - nsIDOMWindow *window, - PRBool *_retval) -{ - if (!contentLocation) - return NS_ERROR_FAILURE; - - - nsEmbedCString scheme; - contentLocation->GetScheme(scheme); - - if (strcmp("http", scheme.get()) != 0 && - strcmp("https", scheme.get()) != 0 && - strcmp("ftp", scheme.get()) != 0) - { - // this isn't a type of URI that we deal with - *_retval = PR_TRUE; - return NS_OK; - } - - nsEmbedCString hostToLoad; - contentLocation->GetHost(hostToLoad); - - // Assume failure. Do not allow this nsIURI to load. - *_retval = PR_FALSE; - - nsresult rv; - - urlNode* node = mRootURLNode; - PRBool match = PR_FALSE; - - while (node) - { - nsCOMPtr<nsIURI> uri; - nsEmbedCString urlString(node->urlString); - rv = mIOService->NewURI(urlString, nsnull, nsnull, getter_AddRefs(uri)); - - // if anything bad happens, just abort - if (NS_FAILED(rv)) - return rv; - - nsEmbedCString host; - uri->GetHost(host); - - if (strcmp(hostToLoad.get(), host.get()) == 0) - { - // match found. Allow this nsIURI to load - *_retval = PR_TRUE; - return NS_OK; - } - node = node->next; - } - return NS_OK; -} -</pre> - -<p>At this point, all of the backend work is complete. You can of course improve this backend in many ways, but this example presents the basic creation of what is commonly referred to as a "browser helper object" like <strong>WebLock</strong>. The next chapter looks at how to tie this into the front end - specifically, how to use XPConnect to access and control this component from JavaScript in the user interface.</p> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Starting_WebLock" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Building_the_WebLock_UI">下一页 »</a></p> -</div> <p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/index.html deleted file mode 100644 index 13fd6aff60..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/index.html +++ /dev/null @@ -1,278 +0,0 @@ ---- -title: 创建_XPCOM_组件 -slug: Mozilla/Tech/XPCOM/Guide/Creating_components -tags: - - XPCOM - - 'XPCOM:索引' - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components ---- -<p> </p> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/创建_XPCOM_组件:前言">下一页 »</a></p> -</div><p></p> - -<h3 id=".E5.89.8D.E8.A8.80" name=".E5.89.8D.E8.A8.80"><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%89%8D%E8%A8%80" title="cn/创建_XPCOM_组件/前言">前言</a></h3> - -<dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%89%8D%E8%A8%80#.E8.B0.81.E8.AF.A5.E8.AF.BB.E8.BF.99.E6.9C.AC.E4.B9.A6" title="cn/创建_XPCOM_组件/前言#.E8.B0.81.E8.AF.A5.E8.AF.BB.E8.BF.99.E6.9C.AC.E4.B9.A6">谁该读这本书</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%89%8D%E8%A8%80#.E6.9C.AC.E6.95.99.E7.A8.8B.E7.9A.84.E7.BB.84.E7.BB.87" title="cn/创建_XPCOM_组件/前言#.E6.9C.AC.E6.95.99.E7.A8.8B.E7.9A.84.E7.BB.84.E7.BB.87">本教程的组织</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%89%8D%E8%A8%80#.E6.8C.89.E7.85.A7.E4.BE.8B.E5.AD.90.E6.9D.A5.E5.AD.A6.E4.B9.A0" title="cn/创建_XPCOM_组件/前言#.E6.8C.89.E7.85.A7.E4.BE.8B.E5.AD.90.E6.9D.A5.E5.AD.A6.E4.B9.A0">按照例子来学习</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%89%8D%E8%A8%80#.E6.9C.AC.E4.B9.A6.E7.9A.84.E4.BD.93.E4.BE.8B" title="cn/创建_XPCOM_组件/前言#.E6.9C.AC.E4.B9.A6.E7.9A.84.E4.BD.93.E4.BE.8B">本书的体例</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%89%8D%E8%A8%80#.E8.87.B4.E8.B0.A2" title="cn/创建_XPCOM_组件/前言#.E8.87.B4.E8.B0.A2">致谢</a></dd> -</dl> - -<h3 id="XPCOM_.E7.AE.80.E4.BB.8B" name="XPCOM_.E7.AE.80.E4.BB.8B"><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B" title="cn/创建_XPCOM_组件/XPCOM_简介">XPCOM 简介</a></h3> - -<dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#XPCOM_.E8.A7.A3.E5.86.B3.E6.96.B9.E6.A1.88" title="cn/创建_XPCOM_组件/XPCOM_简介#XPCOM_.E8.A7.A3.E5.86.B3.E6.96.B9.E6.A1.88">XPCOM 解决方案</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#Gecko" title="cn/创建_XPCOM_组件/XPCOM_简介#Gecko">Gecko</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#.E7.BB.84.E4.BB.B6" title="cn/创建_XPCOM_组件/XPCOM_简介#.E7.BB.84.E4.BB.B6">组件</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#.E6.8E.A5.E5.8F.A3" title="cn/创建_XPCOM_组件/XPCOM_简介#.E6.8E.A5.E5.8F.A3">接口</a> - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#.E6.8E.A5.E5.8F.A3.E4.B8.8E.E5.B0.81.E8.A3.85" title="cn/创建_XPCOM_组件/XPCOM_简介#.E6.8E.A5.E5.8F.A3.E4.B8.8E.E5.B0.81.E8.A3.85">接口与封装</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#nsISupports_.E5.9F.BA.E6.8E.A5.E5.8F.A3" title="cn/创建_XPCOM_组件/XPCOM_简介#nsISupports_.E5.9F.BA.E6.8E.A5.E5.8F.A3"><code>nsISupports</code> 基接口</a></dd> - </dl> - </dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#XPCOM_.E7.9A.84ID" title="cn/创建_XPCOM_组件/XPCOM_简介#XPCOM_.E7.9A.84ID">XPCOM 的ID</a> - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#CID" title="cn/创建_XPCOM_组件/XPCOM_简介#CID">CID</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#.E5.A5.91.E7.BA.A6_ID" title="cn/创建_XPCOM_组件/XPCOM_简介#.E5.A5.91.E7.BA.A6_ID">契约 ID</a></dd> - </dl> - </dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#.E7.B1.BB.E5.8E.82" title="cn/创建_XPCOM_组件/XPCOM_简介#.E7.B1.BB.E5.8E.82">类厂</a> - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#XPIDL_.E4.B8.8E.E7.B1.BB.E5.9E.8B.E5.BA.93" title="cn/创建_XPCOM_组件/XPCOM_简介#XPIDL_.E4.B8.8E.E7.B1.BB.E5.9E.8B.E5.BA.93">XPIDL 与类型库</a></dd> - </dl> - </dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#XPCOM_.E6.9C.8D.E5.8A.A1" title="cn/创建_XPCOM_组件/XPCOM_简介#XPCOM_.E6.9C.8D.E5.8A.A1">XPCOM 服务</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#XPCOM_.E7.B1.BB.E5.9E.8B" title="cn/创建_XPCOM_组件/XPCOM_简介#XPCOM_.E7.B1.BB.E5.9E.8B">XPCOM 类型</a> - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#.E6.96.B9.E6.B3.95.E7.B1.BB.E5.9E.8B" title="cn/创建_XPCOM_组件/XPCOM_简介#.E6.96.B9.E6.B3.95.E7.B1.BB.E5.9E.8B">方法类型</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#.E5.BC.95.E7.94.A8.E8.AE.A1.E6.95.B0" title="cn/创建_XPCOM_组件/XPCOM_简介#.E5.BC.95.E7.94.A8.E8.AE.A1.E6.95.B0">引用计数</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#.E7.8A.B6.E6.80.81.E7.A0.81" title="cn/创建_XPCOM_组件/XPCOM_简介#.E7.8A.B6.E6.80.81.E7.A0.81">状态码</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#.E5.8F.98.E9.87.8F.E6.98.A0.E5.B0.84" title="cn/创建_XPCOM_组件/XPCOM_简介#.E5.8F.98.E9.87.8F.E6.98.A0.E5.B0.84">变量映射</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/XPCOM_%E7%AE%80%E4%BB%8B#.E9.80.9A.E7.94.A8_XPCOM_.E9.94.99.E8.AF.AF.E7.A0.81" title="cn/创建_XPCOM_组件/XPCOM_简介#.E9.80.9A.E7.94.A8_XPCOM_.E9.94.99.E8.AF.AF.E7.A0.81">通用 XPCOM 错误码</a></dd> - </dl> - </dd> -</dl> - -<h3 id=".E4.BD.BF.E7.94.A8_XPCOM_.E7.BB.84.E4.BB.B6" name=".E4.BD.BF.E7.94.A8_XPCOM_.E7.BB.84.E4.BB.B6"><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8_XPCOM_%E7%BB%84%E4%BB%B6" title="cn/创建_XPCOM_组件/使用_XPCOM_组件">使用 XPCOM 组件</a></h3> - -<dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8_XPCOM_%E7%BB%84%E4%BB%B6#.E7.BB.84.E4.BB.B6.E7.9A.84.E4.BE.8B.E5.AD.90" title="cn/创建_XPCOM_组件/使用_XPCOM_组件#.E7.BB.84.E4.BB.B6.E7.9A.84.E4.BE.8B.E5.AD.90">组件的例子</a> - - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8_XPCOM_%E7%BB%84%E4%BB%B6#Cookie_.E7.AE.A1.E7.90.86.E5.99.A8" title="cn/创建_XPCOM_组件/使用_XPCOM_组件#Cookie_.E7.AE.A1.E7.90.86.E5.99.A8">Cookie 管理器</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8_XPCOM_%E7%BB%84%E4%BB%B6#WebBrowserFind_.E7.BB.84.E4.BB.B6" title="cn/创建_XPCOM_组件/使用_XPCOM_组件#WebBrowserFind_.E7.BB.84.E4.BB.B6"><strong>WebBrowserFind</strong> 组件</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8_XPCOM_%E7%BB%84%E4%BB%B6#WebLock_.E7.BB.84.E4.BB.B6" title="cn/创建_XPCOM_组件/使用_XPCOM_组件#WebLock_.E7.BB.84.E4.BB.B6"><strong>WebLock</strong> 组件</a></dd> - </dl> - </dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8_XPCOM_%E7%BB%84%E4%BB%B6#Mozilla_.E4.B8.AD.E4.BD.BF.E7.94.A8.E7.9A.84.E7.BB.84.E4.BB.B6" title="cn/创建_XPCOM_组件/使用_XPCOM_组件#Mozilla_.E4.B8.AD.E4.BD.BF.E7.94.A8.E7.9A.84.E7.BB.84.E4.BB.B6">Mozilla 中使用的组件</a> - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8_XPCOM_%E7%BB%84%E4%BB%B6#.E6.9F.A5.E6.89.BE_Mozilla_.E7.BB.84.E4.BB.B6" title="cn/创建_XPCOM_组件/使用_XPCOM_组件#.E6.9F.A5.E6.89.BE_Mozilla_.E7.BB.84.E4.BB.B6">查找 Mozilla 组件</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8_XPCOM_%E7%BB%84%E4%BB%B6#.E5.9C.A8_Cpp_.E4.BB.A3.E7.A0.81.E4.B8.AD.E4.BD.BF.E7.94.A8_XPCOM_.E7.BB.84.E4.BB.B6" title="cn/创建_XPCOM_组件/使用_XPCOM_组件#.E5.9C.A8_Cpp_.E4.BB.A3.E7.A0.81.E4.B8.AD.E4.BD.BF.E7.94.A8_XPCOM_.E7.BB.84.E4.BB.B6">在 Cpp 代码中使用 XPCOM 组件</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8_XPCOM_%E7%BB%84%E4%BB%B6#XPConnect:_.E5.9C.A8.E8.84.9A.E6.9C.AC.E4.B8.AD.E4.BD.BF.E7.94.A8_XPCOM_.E7.BB.84.E4.BB.B6" title="cn/创建_XPCOM_组件/使用_XPCOM_组件#XPConnect:_.E5.9C.A8.E8.84.9A.E6.9C.AC.E4.B8.AD.E4.BD.BF.E7.94.A8_XPCOM_.E7.BB.84.E4.BB.B6">XPConnect: 在脚本中使用 XPCOM 组件</a></dd> - </dl> - </dd> -</dl> - -<h3 id=".E7.BB.84.E4.BB.B6.E5.86.85.E5.B9.95" name=".E7.BB.84.E4.BB.B6.E5.86.85.E5.B9.95"><a href="/cn/Creating_XPCOM_Components/Component_Internals" title="cn/Creating_XPCOM_Components/Component_Internals">组件内幕</a></h3> - -<dl> - <dd><a href="/cn/Creating_XPCOM_Components/Component_Internals#.E7.94.A8Cpp.E4.B9.A6.E5.86.99.E7.BB.84.E4.BB.B6" title="cn/Creating_XPCOM_Components/Component_Internals#.E7.94.A8Cpp.E4.B9.A6.E5.86.99.E7.BB.84.E4.BB.B6">用Cpp书写组件</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Component_Internals#XPCOM.E5.88.9D.E5.A7.8B.E5.8C.96" title="cn/Creating_XPCOM_Components/Component_Internals#XPCOM.E5.88.9D.E5.A7.8B.E5.8C.96">XPCOM初始化</a> - <dl> - <dd><a href="/cn/Creating_XPCOM_Components/Component_Internals#XPCOM.E6.B3.A8.E5.86.8C.E6.8F.8F.E8.BF.B0" title="cn/Creating_XPCOM_Components/Component_Internals#XPCOM.E6.B3.A8.E5.86.8C.E6.8F.8F.E8.BF.B0">XPCOM注册描述</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Component_Internals#XPCOM.E6.B3.A8.E5.86.8C.E7.9A.84.E6.96.B9.E6.B3.95" title="cn/Creating_XPCOM_Components/Component_Internals#XPCOM.E6.B3.A8.E5.86.8C.E7.9A.84.E6.96.B9.E6.B3.95">XPCOM注册的方法</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Component_Internals#.E8.87.AA.E5.8A.A8.E6.B3.A8.E5.86.8C" title="cn/Creating_XPCOM_Components/Component_Internals#.E8.87.AA.E5.8A.A8.E6.B3.A8.E5.86.8C">自动注册</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Component_Internals#The_Shutdown_Process" title="cn/Creating_XPCOM_Components/Component_Internals#The_Shutdown_Process">The Shutdown Process</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Component_Internals#XPCOM.E7.BB.84.E4.BB.B6.E5.BA.93.E7.9A.84.E4.B8.89.E4.B8.AA.E9.83.A8.E5.88.86" title="cn/Creating_XPCOM_Components/Component_Internals#XPCOM.E7.BB.84.E4.BB.B6.E5.BA.93.E7.9A.84.E4.B8.89.E4.B8.AA.E9.83.A8.E5.88.86">XPCOM组件库的三个部分</a></dd> - </dl> - </dd> - <dd><a href="/cn/Creating_XPCOM_Components/Component_Internals#XPCOM_Glue" title="cn/Creating_XPCOM_Components/Component_Internals#XPCOM_Glue">XPCOM Glue</a> - <dl> - <dd><a href="/cn/Creating_XPCOM_Components/Component_Internals#The_Glue_Library" title="cn/Creating_XPCOM_Components/Component_Internals#The_Glue_Library">The Glue Library</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Component_Internals#XPCOM_String_Classes" title="cn/Creating_XPCOM_Components/Component_Internals#XPCOM_String_Classes">XPCOM String Classes</a></dd> - </dl> - </dd> -</dl> - -<h3 id=".E5.BB.BA.E7.AB.8B.E7.BB.84.E4.BB.B6.E4.BB.A3.E7.A0.81" name=".E5.BB.BA.E7.AB.8B.E7.BB.84.E4.BB.B6.E4.BB.A3.E7.A0.81"><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code">建立组件代码</a></h3> - -<dl> - <dd><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E6.88.91.E4.BB.AC.E5.B0.86.E5.81.9A.E4.BB.80.E4.B9.88" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E6.88.91.E4.BB.AC.E5.B0.86.E5.81.9A.E4.BB.80.E4.B9.88">我们将做什么</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E7.BB.84.E4.BB.B6.E6.B3.A8.E5.86.8C" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E7.BB.84.E4.BB.B6.E6.B3.A8.E5.86.8C">组件注册</a> - <dl> - <dd><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#The_regxpcom_Program" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#The_regxpcom_Program">The <code>regxpcom</code> Program</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E5.85.B6.E4.BB.96.E7.9A.84.E6.B3.A8.E5.86.8C.E9.80.94.E5.BE.84" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E5.85.B6.E4.BB.96.E7.9A.84.E6.B3.A8.E5.86.8C.E9.80.94.E5.BE.84">其他的注册途径</a></dd> - </dl> - </dd> - <dd><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E6.A6.82.E8.A7.88WebLock_Module_Source" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E6.A6.82.E8.A7.88WebLock_Module_Source">概览<strong>WebLock</strong> Module Source</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E6.B7.B1.E5.BA.A6.E6.8C.96.E6.8E.98:_.E9.9C.80.E8.A6.81.E7.9A.84Includes.E5.92.8C.E5.B8.B8.E9.87.8F" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E6.B7.B1.E5.BA.A6.E6.8C.96.E6.8E.98:_.E9.9C.80.E8.A6.81.E7.9A.84Includes.E5.92.8C.E5.B8.B8.E9.87.8F">深度挖掘: 需要的Includes和常量</a> - <dl> - <dd><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#XPCOM.E4.B8.AD.E7.9A.84.E6.A0.87.E8.AF.86.E7.AC.A6" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#XPCOM.E4.B8.AD.E7.9A.84.E6.A0.87.E8.AF.86.E7.AC.A6">XPCOM中的标识符</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E6.B3.A8.E5.86.8C.E8.BF.87.E7.A8.8B.E7.9A.84.E4.BB.A3.E7.A0.81" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E6.B3.A8.E5.86.8C.E8.BF.87.E7.A8.8B.E7.9A.84.E4.BB.A3.E7.A0.81">注册过程的代码</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E6.B3.A8.E5.86.8C.E7.94.A8.E7.9A.84.E6.96.B9.E6.B3.95" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E6.B3.A8.E5.86.8C.E7.94.A8.E7.9A.84.E6.96.B9.E6.B3.95">注册用的方法</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E5.BB.BA.E7.AB.8B.E4.BD.A0.E7.9A.84.E7.BB.84.E4.BB.B6.E7.9A.84.E6.8E.A5.E5.8F.A3" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#.E5.BB.BA.E7.AB.8B.E4.BD.A0.E7.9A.84.E7.BB.84.E4.BB.B6.E7.9A.84.E6.8E.A5.E5.8F.A3">建立你的组件的接口</a></dd> - </dl> - </dd> - <dd><a href="/cn/Creating_XPCOM_Components/%E5%BB%BA%E7%AB%8B%E7%BB%84%E4%BB%B6%E4%BB%A3%E7%A0%81#webLock1.cpp" title="cn/Creating_XPCOM_Components/建立组件代码#webLock1.cpp"><code>webLock1.cpp</code></a></dd> -</dl> - -<h3 id=".E4.BD.BF.E7.94.A8XPCOM.E5.B7.A5.E5.85.B7.E7.B1.BB.E8.AE.A9.E4.BA.8B.E6.83.85.E5.8F.98.E5.BE.97.E7.AE.80.E5.8D.95" name=".E4.BD.BF.E7.94.A8XPCOM.E5.B7.A5.E5.85.B7.E7.B1.BB.E8.AE.A9.E4.BA.8B.E6.83.85.E5.8F.98.E5.BE.97.E7.AE.80.E5.8D.95"><a href="/cn/%E5%88%9B%E5%BB%BAXPCOM%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8XPCOM%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%AE%A9%E4%BA%8B%E6%83%85%E5%8F%98%E5%BE%97%E7%AE%80%E5%8D%95" title="cn/创建XPCOM组件/使用XPCOM工具类让事情变得简单">使用XPCOM工具类让事情变得简单</a></h3> - -<dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BAXPCOM%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8XPCOM%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%AE%A9%E4%BA%8B%E6%83%85%E5%8F%98%E5%BE%97%E7%AE%80%E5%8D%95#XPCOM_.E5.AE.8F" title="cn/创建XPCOM组件/使用XPCOM工具类让事情变得简单#XPCOM_.E5.AE.8F">XPCOM 宏</a> - - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BAXPCOM%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8XPCOM%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%AE%A9%E4%BA%8B%E6%83%85%E5%8F%98%E5%BE%97%E7%AE%80%E5%8D%95#.E9.80.9A.E7.94.A8XPCOM.E6.A8.A1.E5.9D.97.E5.AE.8F" title="cn/创建XPCOM组件/使用XPCOM工具类让事情变得简单#.E9.80.9A.E7.94.A8XPCOM.E6.A8.A1.E5.9D.97.E5.AE.8F">通用XPCOM模块宏</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BAXPCOM%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8XPCOM%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%AE%A9%E4%BA%8B%E6%83%85%E5%8F%98%E5%BE%97%E7%AE%80%E5%8D%95#.E5.9F.BA.E6.9C.AC.E5.AE.9E.E7.8E.B0.E5.AE.8F" title="cn/创建XPCOM组件/使用XPCOM工具类让事情变得简单#.E5.9F.BA.E6.9C.AC.E5.AE.9E.E7.8E.B0.E5.AE.8F">基本实现宏</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BAXPCOM%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8XPCOM%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%AE%A9%E4%BA%8B%E6%83%85%E5%8F%98%E5%BE%97%E7%AE%80%E5%8D%95#.E5.A3.B0.E6.98.8E.E5.AE.8F" title="cn/创建XPCOM组件/使用XPCOM工具类让事情变得简单#.E5.A3.B0.E6.98.8E.E5.AE.8F">声明宏</a></dd> - </dl> - </dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BAXPCOM%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8XPCOM%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%AE%A9%E4%BA%8B%E6%83%85%E5%8F%98%E5%BE%97%E7%AE%80%E5%8D%95#webLock2.cpp" title="cn/创建XPCOM组件/使用XPCOM工具类让事情变得简单#webLock2.cpp"><code>webLock2.cpp</code></a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BAXPCOM%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8XPCOM%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%AE%A9%E4%BA%8B%E6%83%85%E5%8F%98%E5%BE%97%E7%AE%80%E5%8D%95#XPCOM.E4.B8.AD.E7.9A.84.E5.AD.97.E7.AC.A6.E4.B8.B2.E7.B1.BB" title="cn/创建XPCOM组件/使用XPCOM工具类让事情变得简单#XPCOM.E4.B8.AD.E7.9A.84.E5.AD.97.E7.AC.A6.E4.B8.B2.E7.B1.BB">XPCOM中的字符串类</a> - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BAXPCOM%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8XPCOM%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%AE%A9%E4%BA%8B%E6%83%85%E5%8F%98%E5%BE%97%E7%AE%80%E5%8D%95#.E4.BD.BF.E7.94.A8.E5.AD.97.E7.AC.A6.E4.B8.B2" title="cn/创建XPCOM组件/使用XPCOM工具类让事情变得简单#.E4.BD.BF.E7.94.A8.E5.AD.97.E7.AC.A6.E4.B8.B2">使用字符串</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BAXPCOM%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8XPCOM%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%AE%A9%E4%BA%8B%E6%83%85%E5%8F%98%E5%BE%97%E7%AE%80%E5%8D%95#nsEmbedString_.E5.92.8C_nsEmbedCString" title="cn/创建XPCOM组件/使用XPCOM工具类让事情变得简单#nsEmbedString_.E5.92.8C_nsEmbedCString"><code>nsEmbedString</code> 和 <code>nsEmbedCString</code></a></dd> - </dl> - </dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BAXPCOM%E7%BB%84%E4%BB%B6/%E4%BD%BF%E7%94%A8XPCOM%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%AE%A9%E4%BA%8B%E6%83%85%E5%8F%98%E5%BE%97%E7%AE%80%E5%8D%95#.E6.99.BA.E8.83.BD.E6.8C.87.E9.92.88" title="cn/创建XPCOM组件/使用XPCOM工具类让事情变得简单#.E6.99.BA.E8.83.BD.E6.8C.87.E9.92.88">智能指针</a></dd> -</dl> - -<h3 id=".E5.BC.80.E5.A7.8BWebLock" name=".E5.BC.80.E5.A7.8BWebLock"><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock" title="cn/创建_XPCOM_组件/开始WebLock">开始<strong>WebLock</strong></a></h3> - -<dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E5.90.AF.E5.8A.A8.E6.97.B6.E8.A2.AB.E8.B0.83.E7.94.A8" title="cn/创建_XPCOM_组件/开始WebLock#.E5.90.AF.E5.8A.A8.E6.97.B6.E8.A2.AB.E8.B0.83.E7.94.A8">启动时被调用</a> - - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E6.B3.A8.E5.86.8C.E5.88.B0.E6.B6.88.E6.81.AF" title="cn/创建_XPCOM_组件/开始WebLock#.E6.B3.A8.E5.86.8C.E5.88.B0.E6.B6.88.E6.81.AF">注册到消息</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E8.AE.BF.E9.97.AECategory_Manager" title="cn/创建_XPCOM_组件/开始WebLock#.E8.AE.BF.E9.97.AECategory_Manager">访问Category Manager</a></dd> - </dl> - </dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E6.8F.90.E4.BE.9BWebLock.E8.AE.BF.E9.97.AE" title="cn/创建_XPCOM_组件/开始WebLock#.E6.8F.90.E4.BE.9BWebLock.E8.AE.BF.E9.97.AE">提供<strong>WebLock</strong>访问</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E5.BB.BA.E7.AB.8BWebLock.E7.BC.96.E7.A8.8B.E6.8E.A5.E5.8F.A3" title="cn/创建_XPCOM_组件/开始WebLock#.E5.BB.BA.E7.AB.8BWebLock.E7.BC.96.E7.A8.8B.E6.8E.A5.E5.8F.A3">建立<strong>WebLock</strong>编程接口</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E5.9C.A8XPIDL.E4.B8.AD.E5.AE.9A.E4.B9.89WebLock.E6.8E.A5.E5.8F.A3" title="cn/创建_XPCOM_组件/开始WebLock#.E5.9C.A8XPIDL.E4.B8.AD.E5.AE.9A.E4.B9.89WebLock.E6.8E.A5.E5.8F.A3">在XPIDL中定义<strong>WebLock</strong>接口</a> - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#XPIDL.E4.B9.A6.E5.86.99.E6.A0.BC.E5.BC.8F" title="cn/创建_XPCOM_组件/开始WebLock#XPIDL.E4.B9.A6.E5.86.99.E6.A0.BC.E5.BC.8F">XPIDL书写格式</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E8.84.9A.E6.9C.AC.E5.8C.96.E6.8E.A5.E5.8F.A3" title="cn/创建_XPCOM_组件/开始WebLock#.E8.84.9A.E6.9C.AC.E5.8C.96.E6.8E.A5.E5.8F.A3">脚本化接口</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E5.AE.9E.E7.8E.B0nsISupports" title="cn/创建_XPCOM_组件/开始WebLock#.E5.AE.9E.E7.8E.B0nsISupports">实现<code>nsISupports</code></a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#Web_Locking_.E6.8E.A5.E5.8F.A3" title="cn/创建_XPCOM_组件/开始WebLock#Web_Locking_.E6.8E.A5.E5.8F.A3">Web Locking 接口</a></dd> - </dl> - </dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E5.AE.9E.E7.8E.B0WebLock" title="cn/创建_XPCOM_组件/开始WebLock#.E5.AE.9E.E7.8E.B0WebLock">实现<strong>WebLock</strong></a> - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E5.A3.B0.E6.98.8E.E5.AE.8F" title="cn/创建_XPCOM_组件/开始WebLock#.E5.A3.B0.E6.98.8E.E5.AE.8F">声明宏</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E5.9C.A8XPCOM.E4.B8.AD.E8.A1.A8.E8.BE.BE.E8.BF.94.E5.9B.9E.E5.80.BC" title="cn/创建_XPCOM_组件/开始WebLock#.E5.9C.A8XPCOM.E4.B8.AD.E8.A1.A8.E8.BE.BE.E8.BF.94.E5.9B.9E.E5.80.BC">在XPCOM中表达返回值</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#XPIDL.E4.BB.A3.E7.A0.81.E7.94.9F.E6.88.90" title="cn/创建_XPCOM_组件/开始WebLock#XPIDL.E4.BB.A3.E7.A0.81.E7.94.9F.E6.88.90">XPIDL代码生成</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E4.BB.8E.E5.AE.A2.E6.88.B7.E7.AB.AF.E8.8E.B7.E5.8F.96WebLock_Service" title="cn/创建_XPCOM_组件/开始WebLock#.E4.BB.8E.E5.AE.A2.E6.88.B7.E7.AB.AF.E8.8E.B7.E5.8F.96WebLock_Service">从客户端获取WebLock Service</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E5.AE.9E.E7.8E.B0iWebLock.E6.8E.A5.E5.8F.A3" title="cn/创建_XPCOM_组件/开始WebLock#.E5.AE.9E.E7.8E.B0iWebLock.E6.8E.A5.E5.8F.A3">实现<code>iWebLock</code>接口</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#The_Directory_Service" title="cn/创建_XPCOM_组件/开始WebLock#The_Directory_Service">The Directory Service</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E7.94.A8nsIFile.E6.94.B9.E5.8F.98.E8.B7.AF.E5.BE.84" title="cn/创建_XPCOM_组件/开始WebLock#.E7.94.A8nsIFile.E6.94.B9.E5.8F.98.E8.B7.AF.E5.BE.84">用<code>nsIFile</code>改变路径</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E7.94.A8nsIFile.E6.93.8D.E4.BD.9C.E6.96.87.E4.BB.B6" title="cn/创建_XPCOM_组件/开始WebLock#.E7.94.A8nsIFile.E6.93.8D.E4.BD.9C.E6.96.87.E4.BB.B6">用<code>nsIFile</code>操作文件</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E7.94.A8nsILocalFile.E8.AF.BB.E5.8F.96.E6.95.B0.E6.8D.AE" title="cn/创建_XPCOM_组件/开始WebLock#.E7.94.A8nsILocalFile.E8.AF.BB.E5.8F.96.E6.95.B0.E6.8D.AE">用<code>nsILocalFile</code>读取数据</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#.E5.A4.84.E7.90.86White_List_Data" title="cn/创建_XPCOM_组件/开始WebLock#.E5.A4.84.E7.90.86White_List_Data">处理White List Data</a></dd> - </dl> - </dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#iWebLock.E6.96.B9.E6.B3.95.E5.88.97.E4.B8.BE" title="cn/创建_XPCOM_组件/开始WebLock#iWebLock.E6.96.B9.E6.B3.95.E5.88.97.E4.B8.BE"><code>iWebLock</code>方法列举</a> - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#Lock_.E5.92.8C_Unlock" title="cn/创建_XPCOM_组件/开始WebLock#Lock_.E5.92.8C_Unlock"><code>Lock</code> and <code>Unlock</code></a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#AddSite" title="cn/创建_XPCOM_组件/开始WebLock#AddSite"><code>AddSite</code></a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#RemoveSite" title="cn/创建_XPCOM_组件/开始WebLock#RemoveSite"><code>RemoveSite</code></a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#SetSites" title="cn/创建_XPCOM_组件/开始WebLock#SetSites"><code>SetSites</code></a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#GetNext" title="cn/创建_XPCOM_组件/开始WebLock#GetNext"><code>GetNext</code></a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#GetSites" title="cn/创建_XPCOM_组件/开始WebLock#GetSites"><code>GetSites</code></a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BC%80%E5%A7%8BWebLock#HasMoreElements" title="cn/创建_XPCOM_组件/开始WebLock#HasMoreElements"><code>HasMoreElements</code></a></dd> - </dl> - </dd> -</dl> - -<h3 id="Finishing_the_Component" name="Finishing_the_Component"><a href="/cn/Creating_XPCOM_Components/Finishing_the_Component" title="cn/Creating_XPCOM_Components/Finishing_the_Component">Finishing the Component</a></h3> - -<dl> - <dd><a href="/cn/Creating_XPCOM_Components/Finishing_the_Component#Using_Frozen_Interfaces" title="cn/Creating_XPCOM_Components/Finishing_the_Component#Using_Frozen_Interfaces">Using Frozen Interfaces</a> - - <dl> - <dd><a href="/cn/Creating_XPCOM_Components/Finishing_the_Component#Copying_Interfaces_Into_Your_Build_Environment" title="cn/Creating_XPCOM_Components/Finishing_the_Component#Copying_Interfaces_Into_Your_Build_Environment">Copying Interfaces Into Your Build Environment</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Finishing_the_Component#Implementing_the_nsIContentPolicy_Interface" title="cn/Creating_XPCOM_Components/Finishing_the_Component#Implementing_the_nsIContentPolicy_Interface">Implementing the <code>nsIContentPolicy</code> Interface</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Finishing_the_Component#Receiving_Notifications" title="cn/Creating_XPCOM_Components/Finishing_the_Component#Receiving_Notifications">Receiving Notifications</a></dd> - </dl> - </dd> - <dd><a href="/cn/Creating_XPCOM_Components/Finishing_the_Component#Implementing_the_nsIContentPolicy" title="cn/Creating_XPCOM_Components/Finishing_the_Component#Implementing_the_nsIContentPolicy">Implementing the <code>nsIContentPolicy</code></a> - <dl> - <dd><a href="/cn/Creating_XPCOM_Components/Finishing_the_Component#Uniform_Resource_Locators" title="cn/Creating_XPCOM_Components/Finishing_the_Component#Uniform_Resource_Locators">Uniform Resource Locators</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Finishing_the_Component#Checking_the_White_List" title="cn/Creating_XPCOM_Components/Finishing_the_Component#Checking_the_White_List">Checking the White List</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Finishing_the_Component#Creating_nsIURI_Objects" title="cn/Creating_XPCOM_Components/Finishing_the_Component#Creating_nsIURI_Objects">Creating <code>nsIURI</code> Objects</a></dd> - </dl> - </dd> -</dl> - -<h3 id="Building_the_WebLock_UI" name="Building_the_WebLock_UI"><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI">Building the <strong>WebLock</strong> UI</a></h3> - -<dl> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#User_Interface_Package_List" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#User_Interface_Package_List">User Interface Package List</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#Client_Code_Overview" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#Client_Code_Overview">Client Code Overview</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#XUL" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#XUL">XUL</a> - <dl> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#The_XUL_Document" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#The_XUL_Document">The XUL Document</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#The_Locking_UI" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#The_Locking_UI">The Locking UI</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#Site_Adding_UI" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#Site_Adding_UI">Site Adding UI</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#weblock.xul" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#weblock.xul"><code>weblock.xul</code></a></dd> - </dl> - </dd> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#Overlaying_New_User_Interface_Into_Mozilla" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#Overlaying_New_User_Interface_Into_Mozilla">Overlaying New User Interface Into Mozilla</a> - <dl> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#webLockOverlay.xul" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#webLockOverlay.xul"><code>webLockOverlay.xul</code></a></dd> - </dl> - </dd> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#Other_Resources" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#Other_Resources">Other Resources</a> - <dl> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#weblock.css" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#weblock.css"><code>weblock.css</code></a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Building_the_WebLock_UI#Image_Resources" title="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#Image_Resources">Image Resources</a></dd> - </dl> - </dd> -</dl> - -<h3 id=".E6.89.93.E5.8C.85_WebLock" name=".E6.89.93.E5.8C.85_WebLock"><a href="/cn/Creating_XPCOM_Components/Packaging_WebLock" title="cn/Creating_XPCOM_Components/Packaging_WebLock">打包 WebLock</a></h3> - -<dl> - <dd><a href="/cn/Creating_XPCOM_Components/Packaging_WebLock#Component_Installation_Overview" title="cn/Creating_XPCOM_Components/Packaging_WebLock#Component_Installation_Overview">组件安装预览</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Packaging_WebLock#Archiving_Resources" title="cn/Creating_XPCOM_Components/Packaging_WebLock#Archiving_Resources">资源归档</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Packaging_WebLock#The_WebLock_Installation_Script" title="cn/Creating_XPCOM_Components/Packaging_WebLock#The_WebLock_Installation_Script"><strong>WebLock</strong> 安装脚本</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Packaging_WebLock#The_WebLock_Trigger_Script" title="cn/Creating_XPCOM_Components/Packaging_WebLock#The_WebLock_Trigger_Script"><strong>WebLock</strong> 跟踪脚本</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Packaging_WebLock#Distributing_Your_Component" title="cn/Creating_XPCOM_Components/Packaging_WebLock#Distributing_Your_Component">分发你的组件</a></dd> -</dl> - -<h3 id=".E9.99.84.E5.BD.95_A_-_.E5.BB.BA.E7.AB.8B_Gecko_SDK" name=".E9.99.84.E5.BD.95_A_-_.E5.BB.BA.E7.AB.8B_Gecko_SDK"><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BB%BA%E7%AB%8B_Gecko_SDK" title="cn/创建_XPCOM_组件/建立_Gecko_SDK">附录 A - 建立 Gecko SDK</a></h3> - -<dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BB%BA%E7%AB%8B_Gecko_SDK#.E4.B8.8B.E8.BD.BD.E5.92.8C.E5.BB.BA.E7.AB.8B_SDK" title="cn/创建_XPCOM_组件/建立_Gecko_SDK#.E4.B8.8B.E8.BD.BD.E5.92.8C.E5.BB.BA.E7.AB.8B_SDK">下载和建立 SDK</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BB%BA%E7%AB%8B_Gecko_SDK#.E7.BC.96.E8.AF.91.E4.B8.80.E4.B8.AA_Microsoft_Visual_Cpp_.E5.B7.A5.E7.A8.8B" title="cn/创建_XPCOM_组件/建立_Gecko_SDK#.E7.BC.96.E8.AF.91.E4.B8.80.E4.B8.AA_Microsoft_Visual_Cpp_.E5.B7.A5.E7.A8.8B">编译一个 Microsoft Visual Cpp 工程</a> - <dl> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BB%BA%E7%AB%8B_Gecko_SDK#.E5.88.9B.E5.BB.BA.E4.B8.80.E4.B8.AA.E6.96.B0.E7.9A.84.E5.B7.A5.E7.A8.8B" title="cn/创建_XPCOM_组件/建立_Gecko_SDK#.E5.88.9B.E5.BB.BA.E4.B8.80.E4.B8.AA.E6.96.B0.E7.9A.84.E5.B7.A5.E7.A8.8B">创建一个新的工程</a></dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BB%BA%E7%AB%8B_Gecko_SDK#.E6.8A.8A_Gecko_SDK_.E6.B7.BB.E5.8A.A0.E5.88.B0.E5.B7.A5.E7.A8.8B.E8.AE.BE.E7.BD.AE" title="cn/创建_XPCOM_组件/建立_Gecko_SDK#.E6.8A.8A_Gecko_SDK_.E6.B7.BB.E5.8A.A0.E5.88.B0.E5.B7.A5.E7.A8.8B.E8.AE.BE.E7.BD.AE">把 Gecko SDK 添加到工程设置</a></dd> - </dl> - </dd> - <dd><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BB%BA%E7%AB%8B_Gecko_SDK#Unix_.E4.B8.8B.E7.9A.84.E4.B8.80.E4.B8.AA_Makefile" title="cn/创建_XPCOM_组件/建立_Gecko_SDK#Unix_.E4.B8.8B.E7.9A.84.E4.B8.80.E4.B8.AA_Makefile">Unix 下的一个 Makefile</a></dd> -</dl> - -<h3 id=".E9.99.84.E5.BD.95B_-_.E8.B5.84.E6.BA.90" name=".E9.99.84.E5.BD.95B_-_.E8.B5.84.E6.BA.90"><a href="/cn/Creating_XPCOM_Components/Resources" title="cn/Creating_XPCOM_Components/Resources">附录B - 资源</a></h3> - -<dl> - <dd><a href="/cn/Creating_XPCOM_Components/Resources#WebLock_Resources" title="cn/Creating_XPCOM_Components/Resources#WebLock_Resources">WebLock 资源</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Resources#Gecko_Resources" title="cn/Creating_XPCOM_Components/Resources#Gecko_Resources">Gecko 资源</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Resources#XPCOM_Resources" title="cn/Creating_XPCOM_Components/Resources#XPCOM_Resources">XPCOM 资源</a></dd> - <dd><a href="/cn/Creating_XPCOM_Components/Resources#General_Development_Resources" title="cn/Creating_XPCOM_Components/Resources#General_Development_Resources">General Development 资源</a></dd> -</dl> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/创建_XPCOM_组件:前言">下一页 »</a></p> -</div> <p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> - -<p> </p> - -<p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/packaging_weblock/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/packaging_weblock/index.html deleted file mode 100644 index 3a7744ec03..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/packaging_weblock/index.html +++ /dev/null @@ -1,136 +0,0 @@ ---- -title: Packaging WebLock -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/Packaging_WebLock -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/Packaging_WebLock ---- -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Building_the_WebLock_UI" style="float: left;">« 上一页</a><a href="/zh-CN/docs/创建_XPCOM_组件:建立_Gecko_SDK">下一页 »</a></p> -</div><p></p> - -<p>这是教程最后一部分, 我们将把所有的web所有的组件成分打包成可安装到其他应用中的形式 - the library itself, the type library, the header file, and the user interface resources. The first section, <a href="#Component_Installation_Overview">Component Installation Overview</a>, describes the general installation process in Mozilla. The following sections describe the steps you can take to organize the <strong>WebLock</strong> component for distribution and installation.</p> - -<div class="side-note"> -<p>请注意: 这个教程主要是关注组件开发本身, 所以这部分描述有关打包和安装到Gecko的过程是很简单的. 如果你希望了解详细的打包和安装组件到基于Gecko应用的信息,应该参考http://www.mozilla.org/projects/xpinstall.</p> -</div> - -<h3 id="Component_Installation_Overview" name="Component_Installation_Overview">Component Installation Overview</h3> - -<p>XPInstall是一组JavaScript APIs用来建立安装脚本. 使用XPInstall,你可以为装载到Gecko-based应用,Mozilla extensions,或者individual components的组件建立web-based安装脚本. <strong>WebLock</strong> component安装脚本也可以用来注册组件到browser(see <a href="cn/Creating_XPCOM_Components/Component_Internals#Registration_Methods_in_XPCOM">Registration Methods in XPCOM</a> for more information on registration).</p> - -<p>下面的例子安装脚本使用了Mozilla XPInstall技术来操作安装并且以高层次Javascript对象的方式来跟Mozilla's<em>chrome registry</em> 交互。</p> - -<div class="side-note"> -<p><span id="What_Is_the_Chrome_Registry?"><a id="What_Is_the_Chrome_Registry?"></a><strong>What Is the Chrome Registry?</strong></span></p> - -<p>Like the Windows registry, the chrome registry is a database of information about applications, skins, and other extensions that have been installed in a Gecko application. Since Mozilla and other Gecko-based applications are cross-platform, this database is abstracted above the operating system or any particular platform's registry.</p> - -<p>The chrome registry lives in a series of RDF/XML files in the application directory of Mozilla and other Gecko-based browsers, where new installs, user configurable data, skins, and other information are related to one another and the application itself.</p> -</div> - -<p>XPInstall中的JavaScript APIs <code>Install</code> 对象下载包含了安装文件的JAR并且调用注册方法来告诉 Mozilla 新的组件和用来调用<strong>WebLock</strong>组件的UI. <a href="#WebLock_Installation_Script">WebLock Installation Script</a> 是完整的<em>trigger installation script</em> , 可以从网页触发. 文件被存储在JAR file <code>weblock.jar</code>, 这是一个简单的ZIP文件,以XPI结尾,有时候也可能包含一个内部的安装脚本<code>install.js</code>.</p> - -<p>一旦你把组件和<strong>Weblock</strong>相关资源正确打包(see the following section, <a href="#Archiving_Resources">Archiving Resources</a>), <strong>WebLock</strong>安装脚本是一个简单的事情(see <a href="#The_WebLock_Installation_Script">The WebLock Installation Script</a>).</p> - -<h3 id="Archiving_Resources" name="Archiving_Resources">Archiving Resources</h3> - -<p>Once you have compiled all the resources that make up the <strong>WebLock</strong> component and the files that make up the user interface that will be added to the browser, you can place these within a subdirectory called <code>weblock</code>.</p> - -<p>Place the entire subdirectory into a ZIP archive and name the archive <code>weblock.xpi</code>. The archive, its subdirectory structure, and its contents should look like this:</p> - -<p><span id="%3Ccode%3Eweblock.xpi%3C/code%3E_Archive_Viewed_in_WinZIP"><a id="%3Ccode%3Eweblock.xpi%3C/code%3E_Archive_Viewed_in_WinZIP"></a><strong><code>weblock.xpi</code> Archive Viewed in WinZIP</strong></span></p> - -<p><img alt="Image:weblock-zipped-package.png"></p> - -<p>Note that the top level of the archive holds the <code>install.js</code> installation file, an RDF manifest for the package as a whole, and the component files (<code>weblock.xpt</code> and <code>weblock4.dll</code>). The component files are copied to the components directory of the Gecko application, and the weblock subdirectory gets copied over into the chrome subdirectory, where its UI resources can be added dynamically to the XUL-based Gecko application.</p> - -<p>The next section shows how this process of downloading, copying and registering the necessary files from the XPI can be achieved with an XPInstall installation script.</p> - -<h3 id="The_WebLock_Installation_Script" name="The_WebLock_Installation_Script">The <strong>WebLock</strong> Installation Script</h3> - -<p>安装脚本是一个存储在XPI中的JavaScript文件. 他必须在包的根目录 (i.e., <code>weblock.xpi</code>) itself. 一旦触发 (see <a href="#The_WebLock_Trigger_Script">The WebLock Trigger Script</a>), 安章脚本将:</p> - -<ul> - <li>downloads the <strong>WebLock</strong> component and places it in the <code>components</code> directory</li> - <li>copies the <code>weblock</code> subdirectory in the Mozilla chrome application subdirectory</li> - <li>registers both the component and the UI</li> -</ul> - -<p>The XPInstall API提供了一些核心方法<sup><a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components/Packaging_WebLock#endnote_essential-methods">[essential-methods]</a></sup>例如 <code>initInstall</code>, <code>registerChrome</code>, <code>addFile</code>, and others.</p> - -<p><span id="WebLock_Installation_Script"><a id="WebLock_Installation_Script"></a><strong>WebLock Installation Script</strong></span></p> - -<pre>// initialize the installation -var err = initInstall("WebLock", "weblock", 1.0); - -var componentsDir = getFolder("Components"); -var cf = getFolder("Chrome"); - -// add the DLL and say where it'll go -addFile("weblock.dll", 1.0, "weblock.dll", componentsDir, ""); - -// add the typelib also -addFile("weblock.xpt", "1.0", "weblock.xpt", componentsDir, ""); - -// add the weblock subdirectory of the XPI and specify that -// it be installed in the chrome application directory -err = addDirectory("weblock", "1.0", "", chromeDir, ""); - -// ? have to register component here or with regxpcom? - -// register the new UI with the mozilla chrome registry - -registerChrome(CONTENT, getFolder(cf,"weblock.xpi"),"weblock"); -registerChrome(SKIN, getFolder(cf, "weblock.xpi"),"weblock"); - -// perform the installation if there are no errors -if (err==SUCCESS) - performInstall(); -else - cancelInstall(err); -</pre> - -<h3 id="The_WebLock_Trigger_Script" name="The_WebLock_Trigger_Script">The <strong>WebLock</strong> Trigger Script</h3> - -<p>The <code>trigger script</code> is the script placed on a web page that actually initiates an XPInstall installation and calls the installation script that appears in the XPI. The following HTML specifies a complete webpage in which the trigger script is defined as a JavaScript function, <code>installWebLock</code>, that gets called when the user clicks the hyperlink.</p> - -<pre><html> -<title>WebLock Installation</title> -<script type="text/javascript"> -/* - * Trigger function that downloads the XPI so the - * install.js file inside can be read and executed - */ -function installWebLock() -{ - weblock_xpi = {'WebLock Extension': 'weblock.xpi'}; - InstallTrigger.install(weblock_xpi); -} -</script> - -<h1>Install WebLock</h1> - -<p><a href="#" onclick="installWebLock();">install weblock</a></p> - -</html> -</pre> - -<h3 id="Distributing_Your_Component" name="Distributing_Your_Component">Distributing Your Component</h3> - -<p>Once you have the component packaged properly and the necessary installation and trigger scripts, you are ready to distribute your component so others can install it in their Gecko applications.</p> - -<p>In Mozilla and Netscape browsers, XPInstall makes this process especially easy by providing the file format (XPI) and the necessary installation scripts for doing a web-based installation. As <a href="#WebLock_Installation_Script">WebLock Installation Script</a> demonstrates, XPInstall uses special keywords to refer to common installation directories such as <code>components</code> in a generalized, cross-platform way.</p> - -<p>If you are installing <strong>WebLock</strong> in an Gecko-based application for which XPInstall is not available, then you will have to devise a separate installation scheme. We leave this as an exercise for the reader.</p> - -<ol> - <li><div class="blockIndicator note"><strong>Note:</strong> install-object-methods</div> The methods are available on the main <code>Install</code> object, which is implied in the script below in the same way that the <code>window</code> object is implied in JavaScript manipulation of the DOM of a web page. In other words, the fragment <code>initInstall()</code> from the script is equivalent to <code>Install.initInstall()</code>.</li> -</ol> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Building_the_WebLock_UI" style="float: left;">« 上一页</a><a href="/zh-CN/docs/创建_XPCOM_组件:建立_Gecko_SDK">下一页 »</a></p> -</div><p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/preface/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/preface/index.html deleted file mode 100644 index 0710f0a701..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/preface/index.html +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: 前言 -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/Preface -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/Preface ---- -<p> </p> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/创建_XPCOM_组件:XPCOM_简介">下一页 »</a></p> -</div>这本书是关于 Gecko, 以及如何创建基于 Gecko 的 <a href="/cn/XPCOM" title="cn/XPCOM">XPCOM</a> 组件. 尽管本书的重点是放在把你的 C++ 代码制作成一个使用 Gecko 的组件的步骤之上, 我们还希望这个过程能够讨论到所有构建 XPCOM 的相关工具, 技巧和技术. 因此本书的安排上是作为一个参考书, 使读者能够自己创建组件, 学习不同的 XPCOM 内容. 比如说, 导言中包含了什么是组件的讨论; 第一章中你可以编译基本的源码并注册到 Mozilla 中, 由此讨论了组件于模块之间的关系, 以及一般的注册过程.<p></p> - -<p>每章的开始会给出这一章的主要内容. Sidebar sections are included to highlight technical details. 在本书的结尾, 如果能够达到本书的目的的话, 读者应该学会如何创建一个组件, Gecko 中的 XPCOM 组件框架.</p> - -<h3 id=".E8.B0.81.E8.AF.A5.E8.AF.BB.E8.BF.99.E6.9C.AC.E4.B9.A6" name=".E8.B0.81.E8.AF.A5.E8.AF.BB.E8.BF.99.E6.9C.AC.E4.B9.A6">谁该读这本书</h3> - -<p><a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6" title="cn/创建_XPCOM_组件">创建 XPCOM 组件</a> 是为 C++ 开发人员而写. 尽管你可能会使用 <a href="/cn/JavaScript" title="cn/JavaScript">JavaScript</a>, <a href="/cn/C" title="cn/C">C</a> 或其他的语言来创建 XPCOM 组件, 组件管理的实现是采用 C++, 许多关于如何创建 XPCOM 组件的讨论也是从 C++ 语言开始的. 然而并不要求读者是一个 C++ 语言的专家, 你需要了解的是基本的 C++ 继承和封装的思想, 我们在书中将尽可能的解释这些 C++ 语言的特性的使用. 由于 Mozilla 使用 JavaScript 脚本语言来访问 XPCOM 组件, 所以熟悉 JavaScript 会很有帮助.</p> - -<p>XPCOM 是 Cross Platform Component Object Model (跨平台组件模型)的缩写. 就象它的名字暗示的, XPCOM 类似于 Microsoft 的 COM. 开发 MS COM 的经验大多都可以被应用到 XPCOM. 然而本书假设读者对 COM 一无所知, 本书将包含关于 COM 基本思想的介绍.</p> - -<p>本书将描述一个控制浏览动作的 XPCOM 组件的制作过程. 尽管 XPCOM 的多数应用环境与 web 浏览并没有关系, 但是 XPCOM 现在的主要客户应用是 Gecko, 一个开源的, 遵循标准的嵌入式 web 浏览器, 所以它是最简单的, 而且是最实用的展示 XPCOM 功能的例子. 本教程中关于组件的详细描述在这里 <a href="/cn/Creating_XPCOM_Components/Creating_the_Component_Code#What_We.27ll_Be_Working_On" title="cn/Creating_XPCOM_Components/Creating_the_Component_Code#What_We.27ll_Be_Working_On">What We'll Be Working On</a>.</p> - -<h3 id=".E6.9C.AC.E6.95.99.E7.A8.8B.E7.9A.84.E7.BB.84.E7.BB.87" name=".E6.9C.AC.E6.95.99.E7.A8.8B.E7.9A.84.E7.BB.84.E7.BB.87">本教程的组织</h3> - -<p>下面的列表给出了编制一个称为 <strong>WebLock</strong> 的 XPCOM 组件的整体步骤, 这个组件向基于 Gecko 的浏览器提供了阻止网站访问的功能. 每个步骤都有各自的章节, 在各个章节中会讨论相关的内容.</p> - -<ul> - <li>创建组件的通用模块.</li> - <li>使用 C++ 宏, 特殊的字符串类以及智能指针来优化代码.</li> - <li>为组件定义功能; 为这个功能创建一个 <a href="/cn/XPIDL" title="cn/XPIDL">XPIDL</a> 接口; 生成实现代码, 规格定制的 <strong>WebLock</strong> 接口.</li> - <li>完整实现 <strong>WebLock</strong> 组件: <code>nsIContentPolicy</code>, 文件 I/O, 加锁等.</li> - <li>创建 WebLock 组件用户接口.</li> - <li>为发布和安装 <strong>WebLock</strong> 打包.</li> -</ul> - -<h3 id=".E6.8C.89.E7.85.A7.E4.BE.8B.E5.AD.90.E6.9D.A5.E5.AD.A6.E4.B9.A0" name=".E6.8C.89.E7.85.A7.E4.BE.8B.E5.AD.90.E6.9D.A5.E5.AD.A6.E4.B9.A0">按照例子来学习</h3> - -<p>安装 XPCOM 到本地机器上的方法有很多, 如果你已经编译了 Mozilla 1.2 或更高的版本源码, 你就已经有了 XPCOM 框架. 如果你还没有下载 Mozilla 源码, 更简单的方法是下载 Gecko SDK, 它包含了 XPCOM 组件框架的库和工具.</p> - -<p>如果有了上面的工具, 你就可以编译自己的组件, 并把这个组件添加到 Gecko 库中. 我们这里讨论的 <strong>WebLock</strong> 组件是一个实用的浏览器扩展, 编译它需要 1.2 或更高版本的 Gecko SDK / Mozilla 源码.</p> - -<p>本书假设你使用的是 SDK, 下载 SDK, 编译, 和获取可用于编成的 Gecko 组件的方法在本书的附录, <a href="/cn/%E5%88%9B%E5%BB%BA_XPCOM_%E7%BB%84%E4%BB%B6/%E5%BB%BA%E7%AB%8B_Gecko_SDK" title="cn/创建_XPCOM_组件/建立_Gecko_SDK">建立 Gecko SDK</a>.</p> - -<h3 id=".E6.9C.AC.E4.B9.A6.E7.9A.84.E4.BD.93.E4.BE.8B" name=".E6.9C.AC.E4.B9.A6.E7.9A.84.E4.BD.93.E4.BE.8B">本书的体例</h3> - -<p>下面列出的是格式化文档的习惯,他们用于本书中特定的信息类型并且让信息检索变得简单。目标是使用尽量少的格式类型,同时能辨别不同的信息类型。</p> - -<table class="standard-table"> - <tbody> - <tr> - <td class="header">Format</td> - <td class="header">Description</td> - </tr> - <tr> - <td><strong>bold</strong></td> - <td><strong>component names</strong> 显示为粗题文字</td> - </tr> - <tr> - <td><code>monospace</code></td> - <td><code>code listings</code>, <code>interface names</code> 和 <code>members</code> of interfaces (e.g., <code>createInstance()</code>) 用monospaced 字体表达. 代码行放在不同的box内. 此外, <code>filenames</code> 和 <code>directories</code> 也用 monospaced 字体.</td> - </tr> - <tr> - <td><em>italic</em></td> - <td><em>variables</em> appear in italic. 重要的条目和新的概念第一次在文本中出现的时候也应该是斜体字。这些条目通常会立刻有进一步的解释,或者读者可以在本书的某个地方找到详细的解释。</td> - </tr> - <tr> - <td>link</td> - <td>References to other sections and to figures and tables are links to those sections.</td> - </tr> - </tbody> -</table> - -<h3 id=".E8.87.B4.E8.B0.A2" name=".E8.87.B4.E8.B0.A2">致谢</h3> - -<p>Thanks to Peter Lubczynski, John Gaunt, Ellen Evans, and Alec Flett for technical reviews. A special thanks goes to Darin Fisher for his very acute observations, close reading, and attention to detail. </p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/创建_XPCOM_组件:XPCOM_简介">下一页 »</a></p> -</div><p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> - -<p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/resources/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/resources/index.html deleted file mode 100644 index b23e6eb4c2..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/resources/index.html +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: 资源 -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/Resources -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/Resources ---- -<p><a href="cn/Link_title">Link title</a> - <i> - Italic text</i> -</p> -<pre class="script">Insert formula here</pre> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/setting_up_the_gecko_sdk/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/setting_up_the_gecko_sdk/index.html deleted file mode 100644 index 3e8c8516e2..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/setting_up_the_gecko_sdk/index.html +++ /dev/null @@ -1,204 +0,0 @@ ---- -title: 建立 Gecko SDK -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/Setting_up_the_Gecko_SDK -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/Setting_up_the_Gecko_SDK ---- -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Packaging_WebLock" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Resources">下一页 »</a></p> -</div><p></p> - -<p>这一章提供建立 Gecko SDK 的基本方法, 下面会告诉开发人员如何下载和组织 Gecko SDK, 如何象 <em>WebLock</em> 一样创建一个新的组件工程.</p> - -<h3 id=".E4.B8.8B.E8.BD.BD.E5.92.8C.E5.BB.BA.E7.AB.8B_SDK" name=".E4.B8.8B.E8.BD.BD.E5.92.8C.E5.BB.BA.E7.AB.8B_SDK">下载和建立 SDK</h3> - -<p>Gecko SDK 提供了编译 XPCOM 组件所需要的所有的工具, 头文件和库. SDK 现在有 Windows 和 Linux 两个版本, 其他操作系统上的 SDK 正在开发. SDK 在下面的地址下载:</p> - -<ul> - <li>Linux: <a class="external" href="http://ftp.mozilla.org/pub/mozilla/releases/mozilla1.4a/gecko-sdk-i686-pc-linux-gnu-1.4a.tar.gz" rel="freelink">http://ftp.mozilla.org/pub/mozilla/r...nu-1.4a.tar.gz</a></li> - <li>Windows: <a class="external" href="http://ftp.mozilla.org/pub/mozilla/releases/mozilla1.4a/gecko-sdk-win32-1.4a.zip" rel="freelink">http://ftp.mozilla.org/pub/mozilla/r...win32-1.4a.zip</a></li> -</ul> - -<p>注意版号要大于1.4a. 可以在下面的地址获取更新的 SDK 版本 <a class="external" href="http://ftp.mozilla.org/pub/mozilla/releases/" rel="freelink">http://ftp.mozilla.org/pub/mozilla/releases/</a>.</p> - -<p>一旦你下载了SDK, 你可以解压缩到任何合适的目录. 在本附录中, 我们建立Windows Gecko SDK 到 <code>c:\gecko-sdk\</code>. 如果你选择其他的位置, 记得调整这里描述的设置指向这个位置(e.g., in the <a href="#建立一个Microsoft_visual_cpp工程">建立一个Microsoft visual cpp工程</a> 章节) .</p> - -<p>当你解压缩SDK,它的目录结构看起来应该是:</p> - -<p><span id="Layout_of_the_Extracted_SDK"><a id="Layout_of_the_Extracted_SDK"></a><strong>Layout of the Extracted SDK</strong></span></p> - -<p><img alt="Image:sdk-layout.png" class="internal" src="/@api/deki/files/2682/=Sdk-layout.png"></p> - -<p>目录分别代表SDK中的不同模块。例如网络通讯的所有头文件放在<code>necko</code>目录中,而所有XPCOM需要的头文件则放在 XPCOM 目录中。 这个目录结构使得编译脚本变得比较复杂(因为会产生很多include路径)但是他帮助把SKD的部分组织得更有条例。</p> - -<p>两组顶级头文件是比较特别的。<code>mozilla-config.h</code>列出了SDK中使用的所有define,在你的文件中包含着个头文件会保证你创建的组件和Gecko库使用的相同的define。注意<code>mozilla-config.h</code>可能需要在你的组件代码中第一个被include.</p> - -<p>每一个模块的目录都分成三个子目录:</p> - -<p><span id="Module_Subdirectories"><a id="Module_Subdirectories"></a><strong>Module Subdirectories</strong></span></p> - -<p><img alt="Image:module-directory-subdirs.png" class="internal" src="/@api/deki/files/2669/=Module-directory-subdirs.png"></p> - -<p><code>bin</code>目录包含了静态库,动态库, 和一些可能会在开发中使用的tools。<code>idl</code>目录包含了模块所公开的公共的IDL文件。<code>includes</code>目录包含了你的组件使用的C++头文件。</p> - -<p>现在我们应该提到XPCOM公开的一组二进制代码文件。下面的列表罗列了可执行的Windows文件名:</p> - -<table class="standard-table"> - <tbody> - <tr> - <td class="header">Application Name</td> - <td class="header">Description of functionality</td> - </tr> - <tr> - <td><code>regxpcom.exe</code></td> - <td>Registers or Unregisters components with XPCOM</td> - </tr> - <tr> - <td><code>xpidl.exe</code></td> - <td>Generates typelib and C++ headers from XPIDL</td> - </tr> - <tr> - <td><code>xpt_dump.exe</code></td> - <td>Prints out information about a given typelib</td> - </tr> - <tr> - <td><code>xpt_link.exe</code></td> - <td>Combines multiple typelibs into a single typelib</td> - </tr> - </tbody> -</table> - -<table class="standard-table"> - <tbody> - <tr> - <td class="header">Library Name</td> - <td class="header">Description of functionality</td> - </tr> - <tr> - <td><code>xpcomglue.lib</code></td> - <td>XPCOM Glue library to be used by xpcom components.</td> - </tr> - </tbody> -</table> - -<h3 id=".E7.BC.96.E8.AF.91.E4.B8.80.E4.B8.AA_Microsoft_Visual_Cpp_.E5.B7.A5.E7.A8.8B" name=".E7.BC.96.E8.AF.91.E4.B8.80.E4.B8.AA_Microsoft_Visual_Cpp_.E5.B7.A5.E7.A8.8B">编译一个 Microsoft Visual Cpp 工程</h3> - -<p>一担你建立了Gecko SDK,你可以创建一个Miscrosoft visual c++项目来处理你基于SDK的组件开发。</p> - -<h4 id=".E5.88.9B.E5.BB.BA.E4.B8.80.E4.B8.AA.E6.96.B0.E7.9A.84.E5.B7.A5.E7.A8.8B" name=".E5.88.9B.E5.BB.BA.E4.B8.80.E4.B8.AA.E6.96.B0.E7.9A.84.E5.B7.A5.E7.A8.8B">创建一个新的工程</h4> - -<p>启动Visual c++以后,从文件菜单重选择new。然后在新建对话框中选择"Win32 Dynamic-Link Library"。 使用对话框右边的栏目输入你的项目和位置。(这个例子使用了 "SampleGeckoProject"作为问兼并,位置是<code>C:\</code> ).</p> - -<p><span id="New_Dialog"><a id="New_Dialog"></a><strong>New Dialog</strong></span></p> - -<p><img alt="Image:new-vcpp-project.png" class="internal" src="/@api/deki/files/2671/=New-vcpp-project.png"></p> - -<p>选择OK. 在出现的Win32 Dynamic-Link Library 对话框里, 你可以选择缺省的 "An Empty DLL Project" 作为DLL的类型.</p> - -<p><img alt="Image:vcpp-dll-dialog.png" class="internal" src="/@api/deki/files/2690/=Vcpp-dll-dialog.png"></p> - -<p>选择Finish. Microsoft Studio 将根据你的设定建立一个新的项目并且展开项目开发视图。</p> - -<h4 id=".E6.8A.8A_Gecko_SDK_.E6.B7.BB.E5.8A.A0.E5.88.B0.E5.B7.A5.E7.A8.8B.E8.AE.BE.E7.BD.AE" name=".E6.8A.8A_Gecko_SDK_.E6.B7.BB.E5.8A.A0.E5.88.B0.E5.B7.A5.E7.A8.8B.E8.AE.BE.E7.BD.AE">把 Gecko SDK 添加到工程设置</h4> - -<p>为了build使用Gecko的所有信息,你还需要进一步修改项目使得它知道在哪里取得Gecko SDK。为了编辑项目设置, 从项目菜单种选择Settings (or press Alt-F7).</p> - -<p>大部分你在下面步骤中所做的修改方法都适用于所有项目设置的修改(包括Debug和Optimize)。选择从Setting菜单中选择"All Configurations",出现一个下拉菜单:</p> - -<p><img alt="Image:vcpp-project-settings.png" class="internal" src="/@api/deki/files/2692/=Vcpp-project-settings.png"></p> - -<p>在C/C++ tab,选择Preprocessor组。在这个窗口里你要添加到Gecko SDK的include路径,以及两个 preprocessor defines:</p> - -<ul> - <li><code>XPCOM_GLUE</code></li> - <li><code>MOZILLA_STRICT_API</code></li> -</ul> - -<p>最起码你要加上include <code>nspr</code>, <code>embedstring</code> 和 <code>string</code> <code>include</code>目录, 和<code>xpcom</code> <code>include</code> 子目录. 如果你的组件适用其他SDK的部分(例如Necko), 你也要添加指向他们的路径.</p> - -<p>假定你使用例子项目的路径,这些路径看起来会是:</p> - -<ul> - <li><code>c:\gecko-sdk\embedstring\include</code></li> - <li><code>c:\gecko-sdk\xpcom\include</code></li> - <li><code>c:\gecko-sdk\nspr\include</code></li> - <li><code>c:\gecko-sdk\string\include</code></li> -</ul> - -<p><img alt="Image:vcpp-project-settings-includes.png" class="internal" src="/@api/deki/files/2691/=Vcpp-project-settings-includes.png"></p> - -<p>在C++ language组, 禁止异常处理. 正如在 <a href="/cn/XPCOM%E6%A6%82%E8%A7%88/XPCOM%E4%B8%AD%E7%9A%84%E5%BC%82%E5%B8%B8" title="cn/XPCOM概览/XPCOM中的异常">XPCOM中的异常</a>章节所表明的, 异常处理不支持跨越Interface, 所以使用这个功能将可能在开发中引起问题。</p> - -<p><strong>WebLock</strong> 组件需要引用必要的库文件以使用XPCOM Glue. 为添加这些库文件,选择Link tab, 然后选择Input category. 在这个面板上不要连接到 <code>nspr</code>, <code>embedstring</code>和<code>xpcom</code>中的子目录<code>include</code> ,而改用<code>bin</code>子目录.</p> - -<p>我们也会连接到一些Object/library 模块中的库:</p> - -<ul> - <li><code>nspr4.lib</code></li> - <li><code>plds4.lib</code></li> - <li><code>plc4.lib</code></li> - <li><code>embedstring.lib</code></li> - <li><code>xpcomglue.lib</code></li> -</ul> - -<p>这些设定看起来会是:</p> - -<p><img alt="Image:vcpp-project-settings.png" class="internal" src="/@api/deki/files/2692/=Vcpp-project-settings.png"></p> - -<p>最后一个你需要让Gecko SDK在你的项目中设定成功的修改是"Use run-time library" 设定为 "Multithreaded DLL." 因为这个设置是根据其他设定而确定的,你<strong>必须设定Release configuration run-time library 为 release multithreaded DLL runtime, 并且Debug configuration 设定为 the debug multithreaded dll runtime</strong> (这个需要澄清一下):</p> - -<p><img alt="Image:vcpp-runtime-settings.png" class="internal" src="/@api/deki/files/2693/=Vcpp-runtime-settings.png"></p> - -<p>完成所有这些设定后,选择OK. 这就完成了项目设定并且让你的项目能包含和编译XPCOM组件.</p> - -<h3 id="Unix_.E4.B8.8B.E7.9A.84.E4.B8.80.E4.B8.AA_Makefile" name="Unix_.E4.B8.8B.E7.9A.84.E4.B8.80.E4.B8.AA_Makefile">Unix 下的一个 Makefile</h3> - -<p>Linux 下不采用工程而采用 <code>Makefile</code> 来组织代码. <code>Makefile</code> 中放置编译环境中的编译选项, 包括使用 Gecko SDK 编译的路径和配置更新等.</p> - -<p>下面是一个使用 SDK 来编译的 <code>Makefile</code>, 这里对 <code>Makefile</code> 的详细用法不做解释. 它与 Visual C++ 的工程(<a href="#Building_a_Microsoft_Visual_Cpp_Project">Building a Microsoft Visual Cpp Project</a>)相类似, 关于 Makefile 的命令请参看 <a class="external" href="http://www.gnu.org/manual/make/">Make 手册</a>.</p> - -<p><span id="Gecko_SDK_%E4%B8%8B%E7%9A%84%E4%B8%80%E4%B8%AA_Makefile_%E4%BE%8B%E5%AD%90"><a id="Gecko_SDK_%E4%B8%8B%E7%9A%84%E4%B8%80%E4%B8%AA_Makefile_%E4%BE%8B%E5%AD%90"></a><strong>Gecko SDK 下的一个 Makefile 例子</strong></span></p> - -<pre>CXX = c++ - -CPPFLAGS += -fno-rtti \ - -fno-exceptions \ - -shared - -# Change this to point at your Gecko SDK directory. -GECKO_SDK_PATH = /home/dougt/gecko-sdk - -# GCC only define which allows us to not have to #include mozilla-config -# in every .cpp file. If your not using GCC remove this line and add -# #include "mozilla-config.h" to each of your .cpp files. -GECKO_CONFIG_INCLUDE = -include mozilla-config.h - -GECKO_DEFINES = -DXPCOM_GLUE -DMOZILLA_STRICT_API - -GECKO_INCLUDES = -I $(GECKO_SDK_PATH) \ - -I $(GECKO_SDK_PATH)/xpcom/include \ - -I $(GECKO_SDK_PATH)/nspr/include \ - -I $(GECKO_SDK_PATH)/string/include \ - -I $(GECKO_SDK_PATH)/embedstring/include - -GECKO_LDFLAGS = -L $(GECKO_SDK_PATH)/xpcom/bin -lxpcomglue \ - -L $(GECKO_SDK_PATH)/nspr/bin -lnspr4 \ - -L $(GECKO_SDK_PATH)/nspr/bin -lplds4 \ - -L $(GECKO_SDK_PATH)/embedstring/bin/ -lembedstring - -build: - $(CXX) -o MozShim.so $(GECKO_CONFIG_INCLUDE) $(GECKO_DEFINES) $(GECKO_INCLUDES) $(GECK\ -O_LDFLAGS) $(CPPFLAGS) $(CXXFLAGS) MozShim.cpp - chmod +x MozShim.so - -clean: - rm MozShim.so -</pre> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Packaging_WebLock" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Resources">下一页 »</a></p> -</div> <p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/starting_weblock/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/starting_weblock/index.html deleted file mode 100644 index 65efd53a72..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/starting_weblock/index.html +++ /dev/null @@ -1,1104 +0,0 @@ ---- -title: 开始WebLock -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/Starting_WebLock -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/Starting_WebLock ---- -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Using_XPCOM_Utilities_to_Make_Things_Easier" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Finishing_the_Component">下一页 »</a></p> -</div><p></p> - -<p>在本章,我们开始设计和实现网络锁定功能本身。我们已经建立了实现多数通用组件功能的模块(例如注册)。这章将关注实际操作网页锁定的功能。</p> - -<h3 id="Getting_Called_at_Startup" name="Getting_Called_at_Startup">Getting Called at Startup</h3> - -<p>没有人是一个孤岛,组件也一样。你所建立的例子组件到目前为止还没有任何功能。当他被注册以后,他没做任何事情。</p> - -<p>为了当某些事件发生的时候被启动或者通知到,例子组件需要挂接到Mozilla,或者覆盖一个现存组件,或者注册到一些事件上面。<strong>WebLock</strong>用后面的方式在Gecko Profile Startup发生的时候被调用。当Gecko应用启动的时候,注册的组件被创建或者通过通用观察者接口被提醒<code>nsIObserver</code>。</p> - -<p><em>Observer</em>是一些对象,他们当特定的事件发生的时候被通知。使用这种机制提供了一个相互不必了解而可以在对象之间传送信息的机制。</p> - -<p>通常,一个对象会通知一系列观察者。例如一个对象被创建的时候它的<code>observe</code>方法被调用,或者它可以注册当XPCOM关闭的时候被通知。这个接口的核心是<code>observe</code>方法。</p> - -<pre>void observe(in nsISupports aSubject, - in string aTopic, - in wstring aData); -</pre> - -<p>实际上ovserver方法的参数没有什么限制。这些参数根据事件的类型变化。例如,XPCOM关闭的时候,aSubject和aData被定义,aTopic被定义为“xpcom-shotdown’,如果你的对象希望注册到这些事件上面,他首先要实现nsIObserver接口,一旦你完成这些,实现nsIObserverService的observer服务将会利用接口通知你的对象,如下所示:</p> - -<p><span id="The_Observer_Interfaces"><a id="The_Observer_Interfaces"></a><strong>The Observer Interfaces</strong></span></p> - -<p><img alt="Image:observation-overview.png"></p> - -<p>上图表现了observer服务管理了所有<code>nsIObserver</code>对象的列表. 当通知产生的时候,<code>nsIObserverService</code>把呼叫者从<code>NotifyObserver()</code>发送出的消息传送给<code>nsIObserver</code>的<code>Observe()</code>方法。这是一个让不同的类解藕的办法。<code>nsIObserver</code>是一个通用的接口,用来在两个或多个对象间传递信息,而不必定义一个特定的冻结接口,它也是XPCOM建立扩展的一个方式。</p> - -<p>WebLock组件对<code>nsIObserver</code>接口的实现和对<code>nsIFactory</code>接口是类似的。<span class="comment">XXX what is Example 2?</span>下面的例子2中,你改变一个类的定义为支持<code>nsIObserver</code>接口并且改变<code>NS_IMPL_ISUPOORTS1</code>,从而<code>QueryInterface</code>实现知道组件也支持<code>nsIObserver</code>。启动的时候被通知的<code>WebLock</code>类定义如下:</p> - -<pre>class WebLock: public nsIObserver { - public: - WebLock(); - virtual ~WebLock(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER -}; - -NS_IMPL_ISUPPORTS1(WebLock, nsIObserver); -</pre> - -<p><code>Observe()</code>最简单的实现仅仅是比较字符串<code>aTopic</code>和对象所接受事件所定义的值. 如果相匹配, 你可以按照你的方式处理事件. 如果对象仅仅注册到一个消息上, 那你可以忽略字符串 <code>aTopic</code> 而仅仅处理事件. 换句话说,对于对象所没有注册的事件,<code>Observe</code> 方法不应该被调用。</p> - -<pre>NS_IMETHODIMP -WebLock::Observe(nsISupports *aSubject, - const char *aTopic, - const PRUnichar *aData) -{ - return NS_OK; -} -</pre> - -<p>从observer service来的消息可能是间接的. 直接获得来自observer service的消息的方法是初始化一个<code>nsIObserver</code> 对象. 大多数情况下这样是可以的,但是要注意当你通过这个消息建立组件的情况. 因为组件还没有被建立,所以不存在初始化的 <code>nsIObserver</code> 对象可以用来传递给 <code>nsIObserverService</code>, 组件代码在他被装载以前不能做什么.</p> - -<h4 id=".E6.B3.A8.E5.86.8C.E5.88.B0.E6.B6.88.E6.81.AF" name=".E6.B3.A8.E5.86.8C.E5.88.B0.E6.B6.88.E6.81.AF">注册到消息</h4> - -<p><code>nsIObserverService</code> 接口有处理注册和注销一个<code>nsIObserver</code>对象的方法. 这两个方法用来动态添加或者删除一个notification topic上的observer. 但是 <strong>WebLock</strong> 要被自动初始化和添加到observer service, 这就意味着需要一些数据持久化。(不管怎么说, 我们需要组件在程序每次启动的时候也启动).</p> - -<p>This is where a new service that manages sets of related data comes in handy. This service, the <code>nsICategoryService</code>, is what XPCOM and Gecko embedding applications use to persist lists of <code>nsIObserver</code> components that want to have startup notification.</p> - -<p>The <code>nsICategoryService</code> maintains sets of name-value pairs like the one below.</p> - -<p><span id="The_Category_Manager"><a id="The_Category_Manager"></a><strong>The Category Manager</strong></span></p> - -<p><img alt="Image:category-manager-table.png"></p> - -<p>Every category is identified by a string that represents the name of the category. Each category contains a set of name-value pairs. For example, you might have a category named "Important People" in which the name-value pairs would be names and phone numbers. The format of the name-value pair is left up to you.</p> - -<p>This data structure is more than enough to support the persisting of components that what to be started up. The category name also maps nicely onto the notion of a notification "topic." The topic name could be something like "xpcom-startup", for instance, and the name-value pair could contain the contract IDs required to create the components requesting startup. In fact, this is exactly how categories are used to handle registration with XPCOM for startup notification. You will see the code which does this in the next section.</p> - -<h4 id="Getting_Access_to_the_Category_Manager" name="Getting_Access_to_the_Category_Manager">Getting Access to the Category Manager</h4> - -<p>Two fields in the <code>nsModuleComponentInfo</code> structure introduced in the last section are addresses for registration and unregistration callbacks. The first callback is called when the component's <code>nsIModule::RegisterSelf</code> method is called. This callback allows the component to execute any one-time registration code it may need. The inverse of this function is the unregistration callback, where it's a good idea to undo whatever the registration function did. The two functions look like this:</p> - -<pre>static NS_METHOD -WebLockRegistration(nsIComponentManager *aCompMgr, - nsIFile *aPath, - const char *registryLocation, - const char *componentType, - const nsModuleComponentInfo *info); - -static NS_METHOD -WebLockUnregistration(nsIComponentManager *aCompMgr, - nsIFile *aPath, - const char *registryLocation, - const nsModuleComponentInfo *info); -</pre> - -<p>The names of the functions can be anything you wish. Both functions are passed the Component Manager and the path to the component, including the opaque <code>registryLocation</code>. These are also parameters in the <code>nsIModule</code> implementation in <span class="comment">XXX what is Example 1? link to it here</span>Example 1. In addition to these parameters, the callback functions are passed the <code>nsModuleComponentInfo</code> struct, which is the same structure initially passed into <code>NS_IMPL_NSGETMODULE</code>.</p> - -<p>During registration, the registration callback is where you get the <code>nsICategoryManager</code>. Once you have it, you can add the component to the category of components that get started automatically. As a service, the <code>nsICategoryManager</code> is accessible via the <code>nsIServiceManager</code>. Also note that the <code>nsIComponentManager</code> is passed into the callback. Since the object that implements the <code>nsIComponentManager</code> interface also implements <code>nsIServiceManager</code>, all you have to do is <code>QueryInterface</code> the <code>nsIComponentManager</code> to <code>nsIServiceManager</code> to get the Service Manager. You can then use the Service Manager to add the component to the category:</p> - -<pre>nsresult rv; - -nsCOMPtr<nsIServiceManager> servman = - do_QueryInterface((nsISupports*)aCompMgr, &rv); - -if (NS_FAILED(rv)) - return rv; -</pre> - -<div class="side-note"> -<p><span id="%3Ccode%3Edo_QueryInterface%3C/code%3E"><a id="%3Ccode%3Edo_QueryInterface%3C/code%3E"></a><strong><code>do_QueryInterface</code></strong></span></p> - -<p>The previous code uses the special <code>nsCOMPtr</code> function <code>do_QueryInterface</code> that lets you <code>QueryInterface</code> without having to worry about reference counting, error handling, and other overhead. The <code>do_QueryInterface</code> knows what interface to <abbr title="QueryInterface">QI</abbr> to based on the <code>nsCOMPtr</code> that is being assigned into. We could have just as easily have used the raw <code>QueryInterface()</code> method, but using <code>nsCOMPtr</code> is much more economical (see <a href="cn/Creating_XPCOM_Components/Using_XPCOM_Utilities_to_Make_Things_Easier#Smart_Pointers">Smart Pointers</a>).</p> -</div> - -<p>Once you have a <code>nsIServiceManager</code> reference, you can ask it for the service you are interested in. This process is similar to using <code>CreateInstance</code> from the <code>nsIComponentManager</code>, but there is no aggregation parameter since the object has already been constructed.</p> - -<pre>nsCOMPtr<nsICategoryManager> catman; -rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID, - NS_GET_IID(nsICategoryManager), - getter_AddRefs(catman)); -if (NS_FAILED(rv)) - return rv; -</pre> - -<p>There are two service getters on the <code>nsIServiceManager</code> interface: one that takes a CID and another interface that takes a Contract ID. Here we'll use the latter. The first parameter to the <code>GetServiceByContractID</code> is of course the contract ID, which is defined in the <code>nsXPCOM.h</code> header file. The next parameter is a nifty macro that returns the IID for the interface name that you pass in. The last parameter assigns an out interface pointer to a <code>nsCOMPtr</code>. Assuming there weren't any unexpected errors, the variable <code>catman</code> holds the <code>nsICategoryManager</code> interface pointer, which you can use to add the component as a startup observer by calling a method on the <code>nsICategoryManager</code>.</p> - -<p>The next step is to figure out which parameters to pass to the method. There is a category name and a name-value pair, but since the name-value pair meaning is category-specific, you need to figure out which category to use.</p> - -<p>There are two startup notifications, both of which create the observer if it isn't already created. The first is provided by XPCOM. This notification will occur during initialization of XPCOM, where all XPCOM services are guaranteed to be available during the calls. Embedding applications may provide other notifications.</p> - -<p><span id="Common_XPCOM_Notifications"><a id="Common_XPCOM_Notifications"></a><strong>Common XPCOM Notifications</strong></span></p> - -<table class="standard-table"> - <tbody> - <tr> - <td class="header">Category</td> - <td class="header">Name</td> - <td class="header">Value</td> - <td class="header">Creates Component</td> - </tr> - <tr> - <td>xpcom-startup</td> - <td>Any</td> - <td>Contract ID</td> - <td>Yes</td> - </tr> - <tr> - <td>xpcom-shutdown</td> - <td>Any</td> - <td>Contract ID</td> - <td>No</td> - </tr> - <tr> - <td>xpcom-autoregistration</td> - <td>Any</td> - <td>Contract ID</td> - <td>No</td> - </tr> - <tr> - <td>app-startup</td> - <td>Any</td> - <td>service, Contract ID</td> - <td>*</td> - </tr> - </tbody> -</table> - -<p>The table above summarizes the popular persistent notifications registered through the category manager. The name of the category itself is a well defined string, but the name-value pairs can be anything.</p> - -<p>When naming your component in the category, take care to use something that means something and doesn't muddy up the namespace. In this case, "WebLock" is unique and provides context to anyone looking at the category. The value of the name-value part is expected to be the contract ID of the component.</p> - -<p>Since every category can define the name-value pairs, the application "app-startup" category can support not only services but component instances as well. For the app-startup notification, you must explicitly pass the string "service," prior to the component's Contract ID. If you do not, the component will be created and then released after the notification, which may cause the component to be deleted.</p> - -<p>In short, to register the <strong>WebLock</strong> component as an xpcom-startup observer, do the following:</p> - -<pre>char* previous = nsnull; -rv = catman->AddCategoryEntry("xpcom-startup", - "WebLock", - WebLock_ContractID, - PR_TRUE, // persist category - PR_TRUE, // replace existing - &previous); -if (previous) - nsMemory::Free(previous); // free the memory the replaced value might have used -</pre> - -<p>The unregistration, which should occur in the unregistration callback, looks like this:</p> - -<pre>rv = catman->DeleteCategoryEntry("xpcom-startup", - "WebLock", - PR_TRUE); // persist -</pre> - -<p>A complete code listing for registering <strong>WebLock</strong> as a startup observer follows:</p> - -<pre>#define MOZILLA_STRICT_API - -#include "nsIGenericFactory.h" - -#include "nsCOMPtr.h" -#include "nsXPCOM.h" -#include "nsIServiceManager.h" -#include "nsICategoryManager.h" - -#include "nsMemory.h" - -#include "nsIObserver.h" - -#include "nsEmbedString.h" - -#define WebLock_CID \ -{ 0x777f7150, 0x4a2b, 0x4301, \ -{ 0xad, 0x10, 0x5e, 0xab, 0x25, 0xb3, 0x22, 0xaa}} - -#define WebLock_ContractID "@dougt/weblock" - -class WebLock: public nsIObserver -{ - public: - WebLock(); - virtual ~WebLock(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER -}; - -WebLock::WebLock() -{ - NS_INIT_ISUPPORTS(); -} - -WebLock::~WebLock() -{ -} - -NS_IMPL_ISUPPORTS1(WebLock, nsIObserver); - -NS_IMETHODIMP -WebLock::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData) -{ - return NS_OK; -} - -static NS_METHOD WebLockRegistration(nsIComponentManager *aCompMgr, - nsIFile *aPath, - const char *registryLocation, - const char *componentType, - const nsModuleComponentInfo *info) -{ - nsresult rv; - - nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr<nsICategoryManager> catman; - rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID, - NS_GET_IID(nsICategoryManager), - getter_AddRefs(catman)); - - if (NS_FAILED(rv)) - return rv; - - char* previous = nsnull; - rv = catman->AddCategoryEntry("xpcom-startup", - "WebLock", - WebLock_ContractID, - PR_TRUE, - PR_TRUE, - &previous); - if (previous) - nsMemory::Free(previous); - - return rv; -} - -static NS_METHOD WebLockUnregistration(nsIComponentManager *aCompMgr, - nsIFile *aPath, - const char *registryLocation, - const nsModuleComponentInfo *info) -{ - nsresult rv; - - nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv); - if (NS_FAILED(rv)) - return rv; - - nsCOMPtr<nsICategoryManager> catman; - rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID, - NS_GET_IID(nsICategoryManager), - getter_AddRefs(catman)); - if (NS_FAILED(rv)) - return rv; - - rv = catman->DeleteCategoryEntry("xpcom-startup", - "WebLock", - PR_TRUE); - - return rv; -} - -NS_GENERIC_FACTORY_CONSTRUCTOR(WebLock) - -static const nsModuleComponentInfo components[] = -{ - { - "WebLock", - WebLock_CID, - WebLock_ContractID, - WebLockConstructor, - WebLockRegistration, - WebLockUnregistration - } -}; - -NS_IMPL_NSGETMODULE(WebLockModule, components) -</pre> - -<h3 id="Providing_Access_to_WebLock" name="Providing_Access_to_WebLock">Providing Access to <strong>WebLock</strong></h3> - -<p>At this point, the component will be called when XPCOM starts up. <strong>WebLock</strong> has already implemented the <code>nsISupports</code>, <code>nsIFactory</code>, <code>nsIModule</code>, and <code>nsIObserver</code> interfaces that handle generic component functionality including being initialized at startup. And it speaks to the Component Manager, Service Manager, Category Manager, and the Component Registrar to register itself properly with XPCOM.</p> - -<p>The next step is to expose additional functionality to Gecko applications and other clients to query and control the <strong>WebLock</strong> component. For example, the user interface needs to be able to enable and disable the web locking functionality, see what sites are in the whitelist, and add or remove sites from that list. WebLock needs to provide an API, and it needs to hook into Gecko in order to implement the actual locking functionality.</p> - -<p>译: 下一步是expose另外的功能以使得Gecko应用以及其它clients查询和控制WebLock组件. 例如, user interface(用户接口)要有能力去允许或者禁止web locking(web锁定)功能, 查看哪些站点在白名单列表中, 并向列表中添加或移除站点. WebLock需要提供一个API并挂接到Gecko中进而实现实际的locking功能.</p> - -<div class="side-note"> -<p><span id="The_WebLock_User_Interface"><a id="The_WebLock_User_Interface"></a><strong>The WebLock User Interface</strong></span></p> - -<p>The <strong>WebLock</strong> component in this tutorial uses XUL to define the additional browser UI in a cross-platform way, and XUL uses JavaScript to access and control XPCOM components, but Gecko's pluggable UI allows any user interface to call into Gecko and the components you create as easily as you can from XUL. See <a href="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#XUL">XUL</a> for a discussion of how XUL interacts with JavaScript and XPCOM.</p> - -<p>在这个教程中<strong>WebLock</strong>组件使用XUL来定义跨平台的浏览器UI, XUL使用JavaScript来访问和控制XPCOM组件, 但Gecko的可挂接UI也允许任何user interface调用Gecko和你所创建的组件, 就如同XUL一样容易. <a href="cn/Creating_XPCOM_Components/Building_the_WebLock_UI#XUL">XUL</a>讨论了XUL如何与JavaScript和XPCOM交互.</p> -</div> - -<h3 id="Creating_the_WebLock_Programming_Interface" name="Creating_the_WebLock_Programming_Interface">Creating the WebLock Programming Interface</h3> - -<p>Design is one of the hardest parts of any programming problem. The question the interface for the <strong>WebLock</strong> component must answer is: How should <strong>WebLock</strong> look to the outside world? What, in other words, is the interaction of clients with the <strong>WebLock</strong> component? In this section, we enumerate the basic functionality the component should expose and create the single interface that organizes and provides this functionality.</p> - -<p>译: 设计是任何编程问题中最困难的部分之一. 问题是<strong>WebLock</strong>组件必须要回答一些问题: <strong>WebLock</strong>应该如何look to外面的世界? 换言之, 什么是clients与<strong>WebLock</strong>的交互? 在这部分列举了组件应该expose的基本功能和create一个组织和提供这些功能的接口.</p> - -<p>Instead of starting with the implementation, developers use XPIDL (see <a href="cn/Creating_XPCOM_Components/An_Overview_of_XPCOM#XPIDL_and_Type_Libraries">XPIDL and Type Libraries</a> for more information about XPIDL) to define the interface to the component: how the functionality should be organized, expressed, and exposed to its clients.</p> - -<p>译: 开发人员应该使用XPIDL(see <a href="cn/Creating_XPCOM_Components/An_Overview_of_XPCOM#XPIDL_and_Type_Libraries">XPIDL and Type Libraries</a> for more information about XPIDL)为组件定义接口(定义功能应该如何被组织, 描述和暴露给它的clients)做为开始, 而不应该从实现开始.</p> - -<p>In general, the <strong>WebLock</strong> service interface needs to include the following functionality:</p> - -<p>译: 通常, <strong>WebLock</strong>服务接口要包括以下功能:</p> - -<ul> - <li><code>Lock</code> - Enable web locking so that any browser in the Gecko application is restricted to the white list of website domains.</li> -</ul> - -<p> 译: <code>Lock</code> - 允许web locking, 这样任何Gecko应用中的浏览器被限定只能访问白名单中的web站点域.</p> - -<ul> - <li><code>Unlock</code> - Disable web locking. This should allow any browser in the Gecko application to browse any website regardless of the white list.</li> -</ul> - -<p> 译: <code>Unlock</code> - 禁止web locking. 允许Gecko应该中的浏览器访问任何web站点, 而不去管白名单列表.</p> - -<ul> - <li><code>AddSite</code> - Add the current URL to the white list.</li> -</ul> - -<p> 译: <code>AddSite</code> - 添加当前URL到白名单列表.</p> - -<ul> - <li><code>RemoveSite</code> - Remove the current URL from the white list.</li> -</ul> - -<p> 译: <code>RemoveSite</code> - 从白名单列表中移除当前URL.</p> - -<ul> - <li><code>EnumerateSites</code> - Allows the enumeration of all sites in the white list. <code>EnumerateSites</code> might be used in the user interface to provide something like an editable listbox of all sites in the white list.</li> -</ul> - -<p> 译: <code>EnumerateSites</code> - 允许列举出所有白名单中的站点. <code>EnumerateSites</code>可能会被user interface(用户接口/用户界面)所提供的例如显示所有白名单列表的可编辑列表框控件所使用.</p> - -<p>Even this simple outline presents some ambiguity, however. It's certainly not enough to spell out the interface for the <strong>WebLock</strong> component in this way. For example, <code>AddSite</code> is supposed to add the current URL to the white list, but is the URL an input parameter to the method, is it the topmost web page in the Gecko application, or is it something more random-a URL picked from global history or that's been given context in some other way?</p> - -<p>As a strongly typed and implementation-agnostic language, XPIDL requires that you be quite specific about the APIs, the list of parameters, their order, and their types. XPIDL requires that you spell it all out, in other words. And it's this formality that makes the interfaces in XPCOM effective contracts between services and clients.</p> - -<p>The next section shows the interface of the <strong>WebLock</strong> component, <code>iWebLock</code>, in XPIDL. Once the interface has been described in the XPIDL language, the interface file can be used to generate the header files needed for the implementation code, the binary type library files that let you use the interface of the <strong>WebLock</strong> component from JavaScript, and even <span class="comment">broken link</span><a href="cn/Javadoc">javadoc</a> style HTML documentation.</p> - -<h3 id="Defining_the_Weblock_Interface_in_XPIDL" name="Defining_the_Weblock_Interface_in_XPIDL">Defining the <strong>Weblock</strong> Interface in XPIDL</h3> - -<p>Most interfaces in the XPCOM world are described in XPIDL. The XPIDL file for the <code>iWebLock</code> interface can be used to generate the C++ header file, which you'll need to implement the interface in the component and also a type library that makes the component accessible from JavaScript or other interpreted languages. In Mozilla, JavaScript is the bridge between components and the XUL-based user interface.</p> - -<p>译: 在XPCOM世界里大多数接口都是用XPIDL描述的. <code>iWebLock</code>接口的XPIDL文件可以被用来生成C++ header file(你需要它来在组件中实现接口和用来使组件在JavaScript和其它的解译型语言中可访问的类型库). 在Mozilla中, JavaScript是组件与基于XUL的user interface之间的桥梁.</p> - -<p>The XPIDL Syntax (XPIDL语法)</p> - -<p>The XPIDL syntax is a mix of C++ and Java, and of course it's very much like the OMG IDL upon which it is closely based. The XPIDL for <code>iWebLock</code> appears below:</p> - -<p><span id="iWebLock"><a id="iWebLock"></a><strong>iWebLock</strong></span></p> - -<pre>#include "nsISupports.idl" -interface nsISimpleEnumerator; -[scriptable, uuid(ea54eee4-9548-4b63-b94d-c519ffc91d09)] -interface iWeblock : nsISupports -{ - void lock(); - void unlock(); - - // assume strings are UTF-8 - void addSite(in string url); - void removeSite(in string url); - attribute nsISimpleEnumerator sites; -}; -</pre> - -<p>The first line includes the file <code>nsISupports.idl</code>, which defines the <code>nsISupports</code> interface from which all XPCOM interfaces must derive, and makes it possible for the <code>iWebLock</code> interface to subclass that base interface.</p> - -<pre>#include "nsISupports.idl" -</pre> - -<p>The next line of the XPIDL is a forward declaration of the interface <code>nsISimpleEnumerator</code>. Again, this is similar to the forward declare in C++ (except that C++ does not have the <code>interface</code> keyword seen here).</p> - -<pre>interface nsISimpleEnumerator; -</pre> - -<p>See the <a href="cn/Creating_XPCOM_Components/Resources#XPCOM_Resources">XPCOM resources</a> for more information about the XPIDL syntax.</p> - -<h4 id="Scriptable_Interfaces" name="Scriptable_Interfaces">Scriptable Interfaces</h4> - -<p>The third line in <a href="#iWebLock">iWebLock</a> is more complex. The first thing it says is that <code>iWebLock</code> will be<em>scriptable</em> .</p> - -<pre>[scriptable, uuid(ea54eee4-9548-4b63-b94d-c519ffc91d09)] -</pre> - -<p>The rest of the line provides a UUID for this interface. Recall that every interface has a unique number that is assigned to it. In the case of interfaces, the identifier is an IID. In the case of the components, which also require unique identifiers, the identifier is the CID.</p> - -<h4 id="Subclassing_nsISupports" name="Subclassing_nsISupports">Subclassing <code>nsISupports</code></h4> - -<p>The next line in <a href="#iWebLock">iWebLock</a> names the interface and defines its base interface. <code>iWeblock</code> derives from <code>nsISupports</code>. XPIDL has no way to define multiple inheritance - something that all scriptable objects must deal with.</p> - -<pre>interface iWebLock : nsISupports -</pre> - -<h4 id="The_Web_Locking_Interface" name="The_Web_Locking_Interface">The Web Locking Interface</h4> - -<p>The body of the block (the stuff between the curly braces) defines the methods and attributes of our interface. There are basically two functional sets on this interface. The first section of the interface controls whether or not <strong>WebLock</strong> checks to see if a web page can be loaded. If locked, <strong>WebLock</strong> will prevent sites not on the white list from loading.</p> - -<pre> void lock(); - void unlock(); -</pre> - -<p>This interface does not enforce any policy with respect to how the user enables or disables this feature. This allows maximum flexibility in the implementation. Any place in the application can acquire this interface via the Service Manager and call <code>unlock</code> or <code>lock</code>. For example, the user interface may bring up a dialog asking the user for a password before calling <code>unlock</code>. Another area of code, such as a "Profile Manager" that starts up and lets users choose which profile to use, may unconditionally call <code>unlock</code> on such a component when switching a profile.</p> - -<p>The next set of functionality manages the white list where acceptable domains are stored:</p> - -<pre> void addSite(in string url); - void removeSite(in string url); - attribute nsISimpleEnumerator sites; -</pre> - -<p>Operations in this set - <code>add</code>, <code>remove</code>, and <code>enumerate</code> - will be called from a user interface that manages the white list and adds the current website to the white list. There is no policy applied to what sites get added or removed to this list, or who can remove a site.</p> - -<p>The most interesting method definition is the enumerator. First of all, it does not look like a method at all:</p> - -<pre>attribute nsISimpleEnumerator sites; -</pre> - -<p>This line defines an attribute in the interface. In C++, this is considered a public variable and "compiled" into a <code>Get</code> method (e.g., <code>getSites</code>). If an attribute is not marked <code>readonly</code>, then both <code>Get</code> and <code>Set</code> methods are generated.</p> - -<p>The getter created by this attribute returns a <code>nsISimpleEnumerator</code> interface pointer. This interface allows you to pass a list of elements between interfaces. It has two methods: <code>hasMoreElements()</code> and <code>getNext()</code>.</p> - -<pre>[scriptable, uuid(D1899240-F9D2-11D2-BDD6-000064657374)] -interface nsISimpleEnumerator : nsISupports -{ - /** - * Called to determine whether or not the enumerator has - * any elements that can be returned via getNext(). This method - * is generally used to determine whether or not to initiate or - * continue iteration over the enumerator, though it can be - * called without subsequent getNext() calls. Does not affect - * internal state of enumerator. - * - * @see getNext() - * @return PR_TRUE if there are remaining elements in the enumerator. - * PR_FALSE if there are no more elements in the enumerator. - */ - boolean hasMoreElements(); - - /** - * Called to retrieve the next element in the enumerator. The "next" - * element is the first element upon the first call. Must be - * preceded by a call to hasMoreElements() which returns PR_TRUE. - * This method is generally called within a loop to iterate over - * the elements in the enumerator. - * - * @see hasMoreElements() - * @return NS_OK if the call succeeded in returning a non-null - * value through the out parameter. - * NS_ERROR_FAILURE if there are no more elements - * to enumerate. - * @return the next element in the enumeration. - */ - nsISupports getNext(); -}; -</pre> - -<h3 id="Implementing_WebLock" name="Implementing_WebLock">Implementing <strong>WebLock</strong></h3> - -<p>Once you have defined the interfaces that the component will implement, you can begin to write the implementation code that will actually carry out the web locking functionality.</p> - -<p>The <strong>WebLock</strong> component implements three interfaces:</p> - -<ul> - <li><code>nsISupports</code></li> - <li><code>nsIObserver</code></li> - <li><code>iWebLock</code></li> -</ul> - -<p><code>nsISupports</code> is the base interface that all XPCOM objects must implement. The <code>nsIObserver</code> interface is for listening to various events that Gecko generates. Finally, the <code>iWebLock</code> interface is the interface that actually controls the web locking functionality. The first two have already been implemented as part of the generic module code. Recall from <a href="cn/Creating_XPCOM_Components/Using_XPCOM_Utilities_to_Make_Things_Easier">Using XPCOM Utilities to Make Things Easier</a> that implementing these basic interfaces can be easy and straightforward if you use the macros and other utilities that XPCOM provides.</p> - -<h4 id="Declaration_Macros" name="Declaration_Macros">Declaration Macros</h4> - -<p>The class declaration for the <code>WebLock</code> class that implements these three interfaces is as follows:</p> - -<pre>class WebLock: public nsIObserver, public iWebLock -{ - public: - WebLock(); - virtual ~WebLock(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - NS_DECL_IWEBLOCK -}; -</pre> - -<p>Note that we derive from the <code>nsIObserver</code> interface as well as the <code>iWeblock</code> class. We do not need to explicitly derive from <code>nsISupports</code> as both of these two other interfaces are already subclasses of <code>nsISupports</code>:</p> - -<p><span id="Interface_Hierarchy_for_WebLock"><a id="Interface_Hierarchy_for_WebLock"></a><strong>Interface Hierarchy for WebLock</strong></span></p> - -<p><img alt="Image:weblock-interface-hierarchy.png"></p> - -<p>The body of the class declaration uses declaration macros that are generated from an XPIDL interface file. Every header generated from an XPIDL file has a similar macro that defines all the methods in that interface. This makes changes to the interface when designing a bit simpler, as you do not have to modify any class declarations.</p> - -<p>There are times, of course, when you cannot use these macros-as when two interfaces share the same method signatures. In these cases you have to manually declare the methods in your class. But in practice, manually declaring class methods in XPCOM is the exception and not the rule. The <code>NS_DECL_IWEBLOCK</code> declaration macro expands into the following:</p> - -<pre> NS_IMETHOD Lock(void); - NS_IMETHOD Unlock(void); - NS_IMETHOD AddSite(const char *url); - NS_IMETHOD RemoveSite(const char *url); - NS_IMETHOD GetSites(nsISimpleEnumerator * *aSites); - NS_IMETHOD SetSites(nsISimpleEnumerator *aSites); -</pre> - -<h4 id="Representing_Return_Values_in_XPCOM" name="Representing_Return_Values_in_XPCOM">Representing Return Values in XPCOM</h4> - -<p>The code sample above is the C++ version of the <code>iWebLock</code> interface methods. The return result of XPCOM methods generated from XPIDL is always of the type <code>nsresult</code>, and the small macro used in these expansions, <code>NS_IMETHOD</code>, actually represents that return type. <code>nsresult</code> is returned even when in XPIDL you specify that the method return a <code>void</code>. If you require the return result to be something else, the methods are not truly XPCOM methods. If you really want to change the return result type you can use a special flag in your XPIDL that denotes this (see <a class="external" href="http://www.mozilla.org/scriptable/xpidl/">the XPIDL reference</a>). However, we suggest that you simply add an out parameter to the method.</p> - -<h4 id="XPIDL_Code_Generation" name="XPIDL_Code_Generation">XPIDL Code Generation</h4> - -<p>The XPIDL compiler also generates a stub implementation of the interface in a commented section of the generated header file, in which each method returns <code>NS_ERROR_NOT_IMPLEMENTED</code>. If you copy the stub implementation from the header file into the source, then rename the dummy class name ("<code>_MYCLASS_</code>") to the <code>WebLock</code> class name already defined, you should be able to compile the source successfully.</p> - -<h4 id="Getting_the_WebLock_Service_from_a_Client" name="Getting_the_WebLock_Service_from_a_Client">Getting the WebLock Service from a Client</h4> - -<p>At this point, you can install the XPCOM component and have other systems use it. The component doesn't do anything useful, of course, but you have written enough of the code to have it recognized and accessed as a component in XPCOM. The code snippet below illustrates how to get the <strong>WebLock</strong> service when the component is present:</p> - -<pre>nsCOMPtr<nsIServiceManager> servMan; -nsresult rv = NS_GetServiceManager(getter_AddRefs(servMan)); -if (NS_FAILED(rv)) -{ - printf("ERROR: XPCOM error [%x].\n", rv); - return -1; -} -nsCOMPtr<iWebLock> weblock; -rv = servMan->GetServiceByContractID("@dougt/weblock", - NS_GET_IID(iWeblock), - getter_AddRefs(weblock)); - -if (NS_FAILED(rv)) -{ - printf("ERROR: XPCOM obtaining service [%x].\n", rv); - return -1; -} -</pre> - -<h4 id="Implementing_the_iWebLock_Interface_.28.E5.AE.9E.E7.8E.B0iWebLock.E6.8E.A5.E5.8F.A3.29" name="Implementing_the_iWebLock_Interface_.28.E5.AE.9E.E7.8E.B0iWebLock.E6.8E.A5.E5.8F.A3.29">Implementing the <code>iWebLock</code> Interface (实现iWebLock接口)</h4> - -<p>Once the interface is defined, you can focus on implementing the web lock startup functionality itself. The <strong>WebLock</strong> component starts automatically when XPCOM is started up because it's been registered as a category in XPCOM. When <strong>WebLock</strong> is called, one of the first things it wants to do is read in a file that lists the <abbr title="Uniform Resource Locator">URLs</abbr> that the browser is allowed to load. This file can exist anywhere on the local system, but we've placed it next to the application to keep things simple. The first step in this implementation phase, then, is to create the functionality that accesses this <strong>WebLock</strong> white list and uses its data to determine which domains are allowed and which are to be blocked. For this, we need to use the file interfaces available in XPCOM.</p> - -<p>一旦接口已被定义, 那你的重点应该放在实现web lock的功能上. 当XPCOM运行后WebLock组件也会被自动运行, 因为它已经被注册成为一个XPCOM中的category. 当WebLock被调用时, 它应该做的第一个事情就是读取一个文件, 这个文件列出了允许被浏览器加载的URLs. 这个文件可以位于本地系统中的任何位置, 但我们需要将其放置在距应用程序不远的地方以便操作起来简单一些. 接下来在实现阶段的第一步是实现两个功能, 一是访问WebLock的白名单, 二是使用这些数据去决定哪些域是被允许, 以及哪些是应该被拦截的. 为此, 我们需要使用XPCOM中的文件接口.</p> - -<h5 id="File_Interfaces" name="File_Interfaces">File Interfaces</h5> - -<p>Files and directories are abstracted and encapsulated by interfaces. There are a few reasons for not using strings to represent file locations, but the most important one is that not all file systems can be represented by a series of characters separated by a slash. On the Macintosh platform, for example, files are represented as a triplet - two numbers and one string - so using a string on the Macintosh does not adequately identify files on that operating system.</p> - -<p>文件和目录是通过接口来抽象和封装的. 这里有几个原因说明为什么不使用字符串来表示文件位置, 但更重要的一点是并不是所有的文件系统都能够表示成斜线所分割的字符序列. 例如, 在Macintosh(Apple的系统)平台上, 文件被表示成一个triplet(意思是由三个部分组成), 两个数字一个字符串, 因此在Macintosh系统上使用字符串并不能充分在标识文件.</p> - -<p><code>nsIFile</code>, the file interface in XPCOM, provides most of the functionally that file handling requires. That interface includes members representing the file name, file attributes, permissions, existence, and others. A related interface called <code>nsILocalFile</code> provides access to operations specific to local files, but the <code>nsIFile</code> functionality is adequate for the <strong>WebLock</strong> component.</p> - -<p>nsIFile, XPCOM中的文件接口, 提供了大多数操作文件所必须的功能. 这个接口中所包含的成员描述了文件的名字, 属性, 权限, 是否存在等等. 与之相关的接口nsILocalFile提供 操作特定的本地文件, 不过nsIFile的功能对于WebLock组件来说已经足够了.</p> - -<p><span id="File_Interface_Hierarchy"><a id="File_Interface_Hierarchy"></a><strong>File Interface Hierarchy</strong></span></p> - -<p><img alt="Image:file-iface-hierarchy.png"></p> - -<div class="side-note"> -<p><span id="Remote_Files_and_nsIFile"><a id="Remote_Files_and_nsIFile"></a><strong>Remote Files and nsIFile</strong></span></p> - -<p>It is not inconceivable for remote files to be represented by the <code>nsIFile</code> interface. Someone could write an <code>nsIFile</code> implementation that represented FTP files on some server. The existing code would need to change very little for a <strong>WebLock</strong> implementation to take advantage of files that do not actually exist on disk. This kind of implementation does not exist, but this expandability shows some of the flexibility that interface-based programming can provide.</p> - -<p>并不难想象, 为远程文件使用nsIFile接口来表示它. 某人可以写一个nsIFile的实现用以表示一些服务器上的FTP文件. 已经存在的代码必须要做一些效小的修改以使WebLock的实现可以接受实际上并不是存在于磁盘上的文件. 这种类型的实现虽然还并不存在, 但至少这种扩展性可以显现出一些基于接口的编程带来的灵活性.</p> - -<p>The <a href="cn/XPCOM_API_Reference">XPCOM API Reference</a> contains detailed information on <code>nsIFile</code> and other XPCOM interfaces.</p> -</div> - -<h4 id="The_Directory_Service_.28.E7.9B.AE.E5.BD.95.E6.9C.8D.E5.8A.A1.29" name="The_Directory_Service_.28.E7.9B.AE.E5.BD.95.E6.9C.8D.E5.8A.A1.29">The Directory Service (目录服务)</h4> - -<p>The file interfaces are most useful when you can use them to find and manipulate files that are relative to the application. The Directory Service provides directory and file locations in a cross platform uniform way to make this easier. This service, available as <code>nsIDirectoryService</code>, stores the location of various common system locations, such as the the directory containing the running process, the user's <code>HOME</code> directory, and others. It can be expanded so that applications and components can define and store their own special locations - an application plugin directory, for example, preference files and/or directories, or other application specific paths. For example, to expose the location of the "white list" file containing all of the URLs that are safe for <strong>WebLock</strong>, you can add its location to the <code>nsDirectoryService</code>, which clients can then query for this infomation.</p> - -<p>文件接口较有助于当你使用它们去查找和操作与应用相关的文件. 目录服务提供了跨平台的目录与文件定位的统一方法, 这使得进行这种操作变得容易. 这个服务(利用nsIDirectoryService)存储了各种各样通用系统区域的位置, 例如像是包括了正在运行的程序的目录, 用户的HOME目录等等. 因此它可以被扩展为应用程序和组件能够定义并且存储它们自己的特定位置(应用程序插件目录), 例如, 用户自定义的文件和目录, 或者其它的应用程序的特定路径. 比如指定一个"white list"所在的位置, 它包括了所有对于WebLock来讲是安全的URLs, 你可以将这个位置添加到nsDirectoryService中, 使客户端接下来可以查询到这个信息.</p> - -<p>The Directory Service implements the <code>nsIProperties</code> interface, which allows you to <code>Get()</code>, <code>Set()</code>, and <code>Undefine()</code> interface pointers. In the case of <strong>WebLock</strong>, these interface pointers will be <code>nsIFile</code> objects.</p> - -<p>目录服务实现了nsIProperties接口, 它允许你Get(), Set()以及Undefine()接口指针. 在WebLock中这些接口指针是nsIFile对象.</p> - -<pre>[scriptable, uuid(78650582-4e93-4b60-8e85-26ebd3eb14ca)] -interface nsIProperties : nsISupports -{ - /** - * Gets a property with a given name. - * 用给定的名字(name)取得一个属性(property) - * - * @return NS_ERROR_FAILURE if a property with that - * name doesn't exist. - * 如果给定名字的属性不存在, 函数返回NS_ERROR_FAILURE - * @return NS_ERROR_NO_INTERFACE if the - * found property fails to QI to the - * given iid. - * 如果取得的属性在以给定的iid于QI方法上调用失败, - * 函数返回NS_ERROR_NO_INTERFACE - */ - void get(in string prop, - in nsIIDRef iid, - [iid_is(iid),retval] out nsQIResult result); - - /** - * Sets a property with a given name to a given value. - * 用给定的名字和给定的值为设置一个属性 - */ - void set(in string prop, in nsISupports value); - - /** - * Returns true if the property with the given name exists. - * 如果与给定名字的属性存在, 返回true - */ - boolean has(in string prop); - - /** - * Undefines a property. 取消一个属性的定义 - * @return NS_ERROR_FAILURE if a property with that name doesn't - * already exist. - * 如果给定名字的属性还不存在, 那么函数返回NS_ERROR_FAILURE - */ - void undefine(in string prop); - - /** - * Returns an array of the keys. - * 返回一个key的集合 - */ - void getKeys(out PRUint32 count, - [array, size_is(count), retval] out string keys); -}; -</pre> - -<p><span id="Directory_Service_Hierarchy"><a id="Directory_Service_Hierarchy"></a><strong>Directory Service Hierarchy</strong></span></p> - -<p><img alt="Image:directoryservice-iface-hierarchy.png"></p> - -<p>There are two steps involved to find directories or files with the Directory Service (<code>nsIDirectoryService</code>). You must know the string key (or property) that refers to the location you are interested in, which is published in the file <code>nsDirectoryServiceDefs.h</code> that comes with the Gecko SDK (for a listing of these locations, see the <a href="cn/XPCOM_API_Reference">XPCOM API Reference</a>). The string key for the directory containing the application executable is <code>NS_XPCOM_CURRENT_PROCESS_DIR</code>. Given this key, you can acquire the directory service, call <code>Get()</code>, and pass the key. In the example below, <code>appDir</code> will point to the directory that contains the executable.</p> - -<p>这里有两个步骤有关于通过目录服务(nsIDirectoryService)查找目录或文件. 你必须要知道字符串键(或叫属性)用以引用你所想要的位置, 字符串键(或叫属性)被公开于随Gecko SDK一起提供的nsDirectoryServiceDefs.h文件中(可参见<a href="cn/XPCOM_API_Reference">XPCOM API Reference</a>以得到这些位置的一个列表). 包含可执行程序的目录的字符串键是NS_XPCOM_CURRENT_PROCESS_DIR. 给定这个键, 你就可以通过调用Get()并将键传递到函数中以获得目录服务. 在下面的实例中, appDir将指向一个包含了可执行程序的目录.</p> - -<pre>nsCOMPtr<nsIServiceManager> servMan; -nsresult rv = NS_GetServiceManager(getter_AddRefs(servMan)); -if (NS_FAILED(rv)) return -1; - -nsCOMPtr<nsIProperties> directoryService; -rv = servMan->GetServiceByContractID(NS_DIRECTORY_SERVICE_CONTRACTID, - NS_GET_IID(nsIProperties), - getter_AddRefs(directoryService)); - -if (NS_FAILED(rv)) return -1; - -nsCOMPtr<nsIFile> appDir; -rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, - NS_GET_IID(nsIFile), - getter_AddRefs(appDir)); - -if (NS_FAILED(rv)) return -1; -</pre> - -<p>Most of the useful functionality is exposed by the <code>nsIProperties</code> interface, but the directory service also implements <code>nsIDirectoryService</code>. This interface allows you to extend and override <code>nsIFile</code> objects registered with the directory service. There are currently two ways to add a file location to the directory service: directly and using the delayed method. The direct method is to add a new <code>nsIFile</code> object using the <code>nsIProperties</code> interface, in which case you pass the <code>nsIFile</code> object as an <code>nsISupports</code> to the <code>Set()</code> method of the <code>nsIProperties</code> interface.</p> - -<p>大多数有用的功能都是通过nsIProperties接口所提供, 但目录服务还实现了nsIDirectoryService. nsIDirectoryService接口允许利用目录服务你去扩展和重写nsIFile对象的注册. 当前有两种方法添加一个文件位置到目录服务中:立即的与延迟的两种方法. 立即的方法是使用nsIProperties接口添加一个新的nsIFile对象, 在这种情况下你要把nsIFile对象当成一个nsISupports传递给nsIProperties接口的Set()函数.</p> - -<p>In the delayed method, you register to be a callback that can provide an <code>nsIFile</code>. To do this, you must get the implementation like we did above. When you have it, <code>QueryInterface</code> for the <code>nsIDirectoryService</code> interface. In this interface, there is a function which allows you to register an <code>nsIDirectoryServiceProvider</code> interface. The interface callback looks like this:</p> - -<pre>[scriptable, uuid(bbf8cab0-d43a-11d3-8cc2-00609792278c)] -interface nsIDirectoryServiceProvider: nsISupports -{ -/** -* getFile -* -* Directory Service calls this when it gets the first request for -* a prop or on every request if the prop is not persistent. -* -* @param prop The symbolic name of the file. -* @param persistent TRUE - The returned file will be cached by Directory -* Service. Subsequent requests for this prop will -* bypass the provider and use the cache. -* FALSE - The provider will be asked for this prop -* each time it is requested. -* -* @return The file represented by the property. -* -*/ -nsIFile getFile(in string prop, out PRBool persistent); -}; -</pre> - -<h4 id="Modifying_Paths_with_nsIFile" name="Modifying_Paths_with_nsIFile">Modifying Paths with <code>nsIFile</code></h4> - -<p>The directory service returns an <code>nsIFile</code> object, but that object points to the application directory and not the file itself. To modify this <code>nsIFile</code> so that it points to the file, you must call the <code>Append</code> method of the <code>nsIFile</code>. <code>Append</code> adds the input string to the path already specified in the <code>nsIFile</code>. On Unix, for example, calling <code>Append("b")</code> on an <code>nsIFile</code> modifies that <code>nsIFile</code> representing <code>/u/home/dougt/a</code> to point to <code>/u/home/dougt/a/b</code>. The next operation on the <code>nsIFile</code> returns results associated with the "b" path. If "a" wasn't a directory, further operations would fail, even if the initial <code>Append</code> was successful. This is why <code>Append</code> is considered a string operation.</p> - -<p>目录服务返回一个nsIFile对象, 但nsIFile对象指向的是应用程序目录而并不是文件. 因此为了修改nsIFile对象以指向文件你必须要调用nsIFile的Append函数. Append函数将字符串输入参数追加到已经被指定到nsIFile的路径里. 例如在Unix里, 在一个nsIFile上调用Append("b")将使nsIFile从指向/u/home/dougt/a修改为指向/u/home/dougt/a/b. 在nsIFile上的后续操作返回的结果将是关于"b"这个路径的. 如果"a"不是一个目录, 那么进一步的操作将会失败, 尽管对于Append函数的调用是成功的. 这就是为什么Append函数被认为是对字符串的操作(不进行目录路径的有效性验证).</p> - -<p>The <strong>WebLock</strong> component manipulates a file named <code>weblock.txt</code>. The following snippet adjusts the <code>theFile</code> object representing that file:</p> - -<p>WebLock组件操作名为weblock.txt的文件, 以下程序片段调整了theFile对象以表示那个文件:</p> - -<pre>nsEmbedCString fileName("weblock.txt"); -appDir->AppendNative(fileName); -</pre> - -<h4 id="Manipulating_Files_with_nsIFile" name="Manipulating_Files_with_nsIFile">Manipulating Files with <code>nsIFile</code></h4> - -<p>Once you have an <code>nsIFile</code> object pointing to the file that you're interested in, you can open it and read its contents into memory. There are many ways to do this: You can use Standard ANSI File I/O, or NSPR (see <a href="#The_Netscape_Portable_Runtime_Library">The Netscape Portable Runtime Library</a> below for a brief description of NSPR), or you can use the networking APIs that Gecko provides.</p> - -<div class="side-note"> -<p><span id="The_Netscape_Portable_Runtime_Library"><a id="The_Netscape_Portable_Runtime_Library"></a><strong>The Netscape Portable Runtime Library</strong></span></p> - -<p>The<em>Netscape Portable Runtime Library</em> (NSPR) is a platform-independent library that sits below XPCOM. As a layer of abstraction above the operating system, the NSPR allows Gecko applications to be platform independent by providing the following system-level facilities:</p> - -<ul> - <li>Threads</li> - <li>Thread synchronization</li> - <li>File and network I/O</li> - <li>Timing and intervals</li> - <li>Memory management</li> - <li>Shared library linking</li> -</ul> - -<p>The NSPR is included in the Gecko SDK.</p> -</div> - -<p>To keep things as simple as possible, we'll read the file into memory using standard ANSI file I/O, but for examples and information about how to use<em>necko</em> , the Gecko networking libraries, see <a class="external" href="http://www.mozilla.org/projects/netlib/" rel="freelink">http://www.mozilla.org/projects/netlib/</a>.</p> - -<h4 id="Using_nsILocalFile_for_Reading_Data" name="Using_nsILocalFile_for_Reading_Data">Using <code>nsILocalFile</code> for Reading Data</h4> - -<p>An <code>nsIFile</code> object returned from the directory service may also implement the <code>nsILocalFile</code> interface, which has a method that will return a <code>FILE</code> pointer that can be used in <code>fread()</code>. To implement the actual read, you need to allocate a buffer the length of the file, use the <code>nsILocalFile</code> interface pointer to obtain a <code>FILE *</code>, use this result with <code>fread</code>, and close the file pointer.</p> - -<p>The following code loads the contents of the file referenced by the <code>nsIFile</code> object <code>theFile</code> into the buffer <code>buf</code>:</p> - -<pre>nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(theFile); -if (!localFile) - return -1; - -PRBool exists; -rv = theFile->Exists(&exists); -if (NS_FAILED(rv)) - return -1; - -char *buf = NULL; - -if (exists) -{ - // determine file size: - PRUint32 fs, numread; - PRInt64 fileSize; - rv = theFile->GetFileSize(&fileSize); - if (NS_FAILED(rv)) - return -1; - - // Converting 64 bit value to unsigned int - LL_L2UI(fs, fileSize); - - FILE* openFile; - rv = localFile->OpenANSIFileDesc("rw", &openFile); - if (NS_FAILED(rv)) - return -1; - - char *buf = (char *)malloc((fs+1) * sizeof(char)); - if (!buf) - return -1; - - numread = fread(buf, sizeof(char), fs, openFile); - - if (numread != fs) - // do something useful. - - // ... -} - -if (buf) - free(buf); -</pre> - -<p>The first line of the code calls <code>QueryInterface</code> on <code>theFile</code>, and if that succeeds assigns the new interface pointer to <code>localFile</code>. If the <code>QueryInterface</code> call fails, <code>localFile</code> will have a value of <code>NULL</code>.</p> - -<div class="side-note"> -<p>Note that the out parameter of the method <code>GetFileSize</code> is a 64-bit integer. The type of this variable is <code>PRInt64</code>, but this type is not represented as a primitive on all platforms. On some platforms, <code>PRInt64</code> is a <code>struct</code> with two fields - a high and a low 32-bit integer. So operations on this type must use special macros that do the right thing on each platform. On Windows or Linux, for example, it is possible to multiply a <code>PRInt64</code> by a long like this:</p> - -<pre>PRInt64 x = 1, y = 2; -y = x * 2; -</pre> - -<p>However, this same snippet will not compile on a platform like Macintosh OS 9, where you need to use macros to perform the calculation:</p> - -<pre>PRInt64 x, y, two; -LL_I2L(x, 1); -LL_I2L(y, 2); -LL_I2L(two, 2); -LL_MUL(y, x, two); -</pre> - -<p>A full listing of NSPR's <code>long long</code> support can be found at <a class="external" href="http://www.mozilla.org/projects/nspr/" rel="freelink">http://www.mozilla.org/projects/nspr/</a>.</p> - -<p>The <strong>WebLock</strong> component doesn't have to deal with files that are longer than 2<sup>32</sup> bytes. Truncating this value to whatever can fit into a 32-bit unsigned integer may not work for every application, but in this case it doesn't really matter.</p> -</div> - -<h4 id="Processing_the_White_List_Data" name="Processing_the_White_List_Data">Processing the White List Data</h4> - -<p>There are various ways to process the file data itself. The file <code>weblock.txt</code> consists of URL tokens separated by return characters, which makes them easy to read into a data structure.</p> - -<p>The white list file can be read in as soon as the component starts up (i.e., as <strong>WebLock</strong> intercepts the startup notification in the <code>Observe</code> method of the <code>nsIObserver</code> interface that we implement). Since we have only registered to receive a notification when XPCOM starts up, it's a safe assumption that <code>Observe</code> will only be called during the startup event, so we can read the file data in the callback.</p> - -<p>After you've read the data into memory, you need to store it in some way to make data access quick and efficient.</p> - -<div class="side-note"> -<p><span id="URL_Checking"><a id="URL_Checking"></a><strong>URL Checking</strong></span></p> - -<p>The way in which URL checking is implemented in the <strong>WebLock</strong> component is not at all optimal. The <strong>WebLock</strong> component manages a simple linked list of URL strings. A linear search through the data in the white list may not be terribly bad if the number of URLs is under a couple of dozen, but it decays as the list grows. There's also a large bottleneck in the network request. URL data is accessed as in the diagram below:</p> - -<p><img alt="Image:urldata-access-in-weblock.png"></p> - -<p>You might construct hash values for each of the URL strings instead, or add them to some kind of database. But we leave optimizations and real-world performance for web locking to the reader.</p> -</div> - -<h3 id="iWebLock_Method_by_Method" name="iWebLock_Method_by_Method"><code>iWebLock</code> Method by Method</h3> - -<p>The implementation of the <code>iWeblock</code> interface is straightforward. <strong>WebLock</strong> is designed so that the user interface notifies this service when we should go into lock mode. During this time, any new URL request that is not in our list of "good" URLs will be denied. Through scriptable access to the <code>iWebLock</code> interface, the user interface can also add, remove, and enumerate the list of URLs that it knows about.</p> - -<h4 id="Lock_and_Unlock" name="Lock_and_Unlock"><code>Lock</code> and <code>Unlock</code></h4> - -<p>The <code>lock</code> and <code>unlock</code> methods simply set a Boolean representing state in the object. This Boolean value will be used later to determine if we should be denying URL requests:</p> - -<pre>/* void lock (); */ -NS_IMETHODIMP -WebLock::Lock() -{ - mLocked = PR_TRUE; - return NS_OK; -} - -/* void unlock (); */ -NS_IMETHODIMP WebLock::Unlock() -{ - mLocked = PR_FALSE; - return NS_OK; -} -</pre> - -<h4 id="AddSite" name="AddSite"><code>AddSite</code></h4> - -<p>For <code>AddSite</code>, we add a new node to our linked list. The link list nodes contain a <code>char*</code> which points to the string URL that we care about and, of course, a pointer to the next element in the list.</p> - -<div class="side-note"> -<p><span id="%3Ccode%3EnsMemory%3C/code%3E_for_Cross-component_Boundaries"><a id="%3Ccode%3EnsMemory%3C/code%3E_for_Cross-component_Boundaries"></a><strong><code>nsMemory</code> for Cross-component Boundaries</strong></span></p> - -<p>WebLock maintains ownership of all the memory it allocates, so you can use just about any allocator that you want for <strong>WebLock</strong>, but this is not always the case. In other places, where allocated buffers cross interface boundaries, you must ensure that the correct allocator is used - namely <code>nsMemory</code> - so that the allocators can match the allocation with the deallocation.</p> - -<p>Suppose you call <code>malloc</code> from object A and pass this buffer to another object B, for example. But if object B is using a special allocator that does garbage collection, then when object B deletes a buffer allocated by object A's allocator, the results are unpredictable: probably an assertion will be raised, possibly a memory leak, or a crash. The <code>nsMemory</code> class is a wrapper around the <code>nsIMemory</code> interface, whose only implementation is part of XPCOM. When you use <code>nsMemory</code>, you are guaranteed to be using this same memory allocator in all cases, and this avoids the problem described here.</p> -</div> - -<h4 id="RemoveSite" name="RemoveSite"><code>RemoveSite</code></h4> - -<p><code>RemoveSite</code> deletes a node from the linked list:</p> - -<pre>// a simple link list. -struct urlNode -{ - char* urlString; - struct urlNode* next; -}; - -/* void addSite (in string url); */ -NS_IMETHODIMP -WebLock::AddSite(const char *url) -{ - // we don't special-case duplicates here - urlNode* node = (urlNode*) malloc(sizeof(urlNode)); - node->urlString = strdup(url); - node->next = mRootURLNode; - mRootURLNode = node; - - return NS_OK; -} - -/* void removeSite (in string url); */ -NS_IMETHODIMP -WebLock::RemoveSite(const char *url) -{ - // find our entry. - urlNode* node = mRootURLNode; - urlNode* prev = nsnull; - - while (node) // test this! - { - if (strcmp(node->urlString, url) == 0) - { - free(node->urlString); - if (prev) - prev->next = node->next; - free(node); - return NS_OK; - } - prev = node; - node = node->next; - } - - return NS_ERROR_FAILURE; -} -</pre> - -<h4 id="SetSites" name="SetSites"><code>SetSites</code></h4> - -<p>The purpose of <code>SetSites</code> is to allow clients to pass an enumeration, or set, of URL strings to add to the white list of URLs. <code>SetSites</code> uses an <code>nsISimpleEnumerator</code> and shows how primitive data can be passed as an <code>nsISupports</code> object. The <code>nsISimpleEnumerator</code> interface is shown in <a href="#The_Web_Locking_Interface">The Web Locking Interface</a>.</p> - -<p>The first method returns a Boolean if there are more elements in the set. Internally, the object knows the number of elements it has in its enumeration, and every time a client calls <code>getNext</code>, it decrements a counter - or adjusts a pointer to the next element. When the counter goes to zero or the pointer points to a non-element, <code>hasMoreElements</code> will return false.</p> - -<p>There is no way to reset an <code>nsISimpleEnumerator</code>. For example, you can't re-enumerate the set. If you need random access to the elements in a <code>nsISimpleEnumerator</code>, you can read them from the <code>nsISimpleEnumerator</code>, store them in an array, and access them there. The <code>getNext</code> method returns a <code>nsISupports</code> interface pointer.</p> - -<p>When you want to pass primitive data types like numbers, strings, characters, <code>void *</code>, and others, the solution is to use one of the <code>nsISupportsPrimitive</code> interfaces. These interfaces wrap primitive data types and derive from <code>nsISupports</code>. This allows types like the strings that represent URLs in the <strong>WebLock</strong> component to be passed though methods that take an <code>nsISupports</code> interface pointer. This becomes clear when when you see the implementation of <code>SetSites</code>:</p> - -<pre>NS_IMETHODIMP -WebLock::SetSites(nsISimpleEnumerator * aSites) -{ - PRBool more = PR_TRUE; - while (more) - { - nsCOMPtr<nsISupports> supports; - aSites->GetNext(getter_AddRefs(supports)); - - nsCOMPtr<nsISupportsCString> supportsString = do_QueryInterface(supports); - - if (supportsString) - { - nsEmbedCString url; - supportsString->GetData(url); - AddSite(url.get()); - } - - aSites->HasMoreElements(&more); - } - - return NS_OK; -} -</pre> - -<h4 id="GetNext" name="GetNext"><code>GetNext</code></h4> - -<p><code>GetNext</code> is called with the <code>nsCOMPtr</code> of an <code>nsISupportsCString</code>. <code>nsCOMPtr</code>s are nice because they do whatever <code>QueryInterface</code> calls are necessary under the hood. For example, we know that the <code>GetNext</code> method takes an <code>nsISupports</code> object, but we may not be sure whether the return result supports the interface we want, <code>nsISupportsCString</code>. But after <code>GetNext</code> returns, the <code>nsCOMPtr</code> code takes the out parameter from <code>GetNext</code> and tries to <code>QueryInterface</code> it to the <code>nsCOMPtr</code>'s type. In this case, if the out parameter of <code>GetData</code> does not return something that is <code>QueryInterface</code>-able to an <code>nsISupportsCString</code>, the variable will be set to <code>null</code>. Once you know that you have an <code>nsISupportsCString</code>, you can grab the data from the primitive supports interface.</p> - -<p>To get something you can pass into the <code>AddSite</code> method, you need to convert from an <code>nsEmbedCString</code> to a <code>const char*</code>. To do this, you can take advantage of the <code>nsEmbedCString</code> described in <a href="cn/Creating_XPCOM_Components/Using_XPCOM_Utilities_to_Make_Things_Easier#String_Classes_in_XPCOM">String Classes in XPCOM</a>.</p> - -<h4 id="GetSites" name="GetSites"><code>GetSites</code></h4> - -<p>The implementation of <code>GetSites</code> is more involved. You must construct an implementation of <code>nsISimpleEnumerator</code> and return it when <code>GetSites</code> is called. The class needs to walk the list of <code>urlNode</code>'s for every call to <code>GetNext</code>, so it makes sense for the constructor itself to take an <code>urlNode</code>:</p> - -<pre>class myEnumerator : public nsISimpleEnumerator -{ - public: - NS_DECL_ISUPPORTS - NS_DECL_NSISIMPLEENUMERATOR - - myEnumerator(urlNode* node) { - NS_INIT_ISUPPORTS() - mNode = node; - } - virtual ~myEnumerator(void) {} - - protected: - urlNode* mNode; - nsCOMPtr<nsIComponentManager> mCompMgr; -}; - -NS_IMPL_ISUPPORTS1(myEnumerator, nsISimpleEnumerator); -</pre> - -<p>The <code>myEnumerator</code> class is going to implement the <code>nsISupports</code> interface and also <code>nsISimpleEnumerator</code>. The only state that it needs to maintain is the current URL node - the one that will be return on the next call to <code>GetNext</code>. There is also an <code>nsCOMPtr</code> to the <code>nsIComponentManager</code>, which is used in every call to <code>GetNext</code> so that you can create <code>nsISupportsCString</code> objects and cache the interface pointer as an optimization.</p> - -<h4 id="HasMoreElements" name="HasMoreElements"><code>HasMoreElements</code></h4> - -<p><code>HasMoreElements</code> is simple. All you need to do is make sure that <code>mNode</code> isn't <code>null</code>:</p> - -<pre>NS_IMETHODIMP -myEnumerator::HasMoreElements(PRBool* aResult) -{ - if (!aResult) - return NS_ERROR_NULL_POINTER; - - if (!mNode) { - *aResult = PR_FALSE; - return NS_OK; - } - - *aResult = PR_TRUE; - return NS_OK; -} -</pre> - -<p><code>GetNext</code> needs to create an <code>nsISupportsCString</code> so that you can pass the URL string out through the <code>nsISupports</code> parameter. You must also move <code>mNode</code> to point to the next <code>urlNode</code>.</p> - -<pre>static NS_DEFINE_CID(kSupportsCStringCID, NS_SUPPORTS_CSTRING_CID); - -NS_IMETHODIMP -myEnumerator::GetNext(nsISupports** aResult) -{ - if (!aResult) - return NS_ERROR_NULL_POINTER; - - *aResult = nsnull; - - if (!mNode) - return NS_ERROR_FAILURE; - - if (!mCompMgr) - { - NS_GetComponentManager(getter_AddRefs(mCompMgr)); - if (!mCompMgr) - return NS_ERROR_UNEXPECTED; - } - - nsISupportsCString* stringSupports; - mCompMgr->CreateInstance(kSupportsCStringCID, - nsnull, - NS_GET_IID(nsISupportsCString), - (void**)&stringSupports); - if (!stringSupports) - return NS_ERROR_UNEXPECTED; - - nsEmbedCString str(mNode->urlString); - stringSupports->SetData(str); - - *aResult = stringSupports; // addref'ed above. - - mNode = mNode->next; - - return NS_OK; -} -</pre> - -<p>在实际的<code>GetSites</code>呼叫中, 你需要做的就是产生一个<code>myEnumerator</code>实例并且返回它.</p> - -<p>此前,我们建立了一个类并且把它注册到组件管理器。当一个客户端需要获取某个接口的实现时,实际上的对象建立过程隐藏在XPCOM代码中。 但是其中, 你要初始化你自己的<code>nsISimpleEnumerator</code>实现. 这是一个简单的事情,但是你需要注意<code>NS_ADDREF</code>.</p> - -<pre>NS_IMETHODIMP -WebLock::GetSites(nsISimpleEnumerator * *aSites) -{ - myEnumerator* enumerator = new myEnumerator(mRootURLNode); - if (!enumerator) - return NS_ERROR_OUT_OF_MEMORY; - - NS_ADDREF(*aSites = enumerator); - return NS_OK; -} -</pre> - -<div class="side-note"> -<p><span id="AddRef,_Releasing,_and_Deleting_Objects"><a id="AddRef,_Releasing,_and_Deleting_Objects"></a><strong>AddRef, Releasing, and Deleting Objects</strong></span></p> - -<p>永远不要忘记调用你通过<code>new</code>建立的XPCOM对象的<code>AddRef</code>方法。所有的代码或者活动组件都应该有一个起码一个引用计数。忘记这点可能引起麻烦。</p> - -<p>一个相关的警示试你不要忘记永远不要用<code>delete</code>删除一个XPCOM. 当系统的一部分不是释放而是删除一个XPCOM对象的时候,可能会引起几个小时的资源搜索并且引起崩溃。</p> -</div> - -<p>注意上面的实现中,当其他的线程访问链接表的时候<code>myEnumerator</code> 可能变得非法。枚举仅仅表现了访问URL字符串链接表的一个方法。如果你需要枚举成为URL字符串链表的一个快照,你需要重构这个实现让枚举持有一个链表的copy。</p> - -<p>当组件中止的时候,你也需要把链表写到磁盘里并且释放空间。我们把这个作为练习留给读者。</p> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Using_XPCOM_Utilities_to_Make_Things_Easier" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Finishing_the_Component">下一页 »</a></p> -</div> <p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/using_xpcom_components/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/using_xpcom_components/index.html deleted file mode 100644 index a0a5b301ba..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/using_xpcom_components/index.html +++ /dev/null @@ -1,311 +0,0 @@ ---- -title: 创建_XPCOM_组件/使用_XPCOM_组件 -slug: Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Components -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Components ---- -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/创建_XPCOM_组件:XPCOM_简介" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Component_Internals">下一页 »</a></p> -</div><p></p> - -<p>创建一个新的 XPCOM 组件, 特别是在我们设计一个供别人使用的组件接口的时候, 最好方式是参照已有的组件. 我们在编写 <a href="cn/Creating_XPCOM_Components/Starting_WebLock">Starting WebLock</a> 这个例子的时候, 也是这么做的.</p> - -<p>Mozilla 浏览器应用是复杂的, 模块化的 XPCOM 客户程序. 实际上, 基本上所有与浏览器相关的功能都被定义成了组件的形式, 包括网页间的跳转, 窗口管理, cookie 管理, 书签, 安全, 搜索, 润色等等的其他功能, 这些功能都是由组件的接口提供的. Mozilla<em>就是</em>一堆 XPCOM 组件.</p> - -<p>本章将讨论 Mozilla 是如何使用象 CookieManager 这样的 XPCOM 对象, 然后根据这些例子我们定义 WebLock 组件的访问接口.</p> - -<h3 id=".E7.BB.84.E4.BB.B6.E7.9A.84.E4.BE.8B.E5.AD.90" name=".E7.BB.84.E4.BB.B6.E7.9A.84.E4.BE.8B.E5.AD.90">组件的例子</h3> - -<p>可以在这里 <a href="cn/XPCOM_API_Reference">XPCOM API Reference</a> 找到下面要描述的组件. 我们要了解的是象本节中所给出的组件是如何被 Mozilla 浏览器获取和使用的.</p> - -<h4 id="Cookie_.E7.AE.A1.E7.90.86.E5.99.A8" name="Cookie_.E7.AE.A1.E7.90.86.E5.99.A8">Cookie 管理器</h4> - -<p>Cookie 管理是以组件形式向 Mozilla 浏览器提供支持的众多组件之一, 这些组件可以被重用在需要类似功能的应用中. 当用户通过 Cookie 管理器对话框来观察, 组织, 或者删除 cookies 的时候, Cookie 管理器在背后默默的工作. <a href="#Cookie_管理器对话框">Cookie 管理器对话框</a>负责向用户提供 Cookie 管理器的 UI 界面<sup><a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Components#endnote_cookie-manager-ui">[cookie-manager-ui]</a></sup>.</p> - -<p><span id="Cookie_%E7%AE%A1%E7%90%86%E5%99%A8%E5%AF%B9%E8%AF%9D%E6%A1%86"><a id="Cookie_%E7%AE%A1%E7%90%86%E5%99%A8%E5%AF%B9%E8%AF%9D%E6%A1%86"></a><strong>Cookie 管理器对话框</strong></span></p> - -<p><img alt="Image:cookie_mgr_dlog.png"></p> - -<p>对话框是用 XUL (XML UI 语言) 和 JavaScript 语言编写, 使用称为<em>XPConnect</em> 的组件无缝连接到 Cookie 管理器组件(参看下面的 <a href="#从接口连接到组件">从接口连接到组件</a>). XUL 只是一种暴露 Cookie 管理器功能的方式, 但是却是 Mozilla 环境下最有用的方式之一.</p> - -<p>CookieManager 组件的功能通过 <code>nsICookieManager</code> 接口提供, 接口的方法如下:</p> - -<p><span id="%3Ccode%3EnsICookieManager%3C/code%3E_%E6%8E%A5%E5%8F%A3"><a id="%3Ccode%3EnsICookieManager%3C/code%3E_%E6%8E%A5%E5%8F%A3"></a><strong><code>nsICookieManager</code> 接口</strong></span></p> - -<table class="standard-table"> - <tbody> - <tr> - <td><code>removeAll</code></td> - <td>删除 cookie 列表中所有的 cookies.</td> - </tr> - <tr> - <td><code>enumerator</code></td> - <td>通过 cookie 列表枚举.</td> - </tr> - <tr> - <td><code>remove</code></td> - <td>从列表中删除某个 cookie .</td> - </tr> - </tbody> -</table> - -<p>XPCOM 中所有的接口必须固定, 虽然组件对接口的实现会有所变化. 接口都是<em>public</em> 的, 相对的, 接口实现是 private 的<sup><a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Components#endnote_private-xpcom-interfaces">[private-xpcom-interfaces]</a></sup>. 当用户选中 cookie 列表中的一个 cookie, 点击 Remove 按钮, <code>nsICookieManager</code> 接口的 <code>Remove</code> 方法被调用. CookieManager 组件执行该函数, 选中的组件就被删除了.</p> - -<p>下面的<a href="#从_JavaScript_中访问_CookieManager_组件">从 JavaScript 中访问 CookieManager 组件</a>代码, 展示了如何从 JavaScript 中调用 <code>Remove()</code> 方法:</p> - -<p><span id="%E4%BB%8E_JavaScript_%E4%B8%AD%E8%AE%BF%E9%97%AE_CookieManager_%E7%BB%84%E4%BB%B6"><a id="%E4%BB%8E_JavaScript_%E4%B8%AD%E8%AE%BF%E9%97%AE_CookieManager_%E7%BB%84%E4%BB%B6"></a><strong>从 JavaScript 中访问 CookieManager 组件</strong></span></p> - -<pre>// xpconnect to cookiemanager -// get the cookie manager component in JavaScript -var cmgr = Components.classes["@mozilla.org/cookiemanager;1"] - .getService(); -cmgr = cmgr.QueryInterface(Components.interfaces.nsICookieManager); - -// called as part of a largerDeleteAllCookies() function -function FinalizeCookieDeletions() { - for (var c=0; c<deletedCookies.length; c++) { - cmgr.remove(deletedCookies[c].host, - deletedCookies[c].name, - deletedCookies[c].path); - } - deletedCookies.length = 0; -} -</pre> - -<div class="side-note"> -<p><span id="%E4%BB%8E%E6%8E%A5%E5%8F%A3%E8%BF%9E%E6%8E%A5%E5%88%B0%E7%BB%84%E4%BB%B6"><a id="%E4%BB%8E%E6%8E%A5%E5%8F%A3%E8%BF%9E%E6%8E%A5%E5%88%B0%E7%BB%84%E4%BB%B6"></a><strong>从接口连接到组件</strong></span></p> - -<p>Mozilla 中使用的从 JavaScript 访问 XPCOM 组件的技术称为<em>XPConnect</em>, XPConnect 也是一个组件.</p> - -<p>XPConnect 把应用程序代码与 Mozilla 浏览器, 基于 Gecko 的 XUL, 和象 xpcshell 这样的 JavaScript 环境绑定在一起.</p> - -<p>xpcshsell 是 Mozilla 内嵌的 XPCOM 工具, 它是 JavaScript 的命令行解释器.</p> - -<p>参看 <a class="external" href="http://www.mozilla.org/scriptable/" rel="freelink">http://www.mozilla.org/scriptable/</a>, 获取更多关于 XPConnect 和 JavaScript 的信息.</p> -</div> - -<p>上面展现的技术当然并不是 XPCOM 的全部, 但是却是一个重要的方面. XPCOM 强加的契约打开了一扇通往<em>二进制互操作</em>技术的大门. - 这是一种能够在运行时刻访问, 使用, 重用 XPCOM 组件的技术, 这种技术能够保证用某种语言编写的组件能够被其他的语言所访问.</p> - -<p>在 Mozilla 浏览器中, 组件常常通过接口在 JavaScript 中访问, 搜索 Mozilla 的源代码, 会发现 CookieManager 组件<em>只是</em>在 JavaScript 中被调用. 在本教程中, 我们也使用这种方式来访问它<sup><a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Components#endnote_教程中使用的_coocki_管理器">[教程中使用的 coocki 管理器]</a></sup>.</p> - -<div class="side-note"> -<p><span id="JavaScript_%E4%B8%8E_Mozilla"><a id="JavaScript_%E4%B8%8E_Mozilla"></a><strong>JavaScript 与 Mozilla</strong></span></p> - -<p>JavaScript 是 Mozilla 浏览器的喉舌, 它把自己与 XPCOM 紧紧地绑定在一起. XPCOM 的这种<em>可扩展</em>能力 - 从 XPConnect 绑定的语言中访问组件的能力, 是 XPCOM 的一个关键属性.</p> -</div> - -<h4 id="WebBrowserFind_.E7.BB.84.E4.BB.B6" name="WebBrowserFind_.E7.BB.84.E4.BB.B6"><code>WebBrowserFind</code> 组件</h4> - -<p>组件的应用是广泛的: 在浏览这样的高级应用中, 会有 <code>nsWebBrowserFind</code> 这样的接口, 它提供 <code>find()</code> 和 <code>findNext()</code> 方法用于在网页上查找特定内容. 在一些低级应用中, 会提供数据管理这样的功能. 虽然 Mozilla 并不能将所有的 API 都写成 XPCOM 组件的形式, 但是绝大多数浏览器的典型功能都是用 XPCOM 的组件形式实现的, 因此可以被嵌入和扩展.</p> - -<p>除了 CookieManager 组件, 这里还要介绍一个 WebBrowserFind 组件. 它实现的 <code>nsIWebBrowserFind</code> 接口见下表 <a href="#nsIWebBrowserFind_接口">nsIWebBrowserFind 接口</a>.</p> - -<p><span id="nsIWebBrowserFind_%E6%8E%A5%E5%8F%A3"><a id="nsIWebBrowserFind_%E6%8E%A5%E5%8F%A3"></a><strong>nsIWebBrowserFind 接口</strong></span></p> - -<table class="standard-table"> - <tbody> - <tr> - <td><code>findNext</code></td> - <td>找到字符串出现的下一个位置.</td> - </tr> - <tr> - <td><code>findBackwards</code></td> - <td>布尔类型属性值, 控制 <code>findNext()</code> 方法向前/向后搜索.</td> - </tr> - <tr> - <td><code>searchFrames</code></td> - <td>布尔类型属性值, 标识是否搜索当前页面的子框(subframes).</td> - </tr> - <tr> - <td><code>matchCase</code></td> - <td>布尔类型属性值, 标识是否按照大小写匹配搜索网页.</td> - </tr> - <tr> - <td><code>entireWord</code></td> - <td>布尔类型属性值, 标识是否匹配整个词.</td> - </tr> - </tbody> -</table> - -<p>一旦我们使用接口来获的了某个组件, 我们就可以询问该组件是否支持其他的接口. 这种基本服务由 <code>nsISupports</code> 接口提供, 会由所有的 XPCOM 组件继承; 它允许我们查询组件的接口, 并在接口之间进行切换; 它展现了 XPCOM 的<em>运行时刻确定类型</em>的能力. 它由 <code>QueryInterface</code> 方法实现, 我们将在后面<a href="cn/Creating_XPCOM_Components/%e4%bb%80%e4%b9%88%e6%98%af_XPCOM%3f">什么是 XPCOM?</a>一章中介绍. <a href="cn/XPCOM_API_Reference">XPCOM API Reference</a> 中提供了完整的 XPCOM 组件的索引.</p> - -<h4 id="WebLock_.E7.BB.84.E4.BB.B6" name="WebLock_.E7.BB.84.E4.BB.B6"><strong>WebLock</strong> 组件</h4> - -<p>现在我们把 <strong>WebLock</strong> 组件看成另一个 XPCOM 组件的例子. 在面向对象编程中, 通常是先设计接口 - 首先定义要提供的功能, 而不是考虑如何实现这些功能. 因此我们把实现这个组件的细节问题放到下一章, 这一章先考虑从外部如何看待这个组件. - 即定义 WebLock 组件的接口.</p> - -<p><span id="IWebLock_%E6%8E%A5%E5%8F%A3"><a id="IWebLock_%E6%8E%A5%E5%8F%A3"></a><strong>IWebLock 接口</strong></span></p> - -<table class="standard-table"> - <tbody> - <tr> - <td><code>lock</code></td> - <td>锁定浏览器到当前站点, 或者是磁盘上保存的某个白名单上的站点.</td> - </tr> - <tr> - <td><code>unlock</code></td> - <td>解开浏览器锁定, 开放访问所有站点.</td> - </tr> - <tr> - <td><code>addSite</code></td> - <td>添加一个新的站点到白名单.</td> - </tr> - <tr> - <td><code>removeSite</code></td> - <td>从白名单上删除某个站点.</td> - </tr> - <tr> - <td><code>sites</code></td> - <td>枚举白名单上的站点.</td> - </tr> - </tbody> -</table> - -<p>WebLock 组件就是要实现上面接口定义的功能. 它在浏览器启动的时候, 注册自己. 当用户或者管理员点击浏览器上的 weblock 图标时, 类厂会创建对象实例.</p> - -<h3 id="Mozilla_.E4.B8.AD.E4.BD.BF.E7.94.A8.E7.9A.84.E7.BB.84.E4.BB.B6" name="Mozilla_.E4.B8.AD.E4.BD.BF.E7.94.A8.E7.9A.84.E7.BB.84.E4.BB.B6">Mozilla 中使用的组件</h3> - -<p>那么我们应该如何获得组件, 然后如何在 Mozilla 中使用它呢? 我们在前面已经看到了一小段 JavaScript 代码, 但是我们并没有解释一般情况下该如何获得 XPCOM 组件.</p> - -<p>这一节讨论 Mozilla 中实际使用的组件例子. 本节分成三部分: 一部分是关于该如何在 Mozilla 上找到组件. 其他两个部分是关于该如何访问这些组件.</p> - -<h4 id=".E6.9F.A5.E6.89.BE_Mozilla_.E7.BB.84.E4.BB.B6" name=".E6.9F.A5.E6.89.BE_Mozilla_.E7.BB.84.E4.BB.B6">查找 Mozilla 组件</h4> - -<p>本书试图向读者提供关于 XPCOM 组件和当前冻结的接口的索引信息. <a class="external" href="http://www.mozilla.org/projects/embedding/">Mozilla 嵌入工程</a>跟踪了当前冻结的接口.</p> - -<p>Mozilla 包含了 Gecko 提供的查找和显示组件信息的工具 -<em>XPCOM 组件观察器</em><a class="external" href="http://lxr.mozilla.org/">LXR</a>.</p> - -<p>提供 XPCOM 组件信息的主要问题是, Mozilla 接口在不断的发展, 试图选择一个冻结的断面是困难的. 组件观察器的实现并没有考虑组件是否已被冻结, 在 LXR 中我们会发现, 被冻结的接口会在头部标记 <code>@status frozen</code>.</p> - -<h5 id="XPCOM_.E7.BB.84.E4.BB.B6.E8.A7.82.E5.AF.9F.E5.99.A8" name="XPCOM_.E7.BB.84.E4.BB.B6.E8.A7.82.E5.AF.9F.E5.99.A8">XPCOM 组件观察器</h5> - -<p><a class="external" href="http://www.hacksrus.com/~ginda/cview">组件观察器</a> 是一个可选安装的浏览器插件.</p> - -<p><span id="XPCOM_%E7%BB%84%E4%BB%B6%E8%A7%82%E5%AF%9F%E5%99%A8"><a id="XPCOM_%E7%BB%84%E4%BB%B6%E8%A7%82%E5%AF%9F%E5%99%A8"></a><strong>XPCOM 组件观察器</strong></span></p> - -<p><img alt="Image:using-component-viewer.png"></p> - -<p>在上面的图中, 左列显示的是以<em>gtx</em> 字符串搜索契约 ID 得到的组件子集, 右列是左列选中组件实现的接口.</p> - -<p>XPCOM 观察器在获取组件的大致信息的时候非常有用, 但是要知道组件观察器显示的是<em>所有</em>的组件, 有些组件并不稳定, 组件的接口可能会在后续版本中变化, 所以要慎重选取我们自己工程中使用的组件.</p> - -<p><span class="comment">XXX mediawiki is t3h suxx0r</span> <span class="comment">XXX give me my C++</span></p> - -<h4 id=".E5.9C.A8_Cpp_.E4.BB.A3.E7.A0.81.E4.B8.AD.E4.BD.BF.E7.94.A8_XPCOM_.E7.BB.84.E4.BB.B6" name=".E5.9C.A8_Cpp_.E4.BB.A3.E7.A0.81.E4.B8.AD.E4.BD.BF.E7.94.A8_XPCOM_.E7.BB.84.E4.BB.B6">在 Cpp 代码中使用 XPCOM 组件</h4> - -<p>XPConnect 把对 XPCOM 组件作为 JavaScript 对象, 使得对 XPCOM 组件的访问变得非常简单, 从 C++ 代码中访问 XPCOM 要复杂一些.</p> - -<p><a href="#从_Cpp_代码管理_Cookies">从 Cpp 代码管理 Cookies</a> 以 C++ 代码重新实现了<a href="#从_JavaScript_中访问_CookieManager_组件">从 JavaScript 中访问 CookieManager 组件</a>的功能.</p> - -<p><span id="%E4%BB%8E_Cpp_%E4%BB%A3%E7%A0%81%E7%AE%A1%E7%90%86_Cookies"><a id="%E4%BB%8E_Cpp_%E4%BB%A3%E7%A0%81%E7%AE%A1%E7%90%86_Cookies"></a><strong>从 Cpp 代码管理 Cookies</strong></span></p> - -<pre>nsCOMPtr<nsIServiceManager> servMan; -nsresult rv = NS_GetServiceManager(getter_AddRefs(servMan)); -if (NS_FAILED(rv)) - return -1; - -nsCOMPtr<nsICookieManager> cookieManager; -rv = servMan->GetServiceByContractID("@mozilla.org/cookiemanager", - NS_GET_IID(nsICookieManager), - getter_AddRefs(cookieManager)); - -if (NS_FAILED(rv)) - return -1; - -PRUint32 len; -deletedCookies->GetLength(&len); - -for (int c=0; c<len; c++) - cookieManager->Remove(deletedCookies[c].host, - deletedCookies[c].name, - deletedCookies[c].path, - PR_FALSE); -</pre> - -<p><span class="comment">XXX: In the original document, there were only the first three parameters to the |Remove| call. I added |PR_TRUE| as a fourth parameter because the interface seems to require it: <a class="external" href="http://lxr.mozilla.org/mozilla/source/netwerk/cookie/public/nsICookieManager.idl#64" rel="freelink">http://lxr.mozilla.org/mozilla/sourc...Manager.idl#64</a> This problem also appears in the JavaScript version below, and I've added |false| as a fourth parameter there as well.</span></p> - -<p>如果我们的应用是用 C++ 编写, <a href="#从_Cpp_代码管理_Cookies">从 Cpp 代码管理 Cookies</a> 这段代码向我们提供了很好的模板.</p> - -<h4 id="XPConnect:_.E5.9C.A8.E8.84.9A.E6.9C.AC.E4.B8.AD.E4.BD.BF.E7.94.A8_XPCOM_.E7.BB.84.E4.BB.B6" name="XPConnect:_.E5.9C.A8.E8.84.9A.E6.9C.AC.E4.B8.AD.E4.BD.BF.E7.94.A8_XPCOM_.E7.BB.84.E4.BB.B6">XPConnect: 在脚本中使用 XPCOM 组件</h4> - -<p>在本章开始我们讨论了CookieManager组件,他提供了一个很好的例子来说明如何使用javascript访问组件.在下面的代码片断里你可以看到如何通过getService()方法创建一个CookieManager组件对象,并且通过它提供的功能来让我们从用户界面来读取和删除cookies.</p> - -<p><span id="Managing_Cookies_from_JavaScript"><a id="Managing_Cookies_from_JavaScript"></a><strong>Managing Cookies from JavaScript</strong></span></p> - -<pre>var cmgr = Components.classes["@mozilla.org/cookiemanager;1"] - .getService(); -cmgr = cmgr.QueryInterface(Components.interfaces.nsICookieManager); - -function loadCookies() { - // load cookies into a table - var enumerator = cmgr.enumerator; - var count = 0; - var showPolicyField = false; - while (enumerator.hasMoreElements()) { - var nextCookie = enumerator.getNext(); - nextCookie = nextCookie.QueryInterface(Components.interfaces.nsICookie); - /* .... */ -} -function FinalizeCookieDeletions() { - for (var c=0; c<deletedCookies.length; c++) { - cmgr.remove(deletedCookies[c].host, - deletedCookies[c].name, - deletedCookies[c].path, - false); - } - deletedCookies.length = 0; -} -</pre> - -<p><span class="comment">XXX: In the original document, there were only the first three parameters to the |remove| call. I added |false| as a fourth parameter because the interface seems to require it: <a class="external" href="http://lxr.mozilla.org/mozilla/source/netwerk/cookie/public/nsICookieManager.idl#64" rel="freelink">http://lxr.mozilla.org/mozilla/sourc...Manager.idl#64</a> This problem also appears in the C++ version above, and I've added |PR_FALSE| as a fourth parameter there as well.</span></p> - -<p>除了CookieManager被调用的方法以外(也就是<code>cookiemanager.remove</code>(他会映射到<code>remove()</code><a href="#The_<code>nsICookieManager</code>_Interface">The <code>nsICookieManager</code> Interface</a>),请注意那些在Javascript中反映XPCOM组件的专门的XPConnect对象和方法。</p> - -<p><code>Components</code> 是用来控制到组件连接的JavaScript对象, 而<code>classes</code> 是一组所有你可以根据契约ID来查询的对象。为了在Javascript中实例化XPCOM组件,你创建一个新的<code>Component</code>对象同时传入你所需要查询的组件契约ID,返回的可能是一个singleton或者一个实例。</p> - -<pre>var cmgr = Components.classes["@mozilla.org/cookiemanager;1"] - .getService(); -</pre> - -<p><code>cookiemanager</code> 对象的结果提供组件的所有在IDL中编译好然后编译到类型库中的方法的入口。 使用CookieManager组件, 你可以写如下的代码来完成从系统中清除所有cookies的操作:</p> - -<pre>cmgr = Components.classes["@mozilla.org/cookiemanager;1"] - .getService(); -cmgr = cmgr.QueryInterface(Components.interfaces.nsICookieManager); - -// delete all cookies -function trashEm() { - cmgr.removeAll(); -} -</pre> - -<p>这个例子所展示的另外一个关键的XPConnect特性的是可以在所有从XPCOM映射到javascript的对象上执行的<code>QueryInterface</code>方法。如同在C++中, 你可以使用这个方法询问给定对象的别的接口。</p> - -<div class="side-note"> -<p><span id="Services_Versus_Regular_Instances"><a id="Services_Versus_Regular_Instances"></a><strong>Services Versus Regular Instances</strong></span></p> - -<p>到底让客户把你的组件作为一个实例还是服务是一个设计问题,你应当在你的组件文挡中进行描述。实际上,例子中通过方法<code>createInstance()调用</code><code>getService()</code>方法的方法实际上也可以是对组件对象调用并且缓存结果,并让他做为一个singlenton而不是实例。</p> - -<p>用来建立服务的singleton设计模式在<a href="cn/Creating_XPCOM_Components/What_is_XPCOM%3f#XPCOM_Services">XPCOM Services</a>进行描述。</p> -</div> - -<p>请记住,<code>QueryInterface</code>让你查询一个对象所支持的接口。在<a href="#The_<code>nsICookieManager</code>_Interface">The <code>nsICookieManager</code> Interface</a>的代码片断中, <code>QueryInterface</code>方法被用来从eunumerator中获得<code>nsICookie</code>接口,从而, 比如说, JavaScript代码就可以获得每个cookie的<code>value</code>和<code>name</code>属性。</p> - -<ol> - <li><div class="blockIndicator note"><strong>Note:</strong> cookie-manager-ui</div> 注意接口不是组件的一部分. XPCOM通过Mozilla's Cross Platform Front End (XPFE)和其他的用户接口使使用CookieManager这样的组件变得容易,但是组件本身并不提供自身的UI。</li> -</ol> - -<ol> - <li><div class="blockIndicator note"><strong>Note:</strong> private-xpcom-interfaces</div>这方面也有例外. 一些XPCOM接口也可以是private并且不是作为公用的. Private接口和在IDL中公开的接口要求有所不同。</li> -</ol> - -<ol> - <li><div class="blockIndicator note"><strong>Note:</strong> cookie-manager-in-tutorial</div> CookieManager组件用来支持本教程所描述的网页所定功能。</li> -</ol> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/创建_XPCOM_组件:XPCOM_简介" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Component_Internals">下一页 »</a></p> -</div> <p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/using_xpcom_utilities_to_make_things_easier/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/using_xpcom_utilities_to_make_things_easier/index.html deleted file mode 100644 index 98bb510dd8..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/creating_components/using_xpcom_utilities_to_make_things_easier/index.html +++ /dev/null @@ -1,388 +0,0 @@ ---- -title: 创建XPCOM组件/使用XPCOM工具类让事情变得简单 -slug: >- - Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Utilities_to_Make_Things_Easier -tags: - - XPCOM - - 所有分类 -translation_of: >- - Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Utilities_to_Make_Things_Easier ---- -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Creating_the_Component_Code" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Starting_WebLock">下一页 »</a></p> -</div><p></p> - -<p>本章回顾你已经在教程第一部分建立的代码 (see <a href="cn/Creating_XPCOM_Components/Creating_the_Component_Code#webLock1.cpp">webLock1.cpp</a> in the previous chapter) 并且使用 XPCOM 工具类让代码更容易更有效. 同时,介绍一个在XPCOM和Gecko API中广泛使用基本的字符串类型.</p> - -<p>作为起点,第一部分描述可以替代<code>webLock1.cpp</code>中的很多代码的<em>C++ 宏</em> . 很多用来完成软件组织和组件注册的代码都可以缩减为精简的数据结构和宏代码.</p> - -<h3 id="XPCOM_Macros" name="XPCOM_Macros">XPCOM Macros</h3> - -<p>XPCOM 架构包含了一系列宏让C++开发变得简单. 尽管有某些重叠(例如,高层的宏可以用其他的宏来组织),他们通常可以组织成如下的类别.</p> - -<h4 id="Generic_XPCOM_Module_Macros" name="Generic_XPCOM_Module_Macros">Generic XPCOM Module Macros</h4> - -<p>The work in the <a href="cn/Creating_XPCOM_Components/Creating_the_Component_Code">previous chapter</a> was useful in setting up the generic component code. But there are only a few places in that code that are unique to the <strong>WebLock</strong> component, and it was a lot of typing. To write a different component library, you could copy the listing at the end of the chapter, change very little, and paste it into a new project. To avoid these kinds of redundancies, to regulate the way generic code is written, and to save typing, XPCOM provides<em>generic module macros</em> that expand into the module code you've already seen.</p> - -<p>Since these macros expand into "generic" implementations, they may not offer as much flexibility as you have when you are writing your own implementation. But they have the advantage of allowing much more rapid development. To get an idea about how much can be handled with the macros described in this section, compare the code listing in <a href="#weblock2.cpp">weblock2.cpp</a> at the end of the chapter with <a href="cn/Creating_XPCOM_Components/Creating_the_Component_Code#webLock1.cpp">webLock1.cpp</a> in the previous chapter.</p> - -<p>The module macros include one set of macros that define the exported <code>NSGetModule</code> entry point, the required <code>nsIModule</code> implementation code and another that creates a generic factory for your implementation class. Used together, these macros can take care of a lot of the component implementation code and leave you working on the actual logic for your component.</p> - -<div class="side-note"> -<p>Note that all of the macros described in this section are similar but are used in slightly different situations. Some differ only in whether or not a method is called when the module is created and/or destroyed. <a href="#XPCOM_Module_Macros">XPCOM Module Macros</a> lists the macros discussed in this section.</p> -</div> - -<p><span id="XPCOM_Module_Macros"><a id="XPCOM_Module_Macros"></a><strong>XPCOM Module Macros</strong></span></p> - -<table class="standard-table"> - <tbody> - <tr> - <td class="header">Macro</td> - <td class="header">Description</td> - </tr> - <tr> - <td><code>NS_IMPL_NSGETMODULE(name, components)</code></td> - <td>Implements the <code>nsIModule</code> interface with the module name of <code>name</code> and the component list in <code>components</code>.</td> - </tr> - <tr> - <td><code>NS_IMPL_NSGETMODULE_WITH_CTOR(name, components, ctor)</code></td> - <td>Same as above but allows for a special function to be called when the module is created.</td> - </tr> - <tr> - <td><code>NS_IMPL_NSGETMODULE_WITH_DTOR(name, components, dtor)</code></td> - <td>Same as the first macro but allows for a special function to be called when the module is destroyed.</td> - </tr> - <tr> - <td><code>NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(name, components, ctor, dtor)</code></td> - <td>This combines the last two macros so that you can define functions to be called at the construction and destruction of the module object.</td> - </tr> - </tbody> -</table> - -<h5 id="Module_Implementation_Macros" name="Module_Implementation_Macros">Module Implementation Macros</h5> - -<p>The general case is to use <code>NS_IMPL_NSGETMODULE</code>, which doesn't take any callbacks, but all the macros follow the same general pattern. All of these macros work on an array of structures represented by the <code>components</code> parameter. Each structure describes a CID that is to be registered with XPCOM.</p> - -<p>The first parameter for each of these macros is an arbitrary string that names the module. In a debugging environment, this string will be printed to the screen when the component library is loaded or unloaded. You should pick a name that makes sense and helps you keep track of things. The four required parts<sup><a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Utilities_to_Make_Things_Easier#endnote_other-parts">[other-parts]</a></sup> of the structure contain the following information:</p> - -<ul> - <li>A human readable class name</li> - <li>the class ID (CID)</li> - <li>the contract ID (an optional but recommended argument)</li> - <li>a constructor for the given object</li> -</ul> - -<pre>static const nsModuleComponentInfo components[] = -{ - { "Pretty Class Name", - CID, - CONTRACT_ID, - Constructor - }, - // ... -}; -</pre> - -<p>The important thing to note in the fictitious listing above is that it can support multiple components in a module. Modules such as the networking libraries in Gecko ("necko") have over 50 components declared in a single <code>nsModuleComponentInfo</code> array like this.</p> - -<p>The first entry of the <code>nsModuleComponentInfo</code> above is the name of the component. Though it isn't used that much internally at the present time, this name should be something that meaningfully describes the module.</p> - -<p>The second entry of the <code>nsModuleComponentInfo</code> is the CID. The usual practice is to put the class ID (CID) into a <code>#define</code> and use the define to declare the CID in the components list. Many CIDs take the following form:</p> - -<pre>#define NS_IOSERVICE_CID \ -{ /* 9ac9e770-18bc-11d3-9337-00104ba0fd40 */ \ - 0x9ac9e770, \ - 0x18bc, \ - 0x11d3, \ - {0x93, 0x37, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ -} -</pre> - -<p>The next entry is the Contract ID string, which is also usually defined in a <code>#define</code> in a header file.</p> - -<p>These three entries constitute the required parameters for the <code>RegisterFactoryLocation</code> method we looked at in the prior chapter. When you use these implementation macros, you must declare a constructor for the object, and this keeps you from having to write a factory object.</p> - -<h5 id="Factory_Macros" name="Factory_Macros">Factory Macros</h5> - -<p>The factory macro makes it easy to write factory implementations. Given the class name <code>ConcreteClass</code>, the factory macro declaration is:</p> - -<pre>NS_GENERIC_FACTORY_CONSTRUCTOR(ConcreteClass) -</pre> - -<p>This results in a function called <code>ConcreteClassConstructor</code> that can be used in the <code>nsModuleComponentInfo</code> structure.</p> - -<pre>#include "nsIGenericFactory.h" - -static const nsModuleComponentInfo components[] = -{ - { "Pretty Class Name", - SAMPLE_CID, - "@company.com/sample", - SampleConstructor - } -} - -NS_IMPL_NSGETMODULE(nsSampleModule, components) -</pre> - -<p>Most of the components in the Mozilla browser client use this approach.</p> - -<h4 id="Common_Implementation_Macros" name="Common_Implementation_Macros">Common Implementation Macros</h4> - -<p>Every XPCOM object implements <code>nsISupports</code>, but writing this implementation over and over is tedious. Unless you have very special requirements for managing reference counting or handling interface discovery, the<em>implementation macros</em> that XPCOM provides can be used. Instead of implementing the <code>nsISupports</code> yourself, <code>NS_IMPL_ISUPPORTS1</code> can expand to the implementation of <code>AddRef</code>, <code>Release</code>, and <code>QueryInterface</code> for any object.</p> - -<pre>NS_IMPL_ISUPPORTS1(classname, interface1) -</pre> - -<p>Also, if you implement more than one interface, you can simply change the <code>1</code> in the macro to the number of interfaces you support and list the interfaces, separated by commas. For example:</p> - -<pre>NS_IMPL_ISUPPORTS2(classname, interface1, interface2) -NS_IMPL_ISUPPORTSn(classname, interface1, ..., interfacen) -</pre> - -<p>These macros automatically add the <code>nsISupports</code> entry for you, so you don't need to do something like this:</p> - -<pre class="eval">NS_IMPL_ISUPPORTS2(classname, interface1, <strong>nsISupports</strong>) -</pre> - -<p><br> - Take a close look at the above example. Note that it uses the actual name of the interface and not an IID. Inside the macro, the interface name expands to <code>NS_GET_IID()</code>, which is another macro that extracts the IID from the generated header of the interface. When an interface is written in XPIDL, the headers include static declarations of their IIDs. On any interface that is generated by XPIDL, you can call <code>NS_GET_IID()</code> to obtain the IID which is associated with that interface.</p> - -<pre>// returns a reference to a shared nsIID object\ -static const nsIID iid1 = NS_GET_IID(nsISupports); - -// constructs a new nsIID object -static const nsIID iid2 = NS_ISUPPORTS_IID; -</pre> - -<p>In order to use <code>NS_IMPL_ISUPPORTSn</code>, you must be sure that a member variable of type <code>nsrefcnt</code> is defined and named <code>mRefCnt</code> in your class. But why even bother when you can use another macro?</p> - -<h4 id="Declaration_Macros" name="Declaration_Macros">Declaration Macros</h4> - -<p><code>NS_DECL_NSISUPPORTS</code> declares <code>AddRef</code>, <code>Release</code>, and <code>QueryInterface</code> for you, and it also defines the <code>mRefCnt</code> required by <code>NS_IMPL_ISUPPORTS</code>. Furthermore, <code>NS_DECL_</code> appended with any interface name in all caps will declare all of the methods of that interface for you. For example, <code>NS_DECL_NSIFOO</code> will declare all of the methods of <code>nsIFoo</code> provided that it exists and that <code>nsIFoo.h</code> was generated by the XPIDL compiler. Consider the following real class:</p> - -<pre>class myEnumerator : public nsISimpleEnumerator -{ - public: - NS_DECL_ISUPPORTS - NS_DECL_NSISIMPLEENUMERATOR - - myEnumerator(); - virtual ~myEnumerator() {} -}; -</pre> - -<p>The declaration of this <code>nsISimpleEnumerator</code> class doesn't include any methods other than the contructor and destructor. Instead, the class uses the <code>NS_DECL_</code> macro<sup><a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Utilities_to_Make_Things_Easier#endnote_nsISupports-warning">[nsISupports-warning]</a></sup>.</p> - -<p>Using these declaration macros not only saves a tremendous amount of time when you're writing the code, it can also save time if you make changes to your IDL file, since the C++ header file will then automatically include the updated list of methods to be supported.</p> - -<div class="side-note"> -<p>The <code>NS_INIT_ISUPPORTS</code> macro is also a bit of a special case. Historically, it gets called in the constructor for your class and sets <code>mRefCnt</code> to zero. However, a change in XPCOM that occurred before Mozilla 1.3 makes <code>NS_INIT_ISUPPORTS</code> no longer necessary: <code>mRefCnt</code>'s type has been changed from an integer to a class that provides its own auto-initialization. If you are building with versions earlier than Mozilla 1.3, this macro is still required.</p> -</div> - -<p>The following table summarizes the macro usage in this portion of the <code>weblock.cpp</code> source file:</p> - -<p><span id="Common_XPCOM_Macros"><a id="Common_XPCOM_Macros"></a><strong>Common XPCOM Macros</strong></span></p> - -<table class="standard-table"> - <tbody> - <tr> - <td><code>NS_IMPL_ISUPPORTSn</code></td> - <td>Implements <code>nsISupports</code> for a given class with <code>n</code> number of interfaces</td> - </tr> - <tr> - <td><code>NS_DECL_ISUPPORTS</code></td> - <td>Declares methods of <code>nsISupports</code> including <code>mRefCnt</code></td> - </tr> - <tr> - <td><code>NS_INIT_ISUPPORTS</code></td> - <td>Initializes <code>mRefCnt</code> to zero. Must be called in class's constructor</td> - </tr> - <tr> - <td><code>NS_GET_IID</code></td> - <td>Returns the IID given the name of an interface. Interface must be generated by XPIDL</td> - </tr> - </tbody> -</table> - -<p>Using the macros described here, the code for the <strong>WebLock</strong> component has gone from around 340 lines of code to just under 40. Clearly from a code maintenance point of view, this kind of reduction is outstanding. The entire source file with these macros included appears in <a href="#weblock2.cpp">weblock2.cpp</a>.</p> - -<h3 id="weblock2.cpp" name="weblock2.cpp">weblock2.cpp</h3> - -<p>The listing below shows the generic module code from <a href="cn/Creating_XPCOM_Components/Creating_the_Component_Code#webLock1.cpp">webLock1.cpp</a> using the macros described in this chapter:</p> - -<p><span id="weblock2.cpp"><a id="weblock2.cpp"></a><strong>weblock2.cpp</strong></span></p> - -<pre>#include "nsIGenericFactory.h" -#include "nsISupportsUtils.h" - -#define SAMPLE_CID \ -{ 0x777f7150, 0x4a2b, 0x4301, \ -{ 0xad, 0x10, 0x5e, 0xab, 0x25, 0xb3, 0x22, 0xaa}} - -class Sample: public nsISupports -{ - public: - Sample(); - virtual ~Sample(); - - NS_DECL_ISUPPORTS -}; - -Sample::Sample() -{ - // note: in newer versions of Gecko (1.3 or later) - // you don't have to do this: - NS_INIT_ISUPPORTS(); -} - -Sample::~Sample() -{ -} - -NS_IMPL_ISUPPORTS1(Sample, nsISupports); - -NS_GENERIC_FACTORY_CONSTRUCTOR(Sample); - -static const nsModuleComponentInfo components[] = -{ - { "Pretty Class Name", - SAMPLE_CID, - "@company.com/sample", - SampleConstructor - } -}; - -NS_IMPL_NSGETMODULE(nsSampleModule, components) -</pre> - -<h3 id="String_Classes_in_XPCOM" name="String_Classes_in_XPCOM">String Classes in XPCOM</h3> - -<p>Strings are usually thought of as linear sequences of characters. In C++, the string literal "XPCOM", for example, consists of 6 consecutive bytes, where `X' is at byte offset zero and a null character is at byte offset 5. Other kinds of strings like "wide" strings use two bytes to represent each character, and are often used to deal with Unicode strings.</p> - -<p>The string classes in XPCOM are not just limited to representing a null terminated sequence of characters, however. They are fairly complex because they support the Gecko layout engine and other subsystems that manage large chunks of data. Additionally, in some versions of Mozilla the string classes support sequences of characters broken up into multiple fragments (fragments which may or may not be null terminated)<sup><a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Utilities_to_Make_Things_Easier#endnote_nulls-in-strings">[nulls-in-strings]</a></sup>.</p> - -<p>All string classes in XPCOM derive from one of two abstract classes<sup><a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components/Using_XPCOM_Utilities_to_Make_Things_Easier#endnote_other-string-classes">[other-string-classes]</a></sup>: <code>nsAString</code> and <code>nsACString</code>. The former handles double byte characters, and the latter tends to be used in more general circumstances, but both of these classes define the functionality of a string. You can see these classes being passed as arguments in many of the XPCOM interfaces we'll look at in the following chapters.</p> - -<h4 id="Using_Strings" name="Using_Strings">Using Strings</h4> - -<p>Explaining how all the string classes work is outside the scope of this book, but we can show you how to use strings in the <strong>WebLock</strong> component. The first thing to note is that the string classes themselves are not frozen, which means that you should not link against them when you can avoid it.</p> - -<p>Linking the full string library (<code>.lib</code> or <code>.a</code>) into a component may raise its footprint by more than 100k (on Windows), which in many cases is an unacceptable gain (see the <a href="cn/XPCOM_string_guide">XPCOM string guide</a>). For <strong>WebLock</strong>, where the string classes need to be only wrappers around already existing string data, trading advanced functionality for a much smaller footprint is the right way to go. The <strong>WebLock</strong> string classes don't need to append, concatenate, search, or do any other real work on the string data; they just need to represent <code>char*</code> and other data and pass them to methods that expect an <code>nsACString</code>.</p> - -<h4 id="nsEmbedString_and_nsEmbedCString" name="nsEmbedString_and_nsEmbedCString"><code>nsEmbedString</code> and <code>nsEmbedCString</code></h4> - -<p>The strings used in this tutorial are <code>nsEmbedString</code> and <code>nsEmbedCString</code>, which implement the <code>nsAString</code> abstract class and the <code>nsACString</code> abstract classes, respectively. This first example shows an <code>nsEmbedCString</code> being used to pass an <code>nsACString</code> to a method that's not expected to modify the string.</p> - -<pre>// in IDL: method(in ACString thing); - -char* str = "How now brown cow?"; -nsEmbedCString data(str); -rv = object->Method(data); -</pre> - -<p>In this next example, the method is going to set the value of the string - as it might need to do when it returns the name of the current user or the last viewed URL.</p> - -<pre>// in IDL: attribute ACString data; - -nsEmbedCString data; -method->GetData(data); - -// now to extract the data from the url class: - -const char* aStringURL = data.get(); -</pre> - -<p>Note that the memory pointed to by <code>aStringURL</code> after the call to <code>url.get()</code> is owned by the URL string object. If you need to keep this string data around past the lifetime of the string object, you must make a copy.</p> - -<div class="side-note"> -<p><span id="String_Size"><a id="String_Size"></a><strong>String Size</strong></span></p> - -<p>The examples above illustrate the use of the single byte string class, <code>nsEmbedCString</code>. The double byte version, <code>nsEmbedString</code>, has the same functionality but the constructor takes <code>nsAString</code> and the .get() method returns the type <code>PRUnichar*</code>. Note that <code>PRUnichar</code> is a two byte value. In the coming chapters, you'll see examples that use this version in the <strong>WebLock</strong> component.</p> -</div> - -<h3 id="Smart_Pointers" name="Smart_Pointers">Smart Pointers</h3> - -<p>All of the interfaces that you've seen so far are reference counted. Leaking a reference by not releasing an object, as the code below demonstrates, can be a major problem.</p> - -<pre>{ - nsISupports* value = nsnull; - object->method(&value); - if (!value) return; - - // ... - - if (NS_FAILED(error)) - return; // <------------ leaks |value| - //... - - NS_RELEASE(value); // release our reference -} -</pre> - -<p>A method returns an <code>nsISupports</code> interface pointer that has been reference counted before it is returned (assuming it wasn't <code>nsnull</code>). If you handle an error condition by returning prematurely, whatever value points at will leak-it will never be deleted. This is a trivial fix in this example, but in real code, this can easily happen in <code>goto</code> constructs, or in deep nesting with early <code>return</code>s.</p> - -<p>Having more than one interface pointer that needs to be released when a block goes out of scope begs for a tool that can aid the developer. In XPCOM, this tool is the <code>nsCOMPtr</code>, or<em>smart pointer</em> class, which can save you countless hours and simplify your code when you're dealing with interface pointers. Using smart pointers, the code above can be simplified to:</p> - -<pre>{ - nsCOMPtr<nsISupports> value; - object->method(getter_AddRefs(value)); - if (!value) return; - - // ... - - if (NS_FAILED(error)) - return; - // ... -} -</pre> - -<p>The style or syntax may be unfamilar, but smart pointers are worth learning and using because they simplify the task of managing references. <code>nsCOMPtr</code> is a C++ template class that acts almost exactly like raw pointers, that can be compared and tested, and so on. When you pass them to a getter, you must do something special, however: You must wrap the variable with the function <code>getter_AddRefs</code>, as in the example above.</p> - -<p>You cannot call the <code>nsISupports</code> <code>AddRef</code> or <code>Release</code> methods on a <code>nsCOMPtr</code>. But this restriction is desirable, since the <code>nsCOMPtr</code> is handling reference counting for you. If for some reason you need to adjust the reference count, you must assign the <code>nsCOMPtr</code> to a new variable and <code>AddRef</code> that. This is a common pattern when you have a local <code>nsCOMPtr</code> in a function and you must pass back a reference to it, as in the following:</p> - -<pre>SomeClass::Get(nsISupports** aResult) -{ - if (!aResult) - return NS_ERROR_NULL_POINTER; - - nsCOMPtr<nsISupports> value; - object->method(getter_AddRefs(value)); - - *aResult = value.get(); - NS_IF_ADDREF(*aResult); - return NS_OK; -} -</pre> - -<p>The first thing that this method does is check to see that the caller passed a valid address. If not, it doesn't even try to continue. Next, it calls another method on an object that is presumed to exist in this context. You can call a <code>.get()</code> method on the <code>nsCOMPtr</code> and have it returned for use as a raw pointer. This raw pointer can then be assigned to a variable and have its reference updated by <code>NS_IF_ADDREF</code>. Be very careful with the result of <code>.get()</code>, however. You should never call <code>Release</code> on this result because it may result in a crash. Instead, to explicitly release the object being held by a <code>nsCOMPtr</code>, you can assign zero to that pointer.</p> - -<p>Another nice feature of smart pointers - the part that makes them smart - is that you can <code>QueryInterface</code> them quite easily. For example, there are two interfaces for representing a file on a file system, the <code>nsIFile</code> and <code>nsILocalFile</code>, and they are both implemented by an object. Although we haven't formally introduced these two interfaces, the next code sample shows how simple it is to switch between these two interface:</p> - -<pre>SomeClass::DoSomething(nsIFile* aFile) -{ - if (!aFile) - return NS_ERROR_NULL_POINTER; - - nsresult rv; - nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile, &rv); - // ... -} -</pre> - -<p>If the <code>QueryInterface</code> is successful, <code>localFile</code> will be non-null, and <code>rv</code> will be set to <code>NS_OK</code>. If <code>QueryInterface</code> fails, <code>localFile</code> will be null, and <code>rv</code> will be set to a specific error code corresponding to the reason for the failure. In this construct, the result code <code>rv</code> is an optional parameter. If you don't care what the error code is, you can simply drop it from the function call.</p> - -<p>From this point on, we'll be using <code>nsCOMPtr</code>s as much as possible in <strong>WebLock</strong>. For a complete listing of smart pointer functionality, see <a class="external" href="http://www.mozilla.org/projects/xpcom/nsCOMPtr/">mozilla.org's <code>nsCOMPtr</code> documentation</a><span class="comment">XXX this should be in devmo</span>.</p> - -<ol> - <li><div class="blockIndicator note"><strong>Note:</strong> other-parts</div> This section discusses the main parameters of this structure. For a complete listing of all available options you can look at the complete reference in the <a href="cn/XPCOM_API_Reference">XPCOM API Reference</a>.</li> - <li><div class="blockIndicator note"><strong>Note:</strong> nsISupports-warning</div> Note that <code>NS_DECL_ISUPPORTS</code> doesn't obey the general rule in which every interface has a declaration macro of the form <code>NS_DECL_INTERFACENAME</code>, where <code>INTERFACENAME</code> is the name of the interface being compiled.</li> - <li><div class="blockIndicator note"><strong>Note:</strong> nulls-in-strings</div> The string classes may also support embedded nulls.</li> - <li><div class="blockIndicator note"><strong>Note:</strong> other-string-classes</div> There are other abstract string classes, but they are outside the scope of this book.</li> -</ol> - -<p></p><div class="prevnext" style="text-align: right;"> - <p><a href="/zh-CN/docs/Creating_XPCOM_Components:Creating_the_Component_Code" style="float: left;">« 上一页</a><a href="/zh-CN/docs/Creating_XPCOM_Components:Starting_WebLock">下一页 »</a></p> -</div> <p></p><div class="licenseblock"> -<p>Copyright (c) 2003 by Doug Turner and Ian Oeschger. This material may be distributed only subject to the terms and conditions set forth in the <a class="external" href="http://www.opencontent.org/openpub/" rel="noopener">Open Publication License</a>, v1.02 or later. Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.</p> -</div><p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/hashtables/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/hashtables/index.html deleted file mode 100644 index 24740b535c..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/hashtables/index.html +++ /dev/null @@ -1,282 +0,0 @@ ---- -title: Hashtables -slug: Mozilla/Tech/XPCOM/Guide/Hashtables -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Hashtables ---- -<p> </p> -<h2 id="What_Is_a_Hashtable.3F" name="What_Is_a_Hashtable.3F">What Is a Hashtable?</h2> -<p>A hashtable is a data construct that stores a set of <b>items</b>. Each item has a <b>key</b> that identifies the item. Items are found, added, and removed from the hashtable by using the key. Hashtables may seem like <a href="cn/XPCOM_array_guide">arrays</a>, but there are important differences:</p> -<p>哈希表是一个存储一系列<b>元素</b>的数据结构。每个元素都由一个<b>关键字</b>来标识。元素可以通过关键字来进行查找,添加,删除操作。哈希表非常类似<a href="cn/XPCOM_array_guide">arrays</a>,但是也有一些很大的区别。</p> -<table class="standard-table"> - <tbody> - <tr> - <th> </th> - <th class="header">数组</th> - <th class="header">哈希表</th> - </tr> - <tr> - <td class="header">关键字:</td> - <td> - <i> - 整数:</i> - arrays are always keyed on integers, and must be contiguous. 数组必须用整数作为关键字,而且每两个元素之间必须相邻接</td> - <td> - <i> - 任意类型:</i> - almost any datatype can be used as key, including strings, integers, XPCOM interface pointers, IIDs, and almost anything else. Keys can be disjunct (i.e. you can store entries with keys 1, 5, and 3000). 任意类型都可以作为关键字,包括字符串,整数,XPCOM接口指针,IIDs等等。关键字之间可以不在一起(例如,你可以用1,5,和3000来作为关键字。)</td> - </tr> - <tr> - <td class="header">查询时间:</td> - <td> - <i> - O(1):</i> - lookup time is a simple constant。查找时间是个简单的定值</td> - <td> - <i> - O(1):</i> - lookup time is mostly-constant, but the constant time can be larger than an array lookup。查找时间几乎是定值,但是比数组慢点。</td> - </tr> - <tr> - <td class="header">排序:</td> - <td> - <i> - sorted:</i> - stored sorted; enumerated in a sorted fashion.</td> - <td> - <i> - unsorted:</i> - stored unsorted; cannot be enumerated in a sorted manner.</td> - </tr> - <tr> - <td class="header">插入/删除:</td> - <td> - <i> - O(n):</i> - adding and removing items from a large array can be time-consuming</td> - <td> - <i> - O(1):</i> - adding and removing items from hashtables is a quick operation</td> - </tr> - <tr> - <td class="header">浪费空间:</td> - <td> - <i> - none:</i> - Arrays are packed structures, so there is no wasted space.</td> - <td> - <i> - some:</i> - hashtables are not packed structures; depending on the implementation, there may be significant wasted memory.</td> - </tr> - </tbody> -</table> -<p>In their implementation, hashtables take the key and apply a mathematical <b>hash function</b> to <b>randomize</b> the key and then use the hash to find the location in the hashtable. Good hashtable implementations will automatically resize the hashtable in memory if extra space is needed, or if too much space has been allocated.</p> -<h2 id="When_Should_I_Use_a_Hashtable.3F" name="When_Should_I_Use_a_Hashtable.3F">When Should I Use a Hashtable?</h2> -<p>Hashtables are useful for</p> -<ul> - <li>sets of data that need swift <b>random access</b>;</li> - <li>with <b>non-integral keys</b> or <b>non-contiguous integral keys</b>;</li> - <li>or where <b>items will be frequently added or removed</b>.</li> -</ul> -<p>Hashtables should - <i> - not</i> - be used for</p> -<ul> - <li>Sets that need to be <b>sorted</b>;</li> - <li>Very small datasets (less than 12-16 items);</li> - <li>Data that does not need random access.</li> -</ul> -<p>In these situations, an array, a linked-list, or various tree data structures are more efficient.</p> -<h2 id="Mozilla.27s_Hashtable_Implementations" name="Mozilla.27s_Hashtable_Implementations">Mozilla's Hashtable Implementations</h2> -<p>Mozilla has several hashtable implementations, which have been tested and, tuned, and hide the inner complexities of hashtable implementations:</p> -<ul> - <li><code><a href="#PLDHash_.28JSDHash.29">PLDHash</a></code> - low-level C API; stores keys and data in one large memory structure; uses the heap efficiently; client must declare an "entry class" and may not hold onto entry pointers.</li> - <li><code><a href="#PLHashTable">PLHashTable</a></code> - low-level C API; entry class pointers are constant; more efficient for large entry structures; often wastes memory making many small heap allocations.</li> - <li><code><a href="#nsTHashtable">nsTHashtable</a></code> - low-level C++ wrapper around <code>PLDHash</code>; generates callback functions and handles most casting automagically. Client writes their own entry class which can include complex key and data types.</li> - <li><code><a href="#nsBaseHashtable_and_friends:_nsDataHashtable.2C_nsInterfaceHashtable.2C_and_nsClassHashtable">nsDataHashtable/nsInterfaceHashtable/nsClassHashtable</a></code> - high-level C++ wrappers around <code>PLDHash</code>; simplifies the common usage pattern mapping a simple keytype to a simple datatype; client does not need to declare or manage an entry class; <code><b>nsDataHashtable</b></code> datatype is a scalar such as <code>RUint32</code>; <code><b>nsInterfaceHashtable</b></code> datatype is an interface; <code><b>nsClassHashtable</b></code> datatype is a class pointer owned by the hashtable.</li> -</ul> -<h3 id="Which_Hashtable_Should_I_Use.3F" name="Which_Hashtable_Should_I_Use.3F">Which Hashtable Should I Use?</h3> -<table class="standard-table"> - <tbody> - <tr> - <th class="header" colspan="2" rowspan="2"> </th> - <th class="header" colspan="5">Key Type:</th> - </tr> - <tr> - <th class="header">integer</th> - <th class="header">String/CString</th> - <th class="header">nsID</th> - <th class="header">nsISupports*</th> - <th class="header">Complex</th> - </tr> - <tr> - <td class="header" rowspan="8">Data Type:</td> - <td class="header">None (Hash Set)</td> - <td><code>nsInt32HashSet</code></td> - <td><code>ns(C)StringHashSet</code></td> - <td colspan="3"><code>nsTHashtable<...></code></td> - </tr> - <tr> - <td class="header" rowspan="2">Simple (PRUint32)</td> - <td colspan="4"><code>nsDataHashtable</code></td> - <td rowspan="6"><code>nsTHashtable<...></code></td> - </tr> - <tr> - <td><code><nsUint32HashKey,<br> - PRUint32></code></td> - <td><code><ns(C)StringHashKey,<br> - PRUint32></code></td> - <td><code><nsIDHashKey,<br> - PRUint32></code></td> - <td><code><nsISupportsHashKey,<br> - PRUint32></code></td> - </tr> - <tr> - <td class="header" rowspan="2">Interface (nsISupports)</td> - <td colspan="4"><code>nsInterfaceHashtable</code></td> - </tr> - <tr> - <td><code><nsUint32HashKey,<br> - nsISupports></code></td> - <td><code><ns(C)StringHashKey,<br> - nsISupports></code></td> - <td><code><nsIDHashKey,<br> - nsISupports></code></td> - <td><code><nsISupportsHashKey,<br> - nsISupports></code></td> - </tr> - <tr> - <td class="header" rowspan="2">Class (nsString*)</td> - <td colspan="4"><code>nsClassHashtable</code></td> - </tr> - <tr> - <td><code><nsUint32HashKey,<br> - nsString></code></td> - <td><code><ns(C)StringHashKey,<br> - nsString></code></td> - <td><code><nsIDHashKey,<br> - nsString></code></td> - <td><code><nsISupportsHashKey,<br> - nsString></code></td> - </tr> - <tr> - <td class="header">Complex<br> - (structures, etc.)</td> - <td colspan="5"><code>nsTHashtable<...></code></td> - </tr> - </tbody> -</table> -<h3 id="PLDHash_.28JSDHash.29" name="PLDHash_.28JSDHash.29">PLDHash (JSDHash)</h3> -<p><code>PLDHash</code> and <code>JSDHash</code> are the same thing; one is linked from the XPCOM libraries, the other from the JS libraries. <code>JSDHash</code> is used extensively in the SpiderMonkey JS engine.</p> -<p>The <code>PLDHash</code> implementation is a fairly low-level implementation, written in C. It is extremely flexible, but requires some time to understand and use. A basic guide is included here, but you should read most of <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/pldhash.h" rel="custom">xpcom/glue/pldhash.h</a></code> if you intend to use <code>PLDHash</code>. The C++ wrappers for <code>PLDHash</code> (see below) are often much easier and safer to use in C++ code, as many potential casting errors are easily avoided.</p> -<p>You must declare an <b>entry struct</b> type, deriving from <a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/pldhash.h#81" rel="custom"><code>PLDHashEntryHdr</code></a>. This entry struct should contain whatever data you wish to store in the hashtable (any pointer or fixed-length data type). <b>Note:</b> because of the double-hashing implementation, entries may move in memory when the hashtable is altered. If you need entry pointers to remain constant, you may want to consider using <code><a href="#PLHashTable">PLHashTable</a></code> instead.</p> -<p>You must also initialize a <a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/pldhash.h#312" rel="custom"><code>PLDHashTableOps</code></a> structure. This serves similarly to a vtable in C++, with pointers to appropriate user-defined functions that initialize, compare, and match entries. Because <code>PLDHash</code> does not know what datatype your key is, all functions that work with keys are declared using <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/pldhash.h#354" rel="custom">const void*</a></code>, and your client code must cast these pointers to the appropriate type.</p> -<p>PLDHashTables can be allocated on the stack or the heap:</p> -<ul> - <li>When allocated on the stack, or as a C++ class member, the table must be initialized using <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/pldhash.h#427" rel="custom">PL_DHashTableInit</a></code>, and finalized using <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/pldhash.h#459" rel="custom">PL_DHashTableFinish</a></code>;</li> - <li>When allocated on the heap, use <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/pldhash.h#410" rel="custom">PL_NewDHashTable</a></code> and <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/pldhash.h#420" rel="custom">PL_DHashTableDestroy</a></code> to allocate and delete the table.</li> -</ul> -<h3 id="PLHashTable" name="PLHashTable">PLHashTable</h3> -<p><code>PLHashTable</code> is a part of NSPR. The header file can be found at <code><code><a href="https://dxr.mozilla.org/mozilla-central/source/nsprpub/lib/ds/plhash.h" rel="custom">nsprpub/lib/ds/plhash.h</a></code></code>. In general, <code><a href="#PLDHash_.28JSDHash.29">PLDHash</a></code> is a better solution than <code>PLHashTable</code>, because <code>PLHashTable</code> makes many heap allocations.</p> -<p>There are two situations where <code>PLHashTable</code> may be preferable to <code>PLDHash</code>:</p> -<ul> - <li>You need entry-pointers to remain constant.</li> - <li>The entries stored in the table are very large (larger than 12 words). <code>PLDHash</code> does not handle large entry structures efficiently.</li> -</ul> -<h3 id="nsTHashtable" name="nsTHashtable">nsTHashtable</h3> -<p><code>nsTHashtable</code> is a C++ template that wraps <code>PLDHash</code>. It hides many of the complexities of <code>PLDHash</code> (callback functions, the ops structure, etc). You should read <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsTHashtable.h" rel="custom">xpcom/glue/nsTHashtable.h</a></code>.</p> -<p>To use <code>nsTHashtable</code>, you must declare an entry-class in a <a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsTHashtable.h#65" rel="custom">pre-defined format</a>. This entry class contains the key and the data that you are hashing (just like <code>PLDHash</code>, above). It also declares functions that manipulate the key. In most cases, the functions of this entry class can be entirely inline. For examples of entry classes, see the declarations at <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsHashKeys.h" rel="custom">xpcom/glue/nsHashKeys.h</a></code>.</p> -<p>The template parameter is the entry class. You must use the <code>Init()</code> function to initalize the table properly. At this point, use the functions <code>PutEntry/GetEntry/RemoveEntry</code> to alter the hashtable. <code>EnumerateEntries</code> will do enumeration, but beware that the enumeration will occur in a seemingly-random order (no sorting).</p> -<ul> - <li><code>nsTHashtable</code>s can be allocated on the stack, as class members, or on the heap.</li> - <li>Entry pointers can and do change when items are added to the hashtable, or removed. Do not keep long-lasting pointers to entries.</li> - <li>because of this, <code>nsTHashtable</code> is not inherently thread-safe. If you use a hashtable in a multi-thread environment, you must provide locking as appropriate.</li> -</ul> -<p>Before using <code>nsTHashtable</code>, see if <code>nsBaseHashtable</code> and relatives will work for you. They are much easier to use, because you do not have to declare an entry class. If you are hashing a simple key type to a simple data type, they are generally a better choice.</p> -<h3 id="nsBaseHashtable_and_friends:_nsDataHashtable.2C_nsInterfaceHashtable.2C_and_nsClassHashtable" name="nsBaseHashtable_and_friends:_nsDataHashtable.2C_nsInterfaceHashtable.2C_and_nsClassHashtable">nsBaseHashtable and friends: nsDataHashtable, nsInterfaceHashtable, and nsClassHashtable</h3> -<p>These C++ templates provide a high-level interface for using hashtables that hides most of the complexities of <code>PLDHash</code>. They provide the following features:</p> -<ul> - <li>hashtable operations can be completed without using an entry class, making code easier to read;</li> - <li>optional thread-safety: the hashtable can manage a read-write lock around the table;</li> - <li>predefined key classes provide automatic cleanup of strings/interfaces</li> - <li><code>nsInterfaceHashtable</code> and <code>nsClassHashtable</code> automatically release/delete data pointers to avoid leaks.</li> -</ul> -<p><code>nsBaseHashtable</code> is not used directly; choose one of the three derivative classes based on the data type you want to store. The <code>KeyClass</code> is taken from <code>nsHashKeys.h</code> and is the same for all three classes:</p> -<ul> - <li><code>nsDataHashtable<KeyClass, - <i> - DataType</i> - ></code> - <code>DataType</code> is a simple type such as <code>PRUint32</code> or <code>PRBool</code>.</li> - <li><code>nsInterfaceHashtable<KeyClass, - <i> - Interface</i> - ></code> - <code>Interface</code> is an XPCOM interface such as <code>nsISupports</code> or <code>nsIDOMNode</code></li> - <li><code>nsClassHashtable<KeyClass, - <i> - T</i> - ></code> - <code>T</code> is any C++ class. The hashtable stores a pointer to the class, and deletes it when the entry is removed.</li> -</ul> -<p>The important files to read are <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsBaseHashtable.h" rel="custom">xpcom/glue/nsBaseHashtable.h</a></code> and <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsHashKeys.h" rel="custom">xpcom/glue/nsHashKeys.h</a></code>. These classes can be used on the stack, as a class member, or on the heap. Initialize using the <code>Init()</code> function; you can specify whether you need thread-safety at this time. Use the <code>Put()</code>, <code>Get()</code>, and <code>Remove()</code> methods to alter the table.</p> -<p>There are two enumeration functions:</p> -<ul> - <li><code>EnumerateRead()</code> performs a read-only enumeration, where entries cannot be changed or removed;</li> - <li><code>Enumerate()</code> performs a read-write enumeration, where entries may be changed or removed as necessary.</li> -</ul> -<h3 id="Using_nsTHashtable_as_a_hash-set" name="Using_nsTHashtable_as_a_hash-set">Using nsTHashtable as a hash-set</h3> -<p>A hash set only tracks the existence of keys: it does not associate data with the keys. This can be done using <code>nsTHashtable<nsSomeHashKey></code>. The appropriate entries are GetEntry and PutEntry.</p> -<h2 id="Future_Plans" name="Future_Plans">Future Plans</h2> -<h3 id="nsISimpleEnumerator_support" name="nsISimpleEnumerator_support">nsISimpleEnumerator support</h3> -<p>The (obsolete) <code>nsHashtable</code> has a wrapper that exposes an <code>nsISimpleEnumerator</code> on its items. I will add this support to the various <code>nsBaseHashtable</code> classes as well, as needed.</p> -<h2 id="Hash_Functions" name="Hash_Functions">Hash Functions</h2> -<p>All of the above hashtables need a <a class="external" href="http://www.nist.gov/dads/HTML/hash.html">Hash Function</a>. This function converts the key into a semi-unique integer. The mozilla codebase already contains hash functions for most key types, including narrow and wide strings, pointers, and most binary data:</p> -<table class="standard-table"> - <tbody> - <tr> - <td><code>void*<br> - (or nsISupports*)</code></td> - <td>cast using <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/base/nscore.h#443" rel="custom">NS_PTR_TO_INT32</a></code></td> - </tr> - <tr> - <td><code>char*</code> string</td> - <td rowspan="2"><code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/ds/nsCRT.h#228" rel="custom">nsCRT::HashCode()</a></code></td> - </tr> - <tr> - <td><code>PRUnichar*</code> string</td> - </tr> - <tr> - <td><code>nsAString</code></td> - <td rowspan="2"><code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsTHashtable.cpp#41" rel="custom">HashString()</a></code></td> - </tr> - <tr> - <td><code>nsACString</code></td> - </tr> - <tr> - <td><code>nsID&</code></td> - <td><code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsHashKeys.h#227" rel="custom">nsIDHashKey::HashKey()</a></code></td> - </tr> - </tbody> -</table> -<p>Writing a good hash function is well beyond the scope of this document, and has been discussed extensively in computer-science circles for many years. There are many different types of hash functions. Mozilla has tuned a good general-purpose hash algorithm for strings and <code>nsID</code>.</p> -<h2 id="Mozilla.27s_Old.2FObsolete.2FDeprecated.2FDecrepit_Hashtables" name="Mozilla.27s_Old.2FObsolete.2FDeprecated.2FDecrepit_Hashtables">Mozilla's Old/Obsolete/Deprecated/Decrepit Hashtables</h2> -<h3 id="nsHashtable" name="nsHashtable">nsHashtable</h3> -<p><code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/ds/nsHashtable.h" rel="custom">nsHashtable</a></code> was a C++ wrapper around <code>PLHashTable</code>, and now wraps <code>PLDHash</code>. The design of the key classes is not optimal, however, and <code>nsHashtable</code> has been deprecated in favor of <code>nsDataHashtable</code> and friends.</p> -<h3 id="nsObjectHashtable" name="nsObjectHashtable">nsObjectHashtable</h3> -<p><code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/ds/nsHashtable.h#163" rel="custom">nsObjectHashtable</a></code> is a form of <code>nsHashtable</code>. It has been replaced by <code>nsClassHashtable</code>.</p> -<h3 id="nsSupportsHashtable" name="nsSupportsHashtable">nsSupportsHashtable</h3> -<p><code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/ds/nsHashtable.h#193" rel="custom">nsSupportsHashtable</a></code> is a form of <code>nsHashtable</code>. It has been replaced by <code>nsInterfaceHashtable</code>.</p> -<h3 id="nsHashSets" name="nsHashSets">nsHashSets</h3> -<p><code>nsHashSets</code> has predefined hash sets for common keys, which are trivially easy to use. See <code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/ds/nsHashSets.h" rel="custom">xpcom/ds/nsHashSets.h</a></code>. This functionality has been replaced by <code>nsTHashtable<nsSomeHashKey></code>.</p> -<h3 id="nsDoubleHashtable" name="nsDoubleHashtable">nsDoubleHashtable</h3> -<p><code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/ds/nsDoubleHashtable.h" rel="custom">nsDoubleHashtable</a></code> is the (obsolete) precursor to <code>nsTHashtable</code>. It uses macros instead of C++ templates.</p> -<div class="originaldocinfo"> - <h2 id="Original_Document_Information" name="Original_Document_Information">Original Document Information</h2> - <ul> - <li>Author(s): Benjamin Smedberg <<a class="link-mailto" href="mailto:benjamin@smedbergs.us" rel="freelink">benjamin@smedbergs.us</a>></li> - </ul> -</div> -<p> </p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/index.html deleted file mode 100644 index 385888d9fb..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/index.html +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: XPCOM 指南 -slug: Mozilla/Tech/XPCOM/Guide -tags: - - Landing - - Mozilla - - XPCOM -translation_of: Mozilla/Tech/XPCOM/Guide ---- -<p> </p> -<p><span class="seoSummary" style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px;">本文提供了关于 XPCOM 的说明和使用文档,包括如何在你的工程中使用,如何为你的 Firefox 扩展等构建 XPCOM 组件。</span></p> -<p></p><div class="row topicpage-table"> - <div class="section"><dl><dl><dt class="landingPageList"><a href="/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Arrays">Array</a></dt><dd class="landingPageList"></dd><dt class="landingPageList"><a href="/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Hashtables">Hashtables</a></dt><dd class="landingPageList"></dd><dt class="landingPageList"><a href="/zh-CN/docs/How_to_Build_an_XPCOM_Component_in_Javascript">How to Build an XPCOM Component in Javascript</a></dt><dd class="landingPageList"></dd></dl></dl></div> - <div class="section"><dl><dt class="landingPageList"><a href="/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Internal_strings">Strings</a></dt><dd class="landingPageList"></dd><dt class="landingPageList"><a href="/zh-CN/docs/Mozilla/Tech/XPCOM/Guide/Creating_components">创建_XPCOM_组件</a></dt><dd class="landingPageList"></dd></dl></div> - </div><p></p> diff --git a/files/zh-cn/mozilla/tech/xpcom/guide/internal_strings/index.html b/files/zh-cn/mozilla/tech/xpcom/guide/internal_strings/index.html deleted file mode 100644 index fe5806168f..0000000000 --- a/files/zh-cn/mozilla/tech/xpcom/guide/internal_strings/index.html +++ /dev/null @@ -1,809 +0,0 @@ ---- -title: Strings -slug: Mozilla/Tech/XPCOM/Guide/Internal_strings -tags: - - XPCOM - - 所有分类 -translation_of: Mozilla/Tech/XPCOM/Guide/Internal_strings ---- -<p> </p> -<h2 id="Preface" name="Preface">Preface</h2> -<div> - <p>by Alec Flett<br> - Thanks to David Baron for <a class="external" href="http://dbaron.org/mozilla/coding-practices">actual docs</a>,<br> - Peter Annema for lots of direction,<br> - Myk Melez for some more docs, and<br> - David Bradley for a diagram<br> - Revised by Darin Fisher for Mozilla 1.7<br> - Revised by Jungshik Shin to clarify character encoding issues</p> -</div> -<p>This guide will attempt to document the plethora of string classes, and hopefully provide an answer to the age old question, "what string class should I use here?"</p> -<div style="border: solid thin steelblue; padding: 0.5em;"> - <p>If you are a Mozilla embedder or if you are writing an XPCOM component that will be distributed separately from the Mozilla code base, then this string guide is most likely not for you! Provided you are developing against Mozilla 1.7 or later, you should instead be using the new minimal <a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsStringAPI.h" rel="custom">Mozilla string API</a> and in particular the <a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/string/public/nsEmbedString.h" rel="custom">nsEmbedString</a> class.</p> -</div> -<p>In a hurry? Go check out the <a href="cn/XPCOM/String_Quick_Reference">String Quick-Reference</a> (<a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">). </a></p> -<h2 id="Introduction" name="Introduction"><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">Introduction </a></h2> -<p><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">The string classes are a library of C++ classes which are used to manage buffers of unicode and single-byte character strings. They reside in the mozilla codebase in the <code></code></a><code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/string" rel="custom">xpcom/string</a></code> directory. </p> -<p><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">Abstract (interface) classes begin with "nsA" and concrete classes simply begin with "ns". Classes with a "<code>CString</code>" in the name store 8-bit bytes (<code>char</code>'s) which may refer to single byte ASCII strings, or multibyte Unicode strings encoded in UTF-8 or a (multibyte or single byte) legacy character encoding (e.g. ISO-8859-1, Shift_JIS, GB2312, KOI8-R). All other classes simply have "<code>String</code>" in their name and refer to 16-bit strings made up of <code>PRUnichar</code>'s, For example: <code>nsAString</code> is an abstract class for storing Unicode characters in UTF-16 encoding, and <code>nsDependentCString</code> is a concrete class which stores a 8-bit string. Every 16-bit string class has an equivalent 8-bit string class. For example: <code>nsCString</code> is the 8-bit string class which corresponds to <code>nsString</code>. </a></p> -<p><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">8-bit and 16-bit string classes have completely separate base classes, but share the same APIs. As a result, you cannot assign a 8-bit string to a 16-bit string without some kind of conversion helper class or routine. For the purpose of this document, we will refer to the 16-bit string classes in class documentation. It is safe to assume that every 16-bit class has an equivalent 8-bit class. </a></p> -<h2 id="String_Guidelines" name="String_Guidelines"><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">String Guidelines </a></h2> -<p><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">Follow these simple rules in your code to keep your fellow developers, reviewers, and users happy. </a></p> -<ul> - <li><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">Avoid </a><code><a href="#Unicode_Conversion_ns.2ACString_vs._ns.2AString">*WithConversion</a></code> functions at all costs: <code>AssignWithConversion</code>, <code>AppendWithConversion</code>, <code>EqualsWithConversion</code>, etc</li> - <li>Use the most abstract string class that you can. Usually this is: - <ul> - <li><code><a href="#The_Abstract_Classes">nsAString</a></code> for function parameters</li> - <li><code><a href="#The_Concrete_Classes_-_which_classes_to_use_when">nsString</a></code> for member variables</li> - <li><a href="#The_Concrete_Classes_-_which_classes_to_use_when"><code>nsAutoString</code> or <code>nsXPIDLString</code></a> for local (stack-based) variables</li> - </ul> - </li> - <li>Use <a href="#Literal_Strings"><code>NS_LITERAL_[C]STRING</code> / <code>NS_NAMED_LITERAL_[C]STRING</code></a> to represent literal strings (i.e. "foo") as nsAString-compatible objects.</li> - <li>Use <a href="#String_Concatenation">string concatenation</a> (i.e. the "+" operator) when combining strings.</li> - <li>Use <code><a href="#Raw_Character_Pointers">nsDependentString</a></code> when you have a raw character pointer that you need to convert to an nsAString-compatible string.</li> - <li>Use <code><a href="#Substrings_.28string_fragments.29">Substring()</a></code> to extract fragments of existing strings.</li> - <li>Use <a href="#Iterators">iterators</a> to parse and extract string fragments.</li> -</ul> -<h2 id="The_Abstract_Classes" name="The_Abstract_Classes">The Abstract Classes</h2> -<p>Every string class derives from <code>nsAString</code> (or <code>nsACString</code>). This class provides the fundamental interface for access and manipulation of strings. While concrete classes derive from <code>nsAString</code>, <code>nsAString</code> itself cannot be instantiated.</p> -<p>This is very similar to the idea of an "interface" that mozilla uses to describe abstract object descriptions in the rest of the codebase. In the case of interfaces, class names begin with "nsI" where "I" refers to "Interface". In the case of strings, abstract classes begin with "nsA" and the "A" means "Abstract".</p> -<p>There are a number of abstract classes which derive from <code>nsAString</code>. These abstract subclasses also cannot be instantiated, but they describe a string in slightly more detail than <code>nsAString</code>. They guarantee that the underlying implementation behind the abstract class provides specific capabilities above and beyond <code>nsAString</code>.</p> -<p>The list below describes the main base classes. Once you are familiar with them, see the appendix describing What Class to Use When.</p> -<ul> - <li><b><code>nsAString</code></b>: the abstract base class for all strings. It provides an API for assignment, individual character access, basic manipulation of characters in the string, and string comparison. This class corresponds to the XPIDL <code>AString</code> parameter type.</li> - <li><b><code>nsSubstring</code></b>: the common base class for all of the string classes. Provides optimized access to data within the string. A <code>nsSubstring</code> is not necessarily null-terminated. (For backwards compatibility, <code>nsASingleFragmentString</code> is a typedef for this string class.)</li> - <li><b><code>nsString</code></b>: builds on <code>nsSubstring</code> by guaranteeing a null-terminated storage. This allows for a method (<code>.get()</code>) to access the underlying character buffer. (For backwards compatibility, <code>nsAFlatString</code> is a typedef for this string class.)</li> -</ul> -<p>The remainder of the string classes inherit from either <code>nsSubstring</code> or <code>nsString</code>. Thus, every string class is compatible with <code>nsAString</code>.</p> -<p>It's important to note that <code>nsSubstring</code> and <code>nsAString</code> both represent a contiguous array of characters that are not necessarily null-terminated. One might ask then ask why two different yet similar string classes need to exist. Well, <code>nsSubstring</code> exists primarily as an optimization since <code>nsAString</code> must retain binary compatibility with the frozen <code>nsAString</code> class that shipped with Mozilla 1.0. Up until the release of Mozilla 1.7, <code>nsAString</code> was capable of representing a string broken into multiple fragments. The cost associated with supporting multi-fragment strings was high and offered limited benefits. It was decided to eliminate support for multi-fragment strings in an effort to reduce the complexity of the string classes and improve performance. See <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=231995" title='FIXED: Exploring nsAString "defragmentation"'>bug 231995</a> for more details.</p> -<p>Though <code>nsSubstring</code> provides a more efficient interface to its underlying buffer than <code>nsAString</code>, <code>nsAString</code> is still the most commonly used class for parameter passing. This is because it is the string class corresponding to <code>AString</code> in XPIDL. Therefore, this string guide will continue to discuss the string classes with an emphasis on <code>nsAString</code>.</p> -<p>Since every string derives from <code>nsAString</code> (or <code>nsACString</code>), they all share a simple API. Common read-only methods:</p> -<ul> - <li><b><code>.Length()</code></b> - the number of code units (bytes for 8-bit string classes and PRUnichar's for 16-bit string classes) in the string.</li> - <li><b><code>.IsEmpty()</code></b> - the fastest way of determining if the string has any value. Use this instead of testing <code>string.Length</code> == 0</li> - <li><b><code>.Equals(string)</code></b> - TRUE if the given string has the same value as the current string.</li> -</ul> -<p>Common methods that modify the string:</p> -<ul> - <li><b><code>.Assign(string)</code></b> - Assigns a new value to the string.</li> - <li><b><code>.Append(string)</code></b> - Appends a value to the string.</li> - <li><b><code>.Insert(string, position)</code></b> - Inserts the given string before the code unit at position.</li> - <li><b><code>.Truncate(length)</code></b> - shortens the string to the given length.</li> -</ul> -<p>Complete documentation can be found in the <a href="#Appendix_B_-_nsAString_Reference">Appendix</a>.</p> -<h3 id="Read-only_strings" name="Read-only_strings">Read-only strings</h3> -<p>The <code>const</code> attribute on a string determines if the string is writable. If a string is defined as a <code>const nsAString</code> then the data in the string cannot be manipulated. If one tries to call a non-<code>const</code> method on a <code>const</code> string the compiler will flag this as an error at build time.</p> -<p>For example:</p> -<pre class="eval">void nsFoo::ReverseCharacters(nsAString& str) { - ... - str.Assign(reversedStr); // modifies the string -} -</pre> -<p>This should not compile, because you're assigning to a <code>const</code> class:</p> -<pre class="eval">void nsFoo::ReverseCharacters(const nsAString& str) { - ... - <b>str.Assign(reversedStr);</b> -} -</pre> -<h3 id="As_function_parameters" name="As_function_parameters">As function parameters</h3> -<p>It is recommended that you use the most abstract interface possible as a function parameter, instead of using concrete classes. The convention is to use C++ references (the '&' character) instead of pointers (the '*' character) when passing string references around. For example:</p> -<pre class="eval">// abstract reference -nsFoo::PrintString(<b>const nsAString&</b> str) {..} - -// using a concrete class! -nsFoo::PrintString(<b>const nsString&</b> str) {..} - -// using a pointer! -nsFoo::PrintString(<b>const nsAString*</b> str) {..} -</pre> -<p>The abstract classes are also sometimes used to store temporary references to objects. You can see both of these uses in <a href="#Common_Patterns">Common Patterns</a>, below.</p> -<p><b>NOTE:</b> While using abstract string classes increases the re-usability of your methods, it also incurs a codesize and performance penalty. Therefore, when writing methods that will only ever be used within the confines of your source file or module, it is better to use <b><code>const nsSubstring&</code></b> for input parameters and <b><code>nsString&</code></b> for output parameters. --Darin</p> -<h2 id="The_Concrete_Classes_-_which_classes_to_use_when" name="The_Concrete_Classes_-_which_classes_to_use_when">The Concrete Classes - which classes to use when</h2> -<p>The concrete classes are for use in code that actually needs to store string data. The most common uses of the concrete classes are as local variables, and members in classes or structs. Whereas the abstract classes differ in storage mechansim, for the most part the concrete classes differ in storage policy.</p> -<p>The following is a list of the most common concrete classes. Once you are familiar with them, see the appendix describing <a href="#Appendix_A_-_What_class_to_use_when">What Class to Use When.</a></p> -<ul> - <li><code><b>nsString / nsCString</b></code>- a null-terminated string whose buffer is allocated on the heap. Destroys its buffer when the string object goes away.</li> - <li><code><b>nsAutoString / nsCAutoString</b></code>- derived from <code>nsString</code>, a string which owns a 64 code unit buffer in the same storage space as the string itself. If a string less than 64 code units is assigned to an <code>nsAutoString</code>, then no extra storage will be allocated. For larger strings, a new buffer is allocated on the heap.</li> - <li><code><b>nsXPIDLString / nsXPIDLCString</b></code>- derived from <code>nsString</code>, this class supports the <code>getter_Copies()</code> operator which allows easy access to XPIDL <code>out wstring / string</code> parameters. This class also supports the notion of a null-valued buffer, whereas <code>nsString</code>'s buffer is never null.</li> - <li><code><b>nsDependentString</b></code>- derived from <code>nsString</code>, this string does - <i> - not</i> - own its buffer. It is useful for converting a raw string (<code>const PRUnichar*</code> or <code>const char*</code>) into a class of type <code>nsAString</code>.</li> - <li><code><b>nsPrintfCString</b></code>- derived from <code>nsCString</code>, this string behaves like an <code>nsCAutoString</code>. The constructor takes parameters which allows it to construct a 8-bit string from a <code>printf</code>-style format string and parameter list.</li> - <li><code><b>NS_LITERAL_STRING/NS_NAMED_LITERAL_STRING</b></code>- these convert a literal string (such as "abc") to a <code>nsString</code> or a subclass of <code>nsString</code>. On platforms supporting double-byte string literals (e.g., MSVC++ or GCC with the -fshort-wchar option), these are simply macros around the <code>nsDependentString</code> class. They are slightly faster than just wrapping them with an <code>nsDependentString</code> because they use the compiler to calculate their length, and they also hide the messy cross-platform details of non-byte literal strings.</li> -</ul> -<p>There are also a number of concrete classes that are created as a side-effect of helper routines, etc. You should avoid direct use of these classes. Let the string library create the class for you.</p> -<ul> - <li><code><b>nsSubstringTuple</b></code> - created via <a href="#String_Concatenation">string concatenation</a></li> - <li><code><b>nsDependentSubstring</b></code> - created through <a href="#Substrings_.28string_fragments.29">Substring</a></li> - <li><code><b>nsPromiseFlatString</b></code> - created through <code><b><a href="#Raw_Character_Pointers">PromiseFlatString()</a></b></code></li> -</ul> -<p>Of course, there are times when it is necessary to reference these string classes in your code, but as a general rule they should be avoided.</p> -<h2 id="Iterators" name="Iterators">Iterators</h2> -<p>Iterators are objects that retain a reference to a position in a string. In some ways they are like a number which refers to an index in an array, or a character-pointer that refers to a position in a character string. They also provide a syntactic means to distinguish between reading and writing to a string.</p> -<p>Iterators are most often used to extract substrings of a string. They provide the capability to modify the contents of a string, but often helper routines, or the string's own methods are quicker at complex string transformations.</p> -<p>Iterators are declared from the string class which they are iterating:</p> -<pre class="eval">nsAString::const_iterator start, end; // reading-only iterators for nsAString -nsString::iterator substr_start, substr_end; // writing iterators for nsString -</pre> -<p>Iterators are initialized with one of 4 methods on the string you wish to reference:</p> -<pre class="eval">// let's read from 'str' -str.BeginReading(start); // initialize 'start' to the beginning of 'str' -str.EndReading(end); // 'end' will be at the end of the string - -// say we also want to write to 'url' -url.BeginWriting(substr_start); -url.EndWriting(substr_end); -</pre> -<p>You can access the code unit that an iterator points to with the dereference operator *.</p> -<pre class="eval">if (*start == '[') - printf("Starts with a bracket\n"); -</pre> -<p>Note in the above examples, that '<code>end</code>' and '<code>substr_end</code>' will actually point to the code unit past the end of the string, so you should never dereference the direct result of <code>.EndReading()</code>.</p> -<p>You can test if two iterators point to the same position with == or !=. You can advance iterators with ++. Putting the ++ before your iterator is preferred, and will prevent creation of a temporary iterator.</p> -<pre class="eval">while (start != end) // iterate through the whole string - ++start; -</pre> -<p>You can effectively write to a string with writing iterators (as opposed to const-iterators):</p> -<pre class="eval">// change all * to ! -while (substr_start != substr_end) { - if (*substr_start == '*') - *substr_start = '!'; - ++substr_start; -} -</pre> -<p>With the patch for <a class="external" href="http://bugzilla.mozilla.org/show_bug.cgi?id=231995">bug 231995</a>, this loop is now as efficient as iterating with raw character pointers.</p> -<h2 id="Helper_Classes_and_Functions" name="Helper_Classes_and_Functions">Helper Classes and Functions</h2> -<h3 id="Searching_strings_-_looking_for_substrings.2C_characters.2C_etc." name="Searching_strings_-_looking_for_substrings.2C_characters.2C_etc.">Searching strings - looking for substrings, characters, etc.</h3> -<p><code>FindInReadable()</code> is the replacement for the old <code>string.Find(..)</code>. The syntax is:</p> -<pre class="eval">PRBool FindInReadable(const nsAString& pattern, - nsAString::const_iterator start, nsAString::const_iterator end, - nsStringComparator& aComparator = nsDefaultStringComparator()); -</pre> -<p>To use this, <code>start</code> and <code>end</code> should point to the beginning and end of a string that you would like to search. If the search string is found, <code>start</code> and <code>end</code> will be adjusted to point to the beginning and end of the found pattern. The return value is PR_TRUE or PR_FALSE, indicating whether or not the string was found.</p> -<p>An example:</p> -<pre class="eval">const nsAString& str = GetSomeString(); -nsAString::const_iterator start, end; - -str.BeginReading(start); -str.EndReading(end); - -NS_NAMED_LITERAL_STRING(valuePrefix, "value="); - -if (FindInReadable(valuePrefix, start, end)) { - // end now points to the character after the pattern - valueStart = end; - -} -</pre> -<h3 id="Memory_Allocation_-_how_to_avoid_it.2C_which_methods_to_use" name="Memory_Allocation_-_how_to_avoid_it.2C_which_methods_to_use">Memory Allocation - how to avoid it, which methods to use</h3> -<p>The preferred method to allocate a new character buffer (<code>PRUnichar*</code>/<code>char*</code>) from an existing string is with one of the following methods:</p> -<ul> - <li><code><b>PRUnichar* ToNewUnicode( - <i> - nsAString&</i> - )</b></code> - Allocates a <code>PRUnichar*</code>buffer from an <code>nsAString</code>.</li> - <li><code><b>char *ToNewCString( - <i> - nsACString&</i> - )</b></code> - Allocates a <code>char*</code>buffer from an <code>nsACString</code>. Note that this method will also work on nsAStrings, but it will do an implicit <a href="#Lossy_Conversion">lossy conversion</a>. This function should only be used if the input is known to be strictly ASCII. Often a conversion to UTF-8 is more appropriate. See <code><b>ToNewUTF8String</b></code> below.</li> - <li><code><b>char* ToNewUTF8String( - <i> - nsAString&</i> - )</b></code> - Allocates a new <code>char*</code> buffer containing the UTF-8 encoded version of the given nsAString. See <a href="#Unicode_Conversion_ns.2ACString_vs._ns.2AString">Unicode Conversion</a> for more details.</li> -</ul> -<p>These methods return a buffer allocated using XPCOM's allocator (<code>nsMemory::Alloc</code>) instead of the traditional allocator (<code>malloc</code>, etc.). You should use <code>nsMemory::Free</code> to deallocate the result when you no longer need it.</p> -<h3 id="Substrings_.28string_fragments.29" name="Substrings_.28string_fragments.29">Substrings (string fragments)</h3> -<p>It is very simple to refer to a substring of an existing string without actually allocating new space and copying the characters into that substring. <code>Substring()</code> is the preferred method to create a reference to such a string.</p> -<pre class="eval">void ProcessString(const nsAString& str) { - const nsAString& firstFive = Substring(str, 0, 5); - // firstFive is now a string representing the first 5 characters -} -</pre> -<h2 id="Unicode_Conversion_ns.2ACString_vs._ns.2AString" name="Unicode_Conversion_ns.2ACString_vs._ns.2AString">Unicode Conversion ns*CString vs. ns*String</h2> -<p>Strings can be - <i> - stored</i> - in two basic formats: 8-bit code unit (byte/<code>char</code>) strings, or 16-bit code unit (<code>PRUnichar</code>) strings. Any string class with a capital "C" in the classname contains 8-bit bytes. These classes include <code>nsCString</code>, <code>nsDependentCString</code>, and so forth. Any string class - <i> - without</i> - the "C" contains 16-bit code units.</p> -<p>A 8-bit string can be in one of many character encodings while a 16-bit string is always in UTF-16. The most common encodings are:</p> -<ul> - <li>ASCII - 8-bit encoding for basic English-only strings. Each ASCII value is stored in exactly one byte in the array.</li> - <li><a class="external" href="http://www.unicode.org/glossary/#UCS_2">UCS2</a> - 16-bit encoding for a - <i> - subset</i> - of Unicode, <a class="external" href="http://www.unicode.org/glossary/#BMP">BMP</a>. The Unicode value of a character stored in UCS2 is stored in exactly one 16-bit <code>PRUnichar</code> in a string class.</li> - <li><a class="external" href="http://www.faqs.org/rfcs/rfc3629.html">UTF-8</a> - 8-bit encoding for Unicode characters. Each Unicode characters is stored in up to 4 bytes in a string class. UTF-8 is capable of representing the entire Unicode character repertoire, and it efficiently maps to <a class="external" href="http://www.unicode.org/glossary/#UTF_32">UTF-32</a>.</li> - <li><a class="external" href="http://www.unicode.org/glossary/#UTF_16">UTF-16</a> - 16-bit encoding for Unicode storage, backwards compatible with UCS2. The Unicode value of a character stored in UTF-16 may require - <i> - one or two</i> - 16-bit <code>PRUnichar</code>s in a string class. The contents of <code>nsAString</code> always has to be regarded as in this encoding instead of UCS2. UTF-16 is capable of representing the entire Unicode character repertoire, and it efficiently maps to UTF-32. (Win32 W APIs and Mac OS X natively use UTF-16.)</li> -</ul> -<p>In addition, there are literally hundreds of encodings that are provided by internationalization libraries. Access to these libraries may be part of the application (such as <code>nsICharsetConversionManager</code> in Mozilla) or built into the operating system (such as <code>iconv()</code> in UNIX operating systems and <code>MultiByteToWideChar</code>/<code>WideCharToMultiByte</code> on Windows).</p> -<p>When working with existing code, it is important to examine the current usage of the strings that you are manipulating, to determine the correct conversion mechanism.</p> -<p>When writing new code, it can be confusing to know which storage class and encoding is the most appropriate. There is no single answer to this question, but there are a few important guidelines:</p> -<ul> - <li><b>Is the string always ASCII?</b> First and foremost, you need to determine what kinds of values will be stored in the string. If the strings are always internal, ASCII strings such as "left", "true", "background" and so forth, then straight C-strings are probably the way to go.</li> - <li><b>If the string is ASCII, will it be compared to, assigned to, or otherwise interact with non-ASCII strings?</b> When assigning or comparing an 8-bit ASCII value (in)to a 16-bit UCS2 string, an "inflation" needs to happen at runtime. If your strings are small enough (say, less than 64 bytes) then it may make sense to store your string in a 16-bit unicode class as well, to avoid the extra conversion. The tradeoff is that your ASCII string takes up twice as much space as a 16-bit Unicode string than it would as an 8-bit string.</li> - <li><b>Is the string usually ASCII, but needs to support unicode?</b> If your string is most often ASCII but needs to be able to store Unicode characters, then UTF-8 may be the right encoding. ASCII characters will still be stored in 8-bit storage but other Unicode characters will take up 2 to 4 bytes. However if the string ever needs to be compared or assigned to a 16-bit string, a runtime conversion will be necessary.</li> - <li><b>Are you storing large strings of non-ASCII data?</b> Up until this point, UTF-8 might seem like the ideal encoding. The drawback is that for most non-European characters (such as Chinese, Indian and Japanese) in BMP, UTF-8 takes 50% more space than UTF-16. For characters in plane 1 and above, both UTF-8 and UTF-16 take 4 bytes.</li> - <li><b>Do you need to manipulate the contents of a Unicode string?</b> One problem with encoding Unicode characters in UTF-8 or other 8-bit storage formats is that the actual Unicode character can span multiple bytes in a string. In most encodings, the actual number of bytes varies from character to character. When you need to iterate over each character, you must take the encoding into account. This is vastly simplified when iterating 16-bit strings because each 16-bit code unit (<code>PRUnichar</code>) corresponds to a Unicode character as long as all characters are in BMP, which is often the case. However, you have to keep in mind that a single Unicode character in plane 1 and beyond is represented in two 16-bit code units in 16-bit strings so that the number of <code>PRUnichar</code>'s is - <i> - not</i> - always equal to the number of Unicode characters. For the same reason, the position and the index in terms of 16-bit code units are not always the same as the position and the index in terms of Unicode characters.</li> -</ul> -<p><br> - To assist with ASCII, UTF-8, and UTF-16 conversions, there are some helper methods and classes. Some of these classes look like functions, because they are most often used as temporary objects on the stack.</p> -<h3 id="UTF-8_.2F_UTF-16_conversion" name="UTF-8_.2F_UTF-16_conversion">UTF-8 / UTF-16 conversion</h3> -<p><code><b>NS_ConvertUTF8toUTF16( - <i> - const nsACString&</i> - )</b></code> - a <code>nsAutoString</code> subclass that converts a UTF-8 encoded <code>nsACString</code> or <code>const char*</code> to a 16-bit UTF-16 string. If you need a <code>const PRUnichar*</code> buffer, you can use the <code>.get()</code> method. For example:</p> -<pre class="eval">/* signature: void HandleUnicodeString(const nsAString& str); */ -object->HandleUnicodeString(<b>NS_ConvertUTF8toUTF16</b>(utf8String)); - -/* signature: void HandleUnicodeBuffer(const PRUnichar* str); */ -object->HandleUnicodeBuffer(<b>NS_ConvertUTF8toUTF16</b>(utf8String).get()); -</pre> -<p><code><b>NS_ConvertUTF16toUTF8( - <i> - const nsAString&</i> - )</b></code> - a <code>nsCAutoString</code> which converts a 16-bit UTF-16 string (<code>nsAString</code>) to a UTF-8 encoded string. As above, you can use <code>.get()</code> to access a <code>const char*</code> buffer.</p> -<pre class="eval">/* signature: void HandleUTF8String(const nsACString& str); */ -object->HandleUTF8String(<b>NS_ConvertUTF16toUTF8</b>(utf16String)); - -/* signature: void HandleUTF8Buffer(const char* str); */ -object->HandleUTF8Buffer(<b>NS_ConvertUTF16toUTF8</b>(utf16String).get()); -</pre> -<p><code><b>CopyUTF8toUTF16( - <i> - const nsACString&, nsAString&</i> - )</b></code> - converts and copies:</p> -<pre class="eval">// return a UTF-16 value -void Foo::GetUnicodeValue(nsAString& result) { - <b>CopyUTF8toUTF16</b>(mLocalUTF8Value, result); - } -</pre> -<p><code><b>AppendUTF8toUTF16( - <i> - const nsACString&, nsAString&</i> - )</b></code> - converts and appends:</p> -<pre class="eval">// return a UTF-16 value -void Foo::GetUnicodeValue(nsAString& result) { - result.AssignLiteral("prefix:"); - <b>AppendUTF8toUTF16</b>(mLocalUTF8Value, result); -} -</pre> -<p><br> - <code><b>UTF8ToNewUnicode( - <i> - const nsACString&, PRUint32* aUTF16Count = nsnull</i> - )</b></code> - allocates and converts (the optional parameter will contain the number of 16-byte units upon return, if non-null):</p> -<pre class="eval">void Foo::GetUTF16Value(PRUnichar** result) { - *result = <b>UTF8ToNewUnicode</b>(mLocalUTF8Value); -} -</pre> -<p><br> - <code><b>CopyUTF16toUTF8( - <i> - const nsAString&, nsACString&</i> - )</b></code> - converts and copies:</p> -<pre class="eval">// return a UTF-8 value -void Foo::GetUTF8Value(nsACString& result) { - <b>CopyUTF16toUTF8</b>(mLocalUTF16Value, result); -} -</pre> -<p><code><b>AppendUTF16toUTF8( - <i> - const nsAString&, nsACString&</i> - )</b></code> - converts and appends:</p> -<pre class="eval">// return a UTF-8 value -void Foo::GetUnicodeValue(nsACString& result) { - result.AssignLiteral("prefix:"); - <b>AppendUTF16toUTF8</b>(mLocalUTF16Value, result); -} -</pre> -<p><code><b>ToNewUTF8String( - <i> - const nsAString&</i> - )</b></code> - allocates and converts:</p> -<pre class="eval">void Foo::GetUTF8Value(char** result) { - *result = <b>ToNewUTF8String</b>(mLocalUTF16Value); -} -</pre> -<h3 id="Lossy_Conversion" name="Lossy_Conversion">Lossy Conversion</h3> -<p>The following should only be used when you can guarantee that the original string is ASCII. These helpers are very similar to the UTF-8 / UTF-16 conversion helpers above.</p> -<h4 id="UTF-16_to_ASCII_converters" name="UTF-16_to_ASCII_converters">UTF-16 to ASCII converters</h4> -<p>These converters are - <i> - <b>very dangerous</b></i> - because they - <i> - <b>lose information</b></i> - during the conversion process. You should - <i> - <b>avoid UTF-16 to ASCII conversions</b></i> - unless your strings are guaranteed to be ASCII. Each 16-bit code unit in 16-bit string is simply cast to an 8-bit byte, which means all Unicode character values above 0xFF are converted to an arbitrary 8-bit byte.</p> -<ul> - <li><code><b>NS_LossyConvertUTF16toASCII( - <i> - nsAString</i> - )</b></code> - a <code>nsCAutoString</code> which holds a temporary buffer containing the deflated value of the string.</li> - <li><code><b>LossyCopyUTF16toASCII( - <i> - nsAString, nsACString</i> - )</b></code> - does an in-place conversion from UTF-16 into an ASCII string object.</li> - <li><code><b>LossyAppendUTF16toASCII( - <i> - nsAString, nsACString</i> - )</b></code> - appends an UTF-16 string to an ASCII string, losing non-ASCII values.</li> - <li><code><b>ToNewCString( - <i> - nsAString</i> - )</b></code> - allocates a new <code>char*</code> string.</li> -</ul> -<h4 id="ASCII_to_UTF-16_converters" name="ASCII_to_UTF-16_converters">ASCII to UTF-16 converters</h4> -<p>These converters are - <i> - <b>very dangerous</b></i> - because they will - <i> - <b>mangle any non-ASCII string</b></i> - into a meaningless UTF-16 string. You should - <i> - <b>avoid ASCII to UTF-16 conversions</b></i> - unless your strings are guaranteed to be ASCII. For instance, if you have an 8-bit string encoded in a multibyte character encoding, each byte of the string will be "inflated" to a 16-bit number by simple casting.</p> -<p>For example, imagine a UTF-8 string where the first Unicode character of the string is represented with a 3-byte UTF-8 sequence, the "inflated" UTF-16 string will contain the 3 <code>PRUnichar</code>'s instead of the single <code>PRUnichar</code> that represents the first character. These <code>PRUnichar</code>'s have nothing to do with the first Unicode character in the UTF-8 string.</p> -<ul> - <li><code><b>NS_ConvertASCIItoUTF16( - <i> - nsACString</i> - )</b></code> - a <code>nsAutoString</code> which holds a temporary buffer containing the inflated value of the string.</li> - <li><code><b>CopyASCIItoUTF16( - <i> - nsACString, nsAString</i> - )</b></code> - does an in-place conversion from one string into a Unicode string object.</li> - <li><code><b>AppendASCIItoUTF16( - <i> - nsACString, nsAString</i> - )</b></code> - appends an ASCII string to a Unicode string.</li> - <li><code><b>ToNewUnicode( - <i> - nsACString</i> - )</b></code> - Creates a new <code>PRUnichar*</code> string which contains the inflated value.</li> -</ul> -<h2 id="Common_Patterns" name="Common_Patterns">Common Patterns</h2> -<h3 id="Callee-allocated_Parameters" name="Callee-allocated_Parameters">Callee-allocated Parameters</h3> -<p>Many APIs result in a method allocating a buffer in order to return strings to its caller. This can be tricky because the caller has to remember to free the string when they have finished using it. Fortunately, the <code>nsXPIDLString</code> class makes this very easy.</p> -<p>A method may look like this:</p> -<pre class="eval">void GetValue(PRUnichar** aValue) -{ - *aValue = ToNewUnicode(foo); -} -</pre> -<p>Without the string classes, the caller would need to free the string:</p> -<pre>{ - PRUnichar* val; - GetValue(&val); - - if (someCondition) { - // don't forget to free the value! - nsMemory::Free(val); - return NS_ERROR_FAILURE; - } - - ... - // and later, still don't forget to free! - nsMemory::Free(val); -} -</pre> -<p>With <code>nsXPIDLString</code> you never have to worry about this. You can just use <code>getter_Copies()</code> to wrap the string class, and the class will remember to free the buffer when it goes out of scope:</p> -<pre>{ - nsXPIDLString val; - GetValue(getter_Copies(val)); - - // val will free itself here - if (someCondition) - return NS_ERROR_FAILURE; - ... - // and later, still nothing to free -} -</pre> -<p>The resulting code is much simpler, and easy to read.</p> -<h3 id="Literal_Strings" name="Literal_Strings">Literal Strings</h3> -<p>A - <i> - literal string</i> - is a raw string value that is written in some C++ code. For example, in the statement <code>printf("Hello World\n");</code> the value <code>"Hello World\n"</code> is a literal string. It is often necessary to insert literal string values when an <code>nsAString</code> or <code>nsACString</code> is required. These four macros will provide you with the necessary conversion:</p> -<ul> - <li><code><b>NS_LITERAL_CSTRING( - <i> - literal string</i> - )</b></code> - a temporary <code>nsCString</code></li> - <li><code><b>NS_NAMED_LITERAL_CSTRING( - <i> - variable,literal string</i> - )</b></code> - declares a <code>nsCString</code> variable named - <i> - variable</i> - </li> - <li><code><b>NS_LITERAL_STRING( - <i> - literal string</i> - )</b></code> - a temporary <code>nsString</code> with the unicode version of - <i> - literal string</i> - </li> - <li><code><b>NS_NAMED_LITERAL_STRING( - <i> - variable,literal string</i> - )</b></code> - declares a <code>nsString</code> variable named - <i> - variable</i> - with the unicode version of - <i> - literal string</i> - </li> -</ul> -<p>The purpose of the <code>CSTRING</code> versions of these macros may seem unnecessary, given that <code>nsDependentCString</code> will also wrap a string value in an <code>nsCString</code>. The advantage to these macros is that the length of these strings is calculated at compile time, so the string does not need to be scanned at runtime to determine its length.</p> -<p>The <code>STRING</code> versions of these macros provide a portable way of declaring UTF-16 versions of the given literal string, avoiding runtime conversion on platforms which support literal UTF-16 strings (e.g., MSVC++ and GCC with the -fshort-wchar option).</p> -<pre>// call Init(const PRUnichar*) -Init(L"start value"); // bad - L"..." is not portable! -Init(NS_ConvertASCIItoUTF16("start value").get()); // bad - runtime ASCII->UTF-16 conversion! - -// call Init(const nsAString&) -Init(nsDependentString(L"start value")); // bad - not portable! -Init(NS_ConvertASCIItoUTF16("start value")); // bad - runtime ASCII->UTF-16 conversion! - -// call Init(const nsACString&) -Init(nsDependentCString("start value")); // bad - length determined at runtime -</pre> -<p>Here are some examples of proper <code>NS_LITERAL_[C]STRING</code> usage.</p> -<pre>// call Init(const PRUnichar*) -Init(NS_LITERAL_STRING("start value").get()); - -// call Init(const nsAString&) -Init(NS_LITERAL_STRING("start value")); - -// call Init(const nsACString&) -Init(NS_LITERAL_CSTRING("start value")); -</pre> -<p>There are a few details which can be useful in tracking down issues with these macros:</p> -<p><code>NS_LITERAL_STRING</code> does compile-time conversion to UTF-16 on some platforms (e.g. Windows, Linux, and Mac) but does runtime conversion on other platforms. By using <code>NS_LITERAL_STRING</code> your code is guaranteed to use the best possible conversion for the platform in question.</p> -<p>Because some platforms do runtime conversion, the use of literal string concatenation inside a <code>NS_LITERAL_STRING/NS_NAMED_LITERAL_STRING</code> macro will compile on these platforms, but not on platforms which support compile-time conversion.</p> -<p>For example:</p> -<pre>// call Init(nsAString&) -Init(NS_LITERAL_STRING("start " - "value")); // only compiles on some platforms -</pre> -<p>The reason for this is that on some platforms, the <code>L"..."</code> syntax is used, but it is only applied to the first string in the concatenation (<code>"start "</code>). When the compiler attempts to concatenate this with the non-Unicode string <code>"value"</code> it gets confused.</p> -<p>Also, using preprocessor macros as the string literal is unsupported:</p> -<pre>#define some_string "See Mozilla Run" -... -Init(NS_LITERAL_STRING( some_string )); // only compiles on some platforms/with some compilers. - -</pre> -<h3 id="String_Concatenation" name="String_Concatenation">String Concatenation</h3> -<p>Strings can be concatenated together using the + operator. The resulting string is a <code>const nsSubstringTuple</code> object. The resulting object can be treated and referenced similarly to a <code>nsAString</code> object. Concatenation - <i> - does not copy the substrings</i> - . The strings are only copied when the concatenation is assigned into another string object. The <code>nsSubstringTuple</code> object holds pointers to the original strings. Therefore, the <code>nsSubstringTuple</code> object is dependent on all of its substrings, meaning that their lifetime must be at least as long as the <code>nsSubstringTuple</code> object.</p> -<p>For example, you can use the value of two strings and pass their concatenation on to another function which takes an <code>const nsAString&:</code></p> -<pre class="eval">void HandleTwoStrings(const nsAString& one, const nsAString& two) { - // call HandleString(const nsAString&) - HandleString(one + two); -} -</pre> -<p>NOTE: The two strings are implicitly combined into a temporary <code>nsString</code> in this case, and the temporary string is passed into <code>HandleString</code>. If <code>HandleString</code> assigns its input into another <code>nsString</code>, then the string buffer will be shared in this case negating the cost of the intermediate temporary. You can concatenate N strings and store the result in a temporary variable:</p> -<pre class="eval">NS_NAMED_LITERAL_STRING(start, "start "); -NS_NAMED_LITERAL_STRING(middle, "middle "); -NS_NAMED_LITERAL_STRING(end, "end"); -// create a string with 3 dependent fragments - no copying involved! -nsString combinedString = start + middle + end; - -// call void HandleString(const nsAString&); -HandleString(combinedString); -</pre> -<p>If you are using <code>NS_LITERAL_STRING</code> to create a temporary that is only used once, then it is safe to define it inside a concatenation because the string buffer will live as long as the temporary concatenation object (of type <code>nsSubstringTuple</code>).</p> -<pre class="eval">// call HandlePage(const nsAString&); -// safe because the concatenated-string will live as long as its substrings -HandlePage(NS_LITERAL_STRING("start ") + NS_LITERAL_STRING("end")); -</pre> -<h3 id="Local_variables" name="Local_variables">Local variables</h3> -<p>Local variables within a function are usually stored on the stack. The <code>nsAutoString/nsCAutoString</code> classes are derivatives of the <code>nsString/nsCString classes</code>. They own a 64-character buffer allocated in the same storage space as the string itself. If the <code>nsAutoString</code> is allocated on the stack, then it has at its disposal a 64-character stack buffer. This allows the implementation to avoid allocating extra memory when dealing with small strings.</p> -<pre class="eval">... -nsAutoString value; -GetValue(value); // if the result is less than 64 code units, - // then this just saved us an allocation -... -</pre> -<h3 id="Member_variables" name="Member_variables">Member variables</h3> -<p>In general, you should use the concrete classes <code>nsString</code> and <code>nsCString</code> for member variables.</p> -<pre class="eval">class Foo { - ... - // these store UTF-8 and UTF-16 values respectively - nsCString mLocalName; - nsString mTitle; -}; -</pre> -<p>Note that the strings are declared directly in the class, not as pointers to strings. Don't do this:</p> -<pre>class Foo { -public: - Foo() { - mLocalName = new nsCString(); - mTitle = new nsString(); - } - ~Foo() { delete mLocalName; delete mTitle; } - -private: - // these store UTF-8 and UTF-16 values respectively - nsCString* mLocalName; - nsString* mTitle; -}; -</pre> -<p>The above code may appear to save the cost of the string objects, but <code>nsString/nsCString</code> are small objects - the overhead of the allocation outweighs the few bytes you'd save by keeping a pointer.</p> -<p>Another common incorrect pattern is to use <code>nsAutoString/nsCAutoString</code> for member variables. As described in <a href="#Local_variables">Local Variables</a>, these classes have a built in buffer that make them very large. This means that if you include them in a class, they bloat the class by 64 bytes (<code>nsCAutoString</code>) or 128 bytes (<code>nsAutoString</code>).</p> -<p>An example:</p> -<pre>class Foo { - ... - - // bloats 'Foo' by 128 bytes! - nsAutoString mLocalName; -}; -</pre> -<h3 id="Raw_Character_Pointers" name="Raw_Character_Pointers">Raw Character Pointers</h3> -<p><code>PromiseFlatString()</code> can be used to create a temporary buffer which holds a null-terminated buffer containing the same value as the source string. <code>PromiseFlatString()</code> will create a temporary buffer if necessary. This is most often used in order to pass an <code>nsAString</code> to an API which requires a null-terminated string.</p> -<p>In the following example, an <code>nsAString</code> is combined with a literal string, and the result is passed to an API which requires a simple character buffer.</p> -<pre class="eval">// Modify the URL and pass to AddPage(const PRUnichar* url) -void AddModifiedPage(const nsAString& url) { - NS_NAMED_LITERAL_STRING(httpPrefix, <span class="nowiki">"http://"</span>); - const nsAString& modifiedURL = httpPrefix + url; - - // creates a temporary buffer - AddPage(PromiseFlatString(modifiedURL).get()); -} -</pre> -<p><code>PromiseFlatString()</code> is smart when handed a string that is already null-terminated. It avoids creating the temporary buffer in such cases.</p> -<pre class="eval">// Modify the URL and pass to AddPage(const PRUnichar* url) -void AddModifiedPage(const nsAString& url, PRBool addPrefix) { - if (addPrefix) { - // MUST create a temporary buffer - string is multi-fragmented - NS_NAMED_LITERAL_STRING(httpPrefix, <span class="nowiki">"http://"</span>); - AddPage(PromiseFlatString(httpPrefix + modifiedURL)); - } else { - // MIGHT create a temporary buffer, does a runtime check - AddPage(PromiseFlatString(url).get()); - } -} -</pre> -<h3 id="printf_and_a_UTF-16_string" name="printf_and_a_UTF-16_string"><code>printf</code> and a UTF-16 string</h3> -<p>For debugging, it's useful to <code>printf</code> a UTF-16 string (nsString, nsAutoString, nsXPIDLString, etc). To do this usually requires converting it to an 8-bit string, because that's what printf expects. However, on Windows, the following should work:</p> -<pre class="eval">printf("%S\n", yourString.get()); -</pre> -<p>(Note: I didn't test this. Also, I'm not sure what exactly this does to non-ASCII characters, especially when they are outside the system codepage). The reason that this doesn't work on Unix is because a wchar_t, which is what %S expects, is usually 4 bytes there (even when Mozilla is compiled with -fshort-wchar, because this would require libc to be compiled with -fshort-wchar).</p> -<p>If non-ASCII characters aren't important, use:</p> -<pre class="eval">printf("%s\n", NS_LossyConvertUTF16toASCII(yourString).get()); -</pre> -<p>On platforms that use UTF-8 for console output (most Linux distributions), this works:</p> -<pre class="eval">printf("%s\n", NS_ConvertUTF16toUTF8(yourString).get()); -</pre> -<h2 id="IDL" name="IDL">IDL</h2> -<p>The string library is also available through IDL. By declaring attributes and methods using the specially defined IDL types, string classes are used as parameters to the corresponding methods.</p> -<h3 id="IDL_String_types" name="IDL_String_types">IDL String types</h3> -<p>The C++ signatures follow the abstract-type convention described above, such that all method parameters are based on the <a href="#The_Abstract_Classes">abstract classes</a>. The following table describes the purpose of each string type in IDL.</p> -<table class="standard-table"> - <tbody> - <tr> - <th class="header">IDL type</th> - <th class="header">C++ Type</th> - <th class="header">Purpose</th> - </tr> - <tr> - <td><code>string</code></td> - <td><code>char*</code></td> - <td>Raw character pointer to ASCII (7-bit) string, no string classes used. High bit is not guaranteed across XPConnect boundaries</td> - </tr> - <tr> - <td><code>wstring</code></td> - <td><code>PRUnichar*</code></td> - <td>Raw character pointer to UTF-16 string, no string classes used</td> - </tr> - <tr> - <td><code>AString</code></td> - <td><code>nsAString</code></td> - <td>UTF-16 string</td> - </tr> - <tr> - <td><code>ACString</code></td> - <td><code>nsACString</code></td> - <td>8-bit string, all bits are preserved across XPConnect boundaries</td> - </tr> - <tr> - <td><code>AUTF8String</code></td> - <td><code>nsACString</code></td> - <td>UTF-8 string - converted to UTF-16 as necessary when value is used across XPConnect boundaries</td> - </tr> - <tr> - <td><code>DOMString</code></td> - <td><code>nsAString</code></td> - <td>UTF-16 string used in the DOM. More or less the same as <code>AString</code>, but in JavaScript it has no distinction between whether the string is void or just empty. (not sure on this, looking for corrections.</td> - </tr> - </tbody> -</table> -<h3 id="C.2B.2B_Signatures" name="C.2B.2B_Signatures">C++ Signatures</h3> -<p>In IDL, <code>in</code> parameters are read-only, and the C++ signatures for <code>*String</code> parameters follows the above guidelines by using <code>const nsAString&</code> for these parameters. <code>out</code> and <code>inout</code> parameters are defined simply as <code>nsAString</code> so that the callee can write to them.</p> -<table class="standard-table"> - <tbody> - <tr> - <th class="header">IDL</th> - <th class="header">C++</th> - </tr> - <tr> - <td> - <pre class="eval"> -interface nsIFoo : nsISupports { - - attribute AString utf16String; - - - - - AUTF8String getValue(in ACString key); - -}; -</pre> - </td> - <td> - <pre class="eval"> -class nsIFoo : public nsISupports { - - NS_IMETHOD GetUtf16String(nsAString& - aResult) = 0; - NS_IMETHOD SetUtf16String(const nsAString& - aValue) = 0; - - NS_IMETHOD GetValue(const nsACString& aKey, - nsACString& aResult) = 0; -}; -</pre> - </td> - </tr> - </tbody> -</table> -<p>In the above example, <code>utf16String</code> is treated as a UTF-16 string. The implementation of <code>GetUtf16String()</code> will use <code>aResult.Assign</code> to "return" the value. In <code>SetUtf16String()</code> the value of the string can be used through a variety of methods including <a href="#Iterators">Iterators</a>, <code><a href="#Raw_Character_Pointers">PromiseFlatString</a></code>, and assignment to other strings.</p> -<p>In <code>GetValue()</code>, the first parameter, <code>aKey</code>, is treated as a raw sequence of 8-bit values. Any non-ASCII characters in <code>aKey</code> will be preserved when crossing XPConnect boundaries. The implementation of <code>GetValue()</code> will assign a UTF-8 encoded 8-bit string into <code>aResult</code>. If the <code>this</code> method is called across XPConnect boundaries, such as from a script, then the result will be decoded from UTF-8 into UTF-16 and used as a Unicode value.</p> -<h3 id="Choosing_a_string_type" name="Choosing_a_string_type">Choosing a string type</h3> -<p>It can be difficult to determine the correct string type to use for IDL. The following points should help determine the appropriate string type.</p> -<ul> - <li>Using string classes may avoid new memory allocation for <code>out</code> parameters. For example, if the caller is using an <code>nsAutoString</code> to receive the value for an <code>out</code> parameter, (defined in C++ as simply <code>nsAString&</code> then assignment of short (less than 64-characters) values to an <code>out</code> parameter will only copy the value into the <code>nsAutoString</code>'s buffer. Moreover, using the string classes allows for sharing of string buffers. In many cases, assigning from one string object to another avoids copying in favor of simply incrementing a reference count.</li> - <li><code>in</code> strings using string classes often have their length pre-calculated. This can be a performance win.</li> - <li>In cases where a raw-character buffer is required, <code>string</code> and <code>wstring</code> provide faster access than <code>PromiseFlatString</code>.</li> - <li>UTF-8 strings defined with <code>AUTF8String</code> may need to be decoded when crossing XPConnect boundaries. This can be a performance hit. On the other hand, UTF-8 strings take up less space for strings that are commonly ASCII.</li> - <li>UTF-16 strings defined with <code>wstring</code> or <code>AString</code> are fast when the unicode value is required. However, if the value is more often ASCII, then half of the storage space of the underlying string may be wasted.</li> -</ul> -<h2 id="Appendix_A_-_What_class_to_use_when" name="Appendix_A_-_What_class_to_use_when">Appendix A - What class to use when</h2> -<p>This table provides a quick reference for what classes you should be using.</p> -<table class="standard-table"> - <tbody> - <tr> - <th class="header">Context</th> - <th class="header">class</th> - <th class="header">Notes</th> - </tr> - <tr> - <td>Local Variables</td> - <td><code>nsAutoString<br> - nsCAutoString</code></td> - <td> </td> - </tr> - <tr> - <td>Class Member Variables</td> - <td><code>nsString<br> - nsCString</code></td> - <td> </td> - </tr> - <tr> - <td>Method Parameter types</td> - <td><code>nsAString<br> - nsACString</code></td> - <td>Use abstract classes for parameters. Use <code>const nsAString&</code> for "in" parameters and <code>nsAString&</code> for "out" parameters.</td> - </tr> - <tr> - <td>Retrieving "out" string/wstrings</td> - <td><code>nsXPIDLString<br> - nsXPIDLCString</code></td> - <td>Use <code>getter_Copies()</code>. Similar to <code>nsString / nsCString</code>.</td> - </tr> - <tr> - <td>Wrapping character buffers</td> - <td><code>nsDependentString<br> - nsDependentCString</code></td> - <td>Wrap <code>const char* / const PRUnichar*</code> buffers.</td> - </tr> - <tr> - <td>Literal strings</td> - <td><code>NS_LITERAL_STRING<br> - NS_LITERAL_CSTRING</code></td> - <td>Similar to <code>nsDependent[C]String</code>, but pre-calculates length at build time.</td> - </tr> - </tbody> -</table> -<h2 id="Appendix_B_-_nsAString_Reference" name="Appendix_B_-_nsAString_Reference">Appendix B - nsAString Reference</h2> -<p>Read-only methods.</p> -<ul> - <li><code><b>Length()</b></code></li> - <li><code><b>IsEmpty()</b></code></li> - <li><code><b>IsVoid()</b></code> - XPConnect will convert void nsAStrings to JavaScript <code>null</code>.</li> - <li><code><b>BeginReading( - <i> - iterator</i> - )</b></code></li> - <li><code><b>EndReading( - <i> - iterator</i> - )</b></code></li> - <li><code><b>Equals( - <i> - string[, comparator]</i> - )</b></code></li> - <li><code><b>First()</b></code></li> - <li><code><b>Last()</b></code></li> - <li><code><b>CountChar()</b></code></li> - <li><code><b>Left( - <i> - outstring, length</i> - )</b></code></li> - <li><code><b>Mid( - <i> - outstring, position, length</i> - )</b></code></li> - <li><code><b>Right( - <i> - outstring, length</i> - )</b></code></li> - <li><code><b>FindChar( - <i> - character</i> - )</b></code></li> -</ul> -<p>Methods that modify the string.</p> -<ul> - <li><code><b>Assign( - <i> - string</i> - )</b></code></li> - <li><code><b>Append( - <i> - string</i> - )</b></code></li> - <li><code><b>Insert( - <i> - string</i> - )</b></code></li> - <li><code><b>Cut( - <i> - start, length</i> - )</b></code></li> - <li><code><b>Replace( - <i> - start, length, string</i> - )</b></code></li> - <li><code><b>Truncate( - <i> - length</i> - )</b></code></li> - <li><code><b>SetIsVoid( - <i> - state</i> - )</b></code> - XPConnect will convert void nsAStrings to JavaScript <code>null</code>.</li> - <li><code><b>BeginWriting( - <i> - iterator</i> - )</b></code></li> - <li><code><b>EndWriting( - <i> - iterator</i> - )</b></code></li> - <li><code><b>SetCapacity()</b></code></li> -</ul> |
