mozilla

比较版本

开始WebLock

更改版本

修订版 283061:

由 Duwei 在 进行的修订 283061

修订版 226416:

由 Duwei 在 进行的修订 226416

标题:
开始WebLock
开始WebLock
网址缩略名:
创建_XPCOM_组件/开始WebLock
创建_XPCOM_组件/开始WebLock
标签:
XPCOM, 所有分类
内容:

修订版 283061
修订版 226416
t7    <p>t
8      {{ PreviousNext("Creating XPCOM Components:Using XPCOM Util
>ities to Make Things Easier", "Creating XPCOM Components:Finishin 
>g the Component") }} 
9    </p>
10    <p>
11      在本章,我们开始设计和实现网络锁定功能本身。我们已经建立了实现多数通用组件功能的模块(例如注册)。这章将关注实际操作网
>页锁定的功能。 
12    </p>
13    <h3 id="Getting_Called_at_Startup" name="Getting_Called_at_St
>artup"> 
14      Getting Called at Startup
15    </h3>
16    <p>
17      没有人是一个孤岛,组件也一样。你所建立的例子组件到目前为止还没有任何功能。当他被注册以后,他没做任何事情。
18    </p>
19    <p>
20      为了当某些事件发生的时候被启动或者通知到,例子组件需要挂接到Mozilla,或者覆盖一个现存组件,或者注册到一些事件上
>面。<b>WebLock</b>用后面的方式在Gecko Profile Startup发生的时候被调用。当Gecko应用启动的时 
>候,注册的组件被创建或者通过通用观察者接口被提醒<code>nsIObserver</code>。 
21    </p>
22    <p>
23      <i>Observer</i>是一些对象,他们当特定的事件发生的时候被通知。使用这种机制提供了一个相互不必了解而可以在
>对象之间传送信息的机制。 
24    </p>
25    <p>
26      通常,一个对象会通知一系列观察者。例如一个对象被创建的时候它的<code>observe</code>方法被调用,或者
>它可以注册当XPCOM关闭的时候被通知。这个接口的核心是<code>observe</code>方法。 
27    </p>
28    <pre>
29void observe(in nsISupports aSubject,  
30             in string aTopic,  
31             in wstring aData); 
32</pre>
33    <p>
34      实际上ovserver方法的参数没有什么限制。这些参数根据事件的类型变化。例如,XPCOM关闭的时候,aSubject
>和aData被定义,aTopic被定义为“xpcom-shotdown’,如果你的对象希望注册到这些事件上面,他首先要实现nsIO 
>bserver接口,一旦你完成这些,实现nsIObserverService的observer服务将会利用接口通知你的对象,如下所 
>示: 
35    </p>
36    <p>
37      {{ Block-title("The Observer Interfaces") }}
38    </p>
39    <p>
40      <img alt="Image:observation-overview.png" fileid="2630" src
>="File:cn/Media_Gallery/Observation-overview.png"> 
41    </p>
42    <p>
43      上图表现了observer服务管理了所有<code>nsIObserver</code>对象的列表. 当通知产生的时候
>,<code>nsIObserverService</code>把呼叫者从<code>NotifyObserver()</code 
>>发送出的消息传送给<code>nsIObserver</code>的<code>Observe()</code>方法。这是一个让 
>不同的类解藕的办法。<code>nsIObserver</code>是一个通用的接口,用来在两个或多个对象间传递信息,而不必定义一 
>个特定的冻结接口,它也是XPCOM建立扩展的一个方式。 
44    </p>
45    <p>
46      WebLock组件对<code>nsIObserver</code>接口的实现和对<code>nsIFactory</
>code>接口是类似的。<span class="comment">XXX what is Example 2?</span>下面 
>的例子2中,你改变一个类的定义为支持<code>nsIObserver</code>接口并且改变<code>NS_IMPL_ISU 
>POORTS1</code>,从而<code>QueryInterface</code>实现知道组件也支持<code>nsIObs 
>erver</code>。启动的时候被通知的<code>WebLock</code>类定义如下: 
47    </p>
48    <pre>
49class WebLock: public nsIObserver {
50  public:
51    WebLock();
52    virtual ~WebLock();
53 
54    NS_DECL_ISUPPORTS
55    NS_DECL_NSIOBSERVER
56};
57 
58NS_IMPL_ISUPPORTS1(WebLock, nsIObserver);
59</pre>
60    <p>
61      <code>Observe()</code>最简单的实现仅仅是比较字符串<code>aTopic</code>和对象所
>接受事件所定义的值. 如果相匹配, 你可以按照你的方式处理事件. 如果对象仅仅注册到一个消息上, 那你可以忽略字符串 <code> 
>aTopic</code> 而仅仅处理事件. 换句话说,对于对象所没有注册的事件,<code>Observe</code> 方法不 
>应该被调用。 
62    </p>
63    <pre>
64NS_IMETHODIMP
65WebLock::Observe(nsISupports *aSubject,
66                 const char *aTopic,
67                 const PRUnichar *aData)
68{
69  return NS_OK;
70}
71</pre>
72    <p>
73      从observer service来的消息可能是间接的. 直接获得来自observer service的消息的方法是初
>始化一个<code>nsIObserver</code> 对象. 大多数情况下这样是可以的,但是要注意当你通过这个消息建立组件的情 
>况. 因为组件还没有被建立,所以不存在初始化的 <code>nsIObserver</code> 对象可以用来传递给 <code> 
>nsIObserverService</code>, 组件代码在他被装载以前不能做什么. 
74    </p>
75    <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"> 
76      注册到消息
77    </h4>
78    <p>
79      <code>nsIObserverService</code> 接口有处理注册和注销一个<code>nsIObserv
>er</code>对象的方法. 这两个方法用来动态添加或者删除一个notification topic上的observer. 但是 
> <b>WebLock</b> 要被自动初始化和添加到observer service, 这就意味着需要一些数据持久化。(不管怎么 
>说, 我们需要组件在程序每次启动的时候也启动). 
80    </p>
81    <p>
82      This is where a new service that manages sets of related da
>ta comes in handy. This service, the <code>nsICategoryService</co 
>de>, is what XPCOM and Gecko embedding applications use to persis 
>t lists of <code>nsIObserver</code> components that want to have  
>startup notification. 
83    </p>
84    <p>
85      The <code>nsICategoryService</code> maintains sets of name-
>value pairs like the one below. 
86    </p>
87    <p>
88      {{ Block-title("The Category Manager") }}
89    </p>
90    <p>
91      <img alt="Image:category-manager-table.png" fileid="2653" s
>rc="File:cn/Media_Gallery/Category-manager-table.png"> 
92    </p>
93    <p>
94      Every category is identified by a string that represents th
>e name of the category. Each category contains a set of name-valu 
>e pairs. For example, you might have a category named "Important  
>People" in which the name-value pairs would be names and phone nu 
>mbers. The format of the name-value pair is left up to you. 
95    </p>
96    <p>
97      This data structure is more than enough to support the pers
>isting of components that what to be started up. The category nam 
>e 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 ex 
>actly how categories are used to handle registration with XPCOM f 
>or startup notification. You will see the code which does this in 
> the next section. 
98    </p>
99    <h4 id="Getting_Access_to_the_Category_Manager" name="Getting
>_Access_to_the_Category_Manager"> 
100      Getting Access to the Category Manager
101    </h4>
102    <p>
103      Two fields in the <code>nsModuleComponentInfo</code> struct
>ure 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 ca 
>lled. This callback allows the component to execute any one-time  
>registration code it may need. The inverse of this function is th 
>e unregistration callback, where it's a good idea to undo whateve 
>r the registration function did. The two functions look like this 
>: 
104    </p>
105    <pre>
106static NS_METHOD
107WebLockRegistration(nsIComponentManager *aCompMgr,
108                    nsIFile *aPath,
109                    const char *registryLocation,
110                    const char *componentType,
111                    const nsModuleComponentInfo *info);
112 
113static NS_METHOD
114WebLockUnregistration(nsIComponentManager *aCompMgr,
115                      nsIFile *aPath,
116                      const char *registryLocation,
117                      const nsModuleComponentInfo *info);
118</pre>
119    <p>
120      The names of the functions can be anything you wish. Both f
>unctions are passed the Component Manager and the path to the com 
>ponent, 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 fu 
>nctions are passed the <code>nsModuleComponentInfo</code> struct, 
> which is the same structure initially passed into <code>NS_IMPL_ 
>NSGETMODULE</code>. 
121    </p>
122    <p>
123      During registration, the registration callback is where you
> get the <code>nsICategoryManager</code>. Once you have it, you c 
>an add the component to the category of components that get start 
>ed automatically. As a service, the <code>nsICategoryManager</cod 
>e> is accessible via the <code>nsIServiceManager</code>. Also not 
>e that the <code>nsIComponentManager</code> is passed into the ca 
>llback. Since the object that implements the <code>nsIComponentMa 
>nager</code> interface also implements <code>nsIServiceManager</c 
>ode>, 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: 
124    </p>
125    <pre>
126nsresult rv;
127 
128nsCOMPtr&lt;nsIServiceManager&gt; servman =
129     do_QueryInterface((nsISupports*)aCompMgr, &amp;rv);
130 
131if (NS_FAILED(rv))
132  return rv;
133</pre>
134    <div class="side-note">
135      <p>
136        {{ Block-title("<code>do_QueryInterface</code>") }}
137      </p>
138      <p>
139        The previous code uses the special <code>nsCOMPtr</code> 
>function <code>do_QueryInterface</code> that lets you <code>Query 
>Interface</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 assigne 
>d into. We could have just as easily have used the raw <code>Quer 
>yInterface()</code> method, but using <code>nsCOMPtr</code> is mu 
>ch more economical (see <a href="cn/Creating_XPCOM_Components/Usi 
>ng_XPCOM_Utilities_to_Make_Things_Easier#Smart_Pointers">Smart Po 
>inters</a>). 
140      </p>
141    </div>
142    <p>
143      Once you have a <code>nsIServiceManager</code> reference, y
>ou can ask it for the service you are interested in. This process 
> is similar to using <code>CreateInstance</code> from the <code>n 
>sIComponentManager</code>, but there is no aggregation parameter  
>since the object has already been constructed. 
144    </p>
145    <pre>
146nsCOMPtr&lt;nsICategoryManager&gt; catman;
147rv = servman-&gt;GetServiceByContractID(NS_CATEGORYMANAGER_CONTRA
>CTID, 
148                                     NS_GET_IID(nsICategoryManage
>r), 
149                                     getter_AddRefs(catman));
150if (NS_FAILED(rv))
151  return rv;
152</pre>
153    <p>
154      There are two service getters on the <code>nsIServiceManage
>r</code> interface: one that takes a CID and another interface th 
>at takes a Contract ID. Here we'll use the latter. The first para 
>meter to the <code>GetServiceByContractID</code> is of course the 
> contract ID, which is defined in the <code>nsXPCOM.h</code> head 
>er file. The next parameter is a nifty macro that returns the IID 
> for the interface name that you pass in. The last parameter assi 
>gns 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>. 
155    </p>
156    <p>
157      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 s 
>ince the name-value pair meaning is category-specific, you need t 
>o figure out which category to use. 
158    </p>
159    <p>
160      There are two startup notifications, both of which create t
>he observer if it isn't already created. The first is provided by 
> XPCOM. This notification will occur during initialization of XPC 
>OM, where all XPCOM services are guaranteed to be available durin 
>g the calls. Embedding applications may provide other notificatio 
>ns. 
161    </p>
162    <p>
163      {{ Block-title("Common XPCOM Notifications") }}
164    </p>
165    <table class="standard-table">
166      <tbody>
167        <tr>
168          <td class="header">
169            Category
170          </td>
171          <td class="header">
172            Name
173          </td>
174          <td class="header">
175            Value
176          </td>
177          <td class="header">
178            Creates Component
179          </td>
180        </tr>
181        <tr>
182          <td>
183            xpcom-startup
184          </td>
185          <td>
186            Any
187          </td>
188          <td>
189            Contract ID
190          </td>
191          <td>
192            Yes
193          </td>
194        </tr>
195        <tr>
196          <td>
197            xpcom-shutdown
198          </td>
199          <td>
200            Any
201          </td>
202          <td>
203            Contract ID
204          </td>
205          <td>
206            No
207          </td>
208        </tr>
209        <tr>
210          <td>
211            xpcom-autoregistration
212          </td>
213          <td>
214            Any
215          </td>
216          <td>
217            Contract ID
218          </td>
219          <td>
220            No
221          </td>
222        </tr>
223        <tr>
224          <td>
225            app-startup
226          </td>
227          <td>
228            Any
229          </td>
230          <td>
231            service, Contract ID
232          </td>
233          <td>
234            *
235          </td>
236        </tr>
237      </tbody>
238    </table>
239    <p>
240      The table above summarizes the popular persistent notificat
>ions registered through the category manager. The name of the cat 
>egory itself is a well defined string, but the name-value pairs c 
>an be anything. 
241    </p>
242    <p>
243      When naming your component in the category, take care to us
>e something that means something and doesn't muddy up the namespa 
>ce. In this case, "WebLock" is unique and provides context to any 
>one looking at the category. The value of the name-value part is  
>expected to be the contract ID of the component. 
244    </p>
245    <p>
246      Since every category can define the name-value pairs, the a
>pplication "app-startup" category can support not only services b 
>ut component instances as well. For the app-startup notification, 
> you must explicitly pass the string "service," prior to the comp 
>onent's Contract ID. If you do not, the component will be created 
> and then released after the notification, which may cause the co 
>mponent to be deleted. 
247    </p>
248    <p>
249      In short, to register the <b>WebLock</b> component as an xp
>com-startup observer, do the following: 
250    </p>
251    <pre>
252char* previous = nsnull;
253rv = catman-&gt;AddCategoryEntry("xpcom-startup",
254                              "WebLock",
255                              WebLock_ContractID,
256                              PR_TRUE,  // persist category
257                              PR_TRUE,  // replace existing
258                              &amp;previous);
259if (previous)
260  nsMemory::Free(previous); // free the memory the replaced value
> might have used 
261</pre>
262    <p>
263      The unregistration, which should occur in the unregistratio
>n callback, looks like this: 
264    </p>
265    <pre>
266rv = catman-&gt;DeleteCategoryEntry("xpcom-startup",
267                                 "WebLock",
268                                  PR_TRUE);  // persist
269</pre>
270    <p>
271      A complete code listing for registering <b>WebLock</b> as a
> startup observer follows: 
272    </p>
273    <pre>
274#define MOZILLA_STRICT_API
275 
276#include "nsIGenericFactory.h"
277 
278#include "nsCOMPtr.h"
279#include "nsXPCOM.h"
280#include "nsIServiceManager.h"
281#include "nsICategoryManager.h"
282 
283#include "nsMemory.h"
284 
285#include "nsIObserver.h"
286 
287#include "nsEmbedString.h"
288 
289#define WebLock_CID \
290{ 0x777f7150, 0x4a2b, 0x4301, \
291{ 0xad, 0x10, 0x5e, 0xab, 0x25, 0xb3, 0x22, 0xaa}}
292 
293#define WebLock_ContractID "@dougt/weblock"
294 
295class WebLock: public nsIObserver
296{
297  public:
298    WebLock();
299    virtual ~WebLock();
300 
301    NS_DECL_ISUPPORTS
302    NS_DECL_NSIOBSERVER
303};
304 
305WebLock::WebLock()
306{
307  NS_INIT_ISUPPORTS();
308}
309 
310WebLock::~WebLock()
311{
312}
313 
314NS_IMPL_ISUPPORTS1(WebLock, nsIObserver);
315 
316NS_IMETHODIMP
317WebLock::Observe(nsISupports *aSubject, const char *aTopic, const
> PRUnichar *aData) 
318{
319  return NS_OK;
320}
321 
322static NS_METHOD WebLockRegistration(nsIComponentManager *aCompMg
>r, 
323                                     nsIFile *aPath,
324                                     const char *registryLocation
>, 
325                                     const char *componentType,
326                                     const nsModuleComponentInfo 
>*info) 
327{
328  nsresult rv;
329 
330  nsCOMPtr&lt;nsIServiceManager&gt; servman = do_QueryInterface((
>nsISupports*)aCompMgr, &amp;rv); 
331  if (NS_FAILED(rv))
332    return rv;
333 
334  nsCOMPtr&lt;nsICategoryManager&gt; catman;
335  rv = servman-&gt;GetServiceByContractID(NS_CATEGORYMANAGER_CONT
>RACTID, 
336                                       NS_GET_IID(nsICategoryMana
>ger), 
337                                       getter_AddRefs(catman));
338 
339  if (NS_FAILED(rv))
340    return rv;
341 
342  char* previous = nsnull;
343  rv = catman-&gt;AddCategoryEntry("xpcom-startup",
344                                "WebLock",
345                                WebLock_ContractID,
346                                PR_TRUE,
347                                PR_TRUE,
348                                &amp;previous);
349  if (previous)
350    nsMemory::Free(previous);
351 
352  return rv;
353}
354 
355static NS_METHOD WebLockUnregistration(nsIComponentManager *aComp
>Mgr, 
356                                       nsIFile *aPath,
357                                       const char *registryLocati
>on, 
358                                       const nsModuleComponentInf
>o *info) 
359{
360  nsresult rv;
361 
362  nsCOMPtr&lt;nsIServiceManager&gt; servman = do_QueryInterface((
>nsISupports*)aCompMgr, &amp;rv); 
363  if (NS_FAILED(rv))
364    return rv;
365 
366  nsCOMPtr&lt;nsICategoryManager&gt; catman;
367  rv = servman-&gt;GetServiceByContractID(NS_CATEGORYMANAGER_CONT
>RACTID, 
368                                       NS_GET_IID(nsICategoryMana
>ger), 
369                                       getter_AddRefs(catman));
370  if (NS_FAILED(rv))
371    return rv;
372 
373  rv = catman-&gt;DeleteCategoryEntry("xpcom-startup",
374                                   "WebLock",
375                                   PR_TRUE);
376 
377  return rv;
378}
379 
380NS_GENERIC_FACTORY_CONSTRUCTOR(WebLock)
381 
382static const nsModuleComponentInfo components[] =
383{
384  {
385    "WebLock",
386    WebLock_CID,
387    WebLock_ContractID,
388    WebLockConstructor,
389    WebLockRegistration,
390    WebLockUnregistration
391  }
392};
393 
394NS_IMPL_NSGETMODULE(WebLockModule, components)
395</pre>
396    <h3 id="Providing_Access_to_WebLock" name="Providing_Access_t
>o_WebLock"> 
397      Providing Access to <b>WebLock</b>
398    </h3>
399    <p>
400      At this point, the component will be called when XPCOM star
>ts up. <b>WebLock</b> has already implemented the <code>nsISuppor 
>ts</code>, <code>nsIFactory</code>, <code>nsIModule</code>, and < 
>code>nsIObserver</code> interfaces that handle generic component  
>functionality including being initialized at startup. And it spea 
>ks to the Component Manager, Service Manager, Category Manager, a 
>nd the Component Registrar to register itself properly with XPCOM 
>. 
401    </p>
402    <p>
403      The next step is to expose additional functionality to Geck
>o applications and other clients to query and control the <b>WebL 
>ock</b> component. For example, the user interface needs to be ab 
>le to enable and disable the web locking functionality, see what  
>sites are in the whitelist, and add or remove sites from that lis 
>t. WebLock needs to provide an API, and it needs to hook into Gec 
>ko in order to implement the actual locking functionality. 
404    </p>
405    <p>
406      译: 下一步是expose另外的功能以使得Gecko应用以及其它clients查询和控制WebLock组件. 例如, 
>user interface(用户接口)要有能力去允许或者禁止web locking(web锁定)功能, 查看哪些站点在白名单列表 
>中, 并向列表中添加或移除站点. WebLock需要提供一个API并挂接到Gecko中进而实现实际的locking功能. 
407    </p>
408    <div class="side-note">
409      <p>
410        {{ Block-title("The WebLock User Interface") }}
411      </p>
412      <p>
413        The <b>WebLock</b> component in this tutorial uses XUL to
> define the additional browser UI in a cross-platform way, and XU 
>L uses JavaScript to access and control XPCOM components, but Gec 
>ko's pluggable UI allows any user interface to call into Gecko an 
>d 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. 
414      </p>
415      <p>
416        在这个教程中<b>WebLock</b>组件使用XUL来定义跨平台的浏览器UI, XUL使用JavaScript来
>访问和控制XPCOM组件, 但Gecko的可挂接UI也允许任何user interface调用Gecko和你所创建的组件, 就如同 
>XUL一样容易. <a href="cn/Creating_XPCOM_Components/Building_the_WebLo 
>ck_UI#XUL">XUL</a>讨论了XUL如何与JavaScript和XPCOM交互. 
417      </p>
418    </div>
419    <h3 id="Creating_the_WebLock_Programming_Interface" name="Cre
>ating_the_WebLock_Programming_Interface"> 
420      Creating the WebLock Programming Interface
421    </h3>
422    <p>
423      Design is one of the hardest parts of any programming probl
>em. The question the interface for the <b>WebLock</b> component m 
>ust answer is: How should <b>WebLock</b> look to the outside worl 
>d? What, in other words, is the interaction of clients with the < 
>b>WebLock</b> component? In this section, we enumerate the basic  
>functionality the component should expose and create the single i 
>nterface that organizes and provides this functionality. 
424    </p>
425    <p>
426      译: 设计是任何编程问题中最困难的部分之一. 问题是<b>WebLock</b>组件必须要回答一些问题: <b>Web
>Lock</b>应该如何look to外面的世界? 换言之, 什么是clients与<b>WebLock</b>的交互? 在这部分 
>列举了组件应该expose的基本功能和create一个组织和提供这些功能的接口. 
427    </p>
428    <p>
429      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 comp 
>onent: how the functionality should be organized, expressed, and  
>exposed to its clients. 
430    </p>
431    <p>
432      译: 开发人员应该使用XPIDL(see <a href="cn/Creating_XPCOM_Components/
>An_Overview_of_XPCOM#XPIDL_and_Type_Libraries">XPIDL and Type Lib 
>raries</a> for more information about XPIDL)为组件定义接口(定义功能应该如何被组织,  
>描述和暴露给它的clients)做为开始, 而不应该从实现开始. 
433    </p>
434    <p>
435      In general, the <b>WebLock</b> service interface needs to i
>nclude the following functionality: 
436    </p>
437    <p>
438      译: 通常, <b>WebLock</b>服务接口要包括以下功能:
439    </p>
440    <ul>
441      <li>
442        <code>Lock</code> - Enable web locking so that any browse
>r in the Gecko application is restricted to the white list of web 
>site domains. 
443      </li>
444    </ul>
445    <p>
446      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;译: <code>Lo
>ck</code> - 允许web locking, 这样任何Gecko应用中的浏览器被限定只能访问白名单中的web站点域. 
447    </p>
448    <ul>
449      <li>
450        <code>Unlock</code> - Disable web locking. This should al
>low any browser in the Gecko application to browse any website re 
>gardless of the white list. 
451      </li>
452    </ul>
453    <p>
454      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;译: <code>Un
>lock</code> - 禁止web locking. 允许Gecko应该中的浏览器访问任何web站点, 而不去管白名单列表. 
455    </p>
456    <ul>
457      <li>
458        <code>AddSite</code> - Add the current URL to the white l
>ist. 
459      </li>
460    </ul>
461    <p>
462      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;译: <code>Ad
>dSite</code> - 添加当前URL到白名单列表. 
463    </p>
464    <ul>
465      <li>
466        <code>RemoveSite</code> - Remove the current URL from the
> white list. 
467      </li>
468    </ul>
469    <p>
470      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;译: <code>Re
>moveSite</code> - 从白名单列表中移除当前URL. 
471    </p>
472    <ul>
473      <li>
474        <code>EnumerateSites</code> - Allows the enumeration of a
>ll 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. 
475      </li>
476    </ul>
477    <p>
478      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;译: <code>En
>umerateSites</code> - 允许列举出所有白名单中的站点. <code>EnumerateSites</code> 
>可能会被user &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;interfac 
>e(用户接口/用户界面)所提供的例如显示所有白名单列表的可编辑列表框控件所使用. 
479    </p>
480    <p>
481      Even this simple outline presents some ambiguity, however. 
>It's certainly not enough to spell out the interface for the <b>W 
>ebLock</b> component in this way. For example, <code>AddSite</cod 
>e> is supposed to add the current URL to the white list, but is t 
>he URL an input parameter to the method, is it the topmost web pa 
>ge 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? 
482    </p>
483    <p>
484      As a strongly typed and implementation-agnostic language, X
>PIDL 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 th 
>at makes the interfaces in XPCOM effective contracts between serv 
>ices and clients. 
485    </p>
486    <p>
487      The next section shows the interface of the <b>WebLock</b> 
>component, <code>iWebLock</code>, in XPIDL. Once the interface ha 
>s 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 interfac 
>e of the <b>WebLock</b> component from JavaScript, and even <span 
> class="comment">broken link</span><a href="cn/Javadoc">javadoc</ 
>a> style HTML documentation. 
488    </p>
489    <h3 id="Defining_the_Weblock_Interface_in_XPIDL" name="Defini
>ng_the_Weblock_Interface_in_XPIDL"> 
490      Defining the <b>Weblock</b> Interface in XPIDL
491    </h3>
492    <p>
493      Most interfaces in the XPCOM world are described in XPIDL. 
>The XPIDL file for the <code>iWebLock</code> interface can be use 
>d to generate the C++ header file, which you'll need to implement 
> the interface in the component and also a type library that make 
>s the component accessible from JavaScript or other interpreted l 
>anguages. In Mozilla, JavaScript is the bridge between components 
> and the XUL-based user interface. 
494    </p>
495    <p>
496      译: 在XPCOM世界里大多数接口都是用XPIDL描述的. <code>iWebLock</code>接口的XPIDL
>文件可以被用来生成C++ header file(你需要它来在组件中实现接口和用来使组件在JavaScript和其它的解译型语言中 
>可访问的类型库). 在Mozilla中, JavaScript是组件与基于XUL的user interface之间的桥梁. 
497    </p>
498    <p>
499      The XPIDL Syntax (XPIDL语法)
500    </p>
501    <p>
502      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: 
503    </p>
504    <p>
505      {{ Block-title("iWebLock") }}
506    </p>
507    <pre>
508#include "nsISupports.idl"
509interface nsISimpleEnumerator;
510[scriptable, uuid(ea54eee4-9548-4b63-b94d-c519ffc91d09)]
511interface iWeblock : nsISupports
512{
513  void lock();
514  void unlock();
515 
516  // assume strings are UTF-8
517  void addSite(in string url);
518  void removeSite(in string url);
519  attribute nsISimpleEnumerator sites;
520};
521</pre>
522    <p>
523      The first line includes the file <code>nsISupports.idl</cod
>e>, which defines the <code>nsISupports</code> interface from whi 
>ch all XPCOM interfaces must derive, and makes it possible for th 
>e <code>iWebLock</code> interface to subclass that base interface 
>. 
524    </p>
525    <pre>
526#include "nsISupports.idl"
527</pre>
528    <p>
529      The next line of the XPIDL is a forward declaration of the 
>interface <code>nsISimpleEnumerator</code>. Again, this is simila 
>r to the forward declare in C++ (except that C++ does not have th 
>e <code>interface</code> keyword seen here). 
530    </p>
531    <pre>
532interface nsISimpleEnumerator;
533</pre>
534    <p>
535      See the <a href="cn/Creating_XPCOM_Components/Resources#XPC
>OM_Resources">XPCOM resources</a> for more information about the  
>XPIDL syntax. 
536    </p>
537    <h4 id="Scriptable_Interfaces" name="Scriptable_Interfaces">
538      Scriptable Interfaces
539    </h4>
540    <p>
541      The third line in {{ Anch("iWebLock") }} is more complex. T
>he first thing it says is that <code>iWebLock</code> will be <i>s 
>criptable</i>. 
542    </p>
543    <pre>
544[scriptable, uuid(ea54eee4-9548-4b63-b94d-c519ffc91d09)]
545</pre>
546    <p>
547      The rest of the line provides a UUID for this interface. Re
>call 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, th 
>e identifier is the CID. 
548    </p>
549    <h4 id="Subclassing_nsISupports" name="Subclassing_nsISupport
>s"> 
550      Subclassing <code>nsISupports</code>
551    </h4>
552    <p>
553      The next line in {{ Anch("iWebLock") }} names the interface
> and defines its base interface. <code>iWeblock</code> derives fr 
>om <code>nsISupports</code>. XPIDL has no way to define multiple  
>inheritance - something that all scriptable objects must deal wit 
>h. 
554    </p>
555    <pre>
556interface iWebLock : nsISupports
557</pre>
558    <h4 id="The_Web_Locking_Interface" name="The_Web_Locking_Inte
>rface"> 
559      The Web Locking Interface
560    </h4>
561    <p>
562      The body of the block (the stuff between the curly braces) 
>defines the methods and attributes of our interface. There are ba 
>sically two functional sets on this interface. The first section  
>of the interface controls whether or not <b>WebLock</b> checks to 
> see if a web page can be loaded. If locked, <b>WebLock</b> will  
>prevent sites not on the white list from loading. 
563    </p>
564    <pre>
565  void lock();
566  void unlock();
567</pre>
568    <p>
569      This interface does not enforce any policy with respect to 
>how the user enables or disables this feature. This allows maximu 
>m flexibility in the implementation. Any place in the application 
> can acquire this interface via the Service Manager and call <cod 
>e>unlock</code> or <code>lock</code>. For example, the user inter 
>face may bring up a dialog asking the user for a password before  
>calling <code>unlock</code>. Another area of code, such as a "Pro 
>file Manager" that starts up and lets users choose which profile  
>to use, may unconditionally call <code>unlock</code> on such a co 
>mponent when switching a profile. 
570    </p>
571    <p>
572      The next set of functionality manages the white list where 
>acceptable domains are stored: 
573    </p>
574    <pre>
575  void addSite(in string url);
576  void removeSite(in string url);
577  attribute nsISimpleEnumerator sites;
578</pre>
579    <p>
580      Operations in this set - <code>add</code>, <code>remove</co
>de>, and <code>enumerate</code> - will be called from a user inte 
>rface that manages the white list and adds the current website to 
> the white list. There is no policy applied to what sites get add 
>ed or removed to this list, or who can remove a site. 
581    </p>
582    <p>
583      The most interesting method definition is the enumerator. F
>irst of all, it does not look like a method at all: 
584    </p>
585    <pre>
586attribute nsISimpleEnumerator sites; 
587</pre>
588    <p>
589      This line defines an attribute in the interface. In C++, th
>is is considered a public variable and "compiled" into a <code>Ge 
>t</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. 
590    </p>
591    <p>
592      The getter created by this attribute returns a <code>nsISim
>pleEnumerator</code> interface pointer. This interface allows you 
> to pass a list of elements between interfaces. It has two method 
>s: <code>hasMoreElements()</code> and <code>getNext()</code>. 
593    </p>
594    <pre>
595[scriptable, uuid(D1899240-F9D2-11D2-BDD6-000064657374)]
596interface nsISimpleEnumerator : nsISupports
597{
598  /**
599   * Called to determine whether or not the enumerator has
600   * any elements that can be returned via getNext(). This method
601   * is generally used to determine whether or not to initiate or
602   * continue iteration over the enumerator, though it can be
603   * called without subsequent getNext() calls. Does not affect
604   * internal state of enumerator.
605   *
606   * @see getNext()
607   * @return PR_TRUE if there are remaining elements in the enume
>rator. 
608   *         PR_FALSE if there are no more elements in the enumer
>ator. 
609   */
610  boolean hasMoreElements();
611 
612  /**
613   * Called to retrieve the next element in the enumerator. The "
>next" 
614   * element is the first element upon the first call. Must be
615   * preceded by a call to hasMoreElements() which returns PR_TRU
>E. 
616   * This method is generally called within a loop to iterate ove
>r 
617   * the elements in the enumerator.
618   *
619   * @see hasMoreElements()
620   * @return NS_OK if the call succeeded in returning a non-null
621   *               value through the out parameter.
622   *         NS_ERROR_FAILURE if there are no more elements
623   *                          to enumerate.
624   * @return the next element in the enumeration.
625   */
626  nsISupports getNext();
627};
628</pre>
629    <h3 id="Implementing_WebLock" name="Implementing_WebLock">
630      Implementing <b>WebLock</b>
631    </h3>
632    <p>
633      Once you have defined the interfaces that the component wil
>l implement, you can begin to write the implementation code that  
>will actually carry out the web locking functionality. 
634    </p>
635    <p>
636      The <b>WebLock</b> component implements three interfaces:
637    </p>
638    <ul>
639      <li>
640        <code>nsISupports</code>
641      </li>
642      <li>
643        <code>nsIObserver</code>
644      </li>
645      <li>
646        <code>iWebLock</code>
647      </li>
648    </ul>
649    <p>
650      <code>nsISupports</code> is the base interface that all XPC
>OM 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 actua 
>lly controls the web locking functionality. The first two have al 
>ready 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 Easi 
>er</a> that implementing these basic interfaces can be easy and s 
>traightforward if you use the macros and other utilities that XPC 
>OM provides. 
651    </p>
652    <h4 id="Declaration_Macros" name="Declaration_Macros">
653      Declaration Macros
654    </h4>
655    <p>
656      The class declaration for the <code>WebLock</code> class th
>at implements these three interfaces is as follows: 
657    </p>
658    <pre>
659class WebLock: public nsIObserver, public iWebLock 
660{     
661  public:   
662    WebLock();   
663    virtual ~WebLock();   
664 
665    NS_DECL_ISUPPORTS 
666    NS_DECL_NSIOBSERVER 
667    NS_DECL_IWEBLOCK 
668};   
669</pre>
670    <p>
671      Note that we derive from the <code>nsIObserver</code> inter
>face as well as the <code>iWeblock</code> class. We do not need t 
>o explicitly derive from <code>nsISupports</code> as both of thes 
>e two other interfaces are already subclasses of <code>nsISupport 
>s</code>: 
672    </p>
673    <p>
674      {{ Block-title("Interface Hierarchy for WebLock") }}
675    </p>
676    <p>
677      <img alt="Image:weblock-interface-hierarchy.png" fileid="27
>29" src="File:cn/Media_Gallery/Weblock-interface-hierarchy.png"> 
678    </p>
679    <p>
680      The body of the class declaration uses declaration macros t
>hat are generated from an XPIDL interface file. Every header gene 
>rated from an XPIDL file has a similar macro that defines all the 
> methods in that interface. This makes changes to the interface w 
>hen designing a bit simpler, as you do not have to modify any cla 
>ss declarations. 
681    </p>
682    <p>
683      There are times, of course, when you cannot use these macro
>s-as when two interfaces share the same method signatures. In the 
>se 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> de 
>claration macro expands into the following: 
684    </p>
685    <pre>
686  NS_IMETHOD Lock(void);
687  NS_IMETHOD Unlock(void);
688  NS_IMETHOD AddSite(const char *url);
689  NS_IMETHOD RemoveSite(const char *url);
690  NS_IMETHOD GetSites(nsISimpleEnumerator * *aSites);
691  NS_IMETHOD SetSites(nsISimpleEnumerator *aSites);
692</pre>
693    <h4 id="Representing_Return_Values_in_XPCOM" name="Representi
>ng_Return_Values_in_XPCOM"> 
694      Representing Return Values in XPCOM
695    </h4>
696    <p>
697      The code sample above is the C++ version of the <code>iWebL
>ock</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 retu 
>rn a <code>void</code>. If you require the return result to be so 
>mething else, the methods are not truly XPCOM methods. If you rea 
>lly want to change the return result type you can use a special f 
>lag 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. 
698    </p>
699    <h4 id="XPIDL_Code_Generation" name="XPIDL_Code_Generation">
700      XPIDL Code Generation
701    </h4>
702    <p>
703      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</co 
>de>. If you copy the stub implementation from the header file int 
>o 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. 
704    </p>
705    <h4 id="Getting_the_WebLock_Service_from_a_Client" name="Gett
>ing_the_WebLock_Service_from_a_Client"> 
706      Getting the WebLock Service from a Client
707    </h4>
708    <p>
709      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 rec 
>ognized and accessed as a component in XPCOM. The code snippet be 
>low illustrates how to get the <b>WebLock</b> service when the co 
>mponent is present: 
710    </p>
711    <pre>
712nsCOMPtr&lt;nsIServiceManager&gt; servMan;
713nsresult rv = NS_GetServiceManager(getter_AddRefs(servMan));
714if (NS_FAILED(rv))
715{
716  printf("ERROR: XPCOM error [%x].\n", rv);
717  return -1;
718}
719nsCOMPtr&lt;iWebLock&gt; weblock;
720rv = servMan-&gt;GetServiceByContractID("@dougt/weblock",
721                                     NS_GET_IID(iWeblock),
722                                     getter_AddRefs(weblock));
723 
724if (NS_FAILED(rv))
725{
726  printf("ERROR: XPCOM obtaining service [%x].\n", rv);
727  return -1;
728}
729</pre>
730    <h4 id="Implementing_the_iWebLock_Interface_.28.E5.AE.9E.E7.8
>E.B0iWebLock.E6.8E.A5.E5.8F.A3.29" name="Implementing_the_iWebLoc 
>k_Interface_.28.E5.AE.9E.E7.8E.B0iWebLock.E6.8E.A5.E5.8F.A3.29"> 
731      Implementing the <code>iWebLock</code> Interface (实现iWebLoc
>k接口) 
732    </h4>
733    <p>
734      Once the interface is defined, you can focus on implementin
>g the web lock startup functionality itself. The <b>WebLock</b> c 
>omponent starts automatically when XPCOM is started up because it 
>'s been registered as a category in XPCOM. When <b>WebLock</b> 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 anywhe 
>re on the local system, but we've placed it next to the applicati 
>on to keep things simple. The first step in this implementation p 
>hase, then, is to create the functionality that accesses this <b> 
>WebLock</b> white list and uses its data to determine which domai 
>ns are allowed and which are to be blocked. For this, we need to  
>use the file interfaces available in XPCOM. 
735    </p>
736    <p>
737      一旦接口已被定义, 那你的重点应该放在实现web lock的功能上. 当XPCOM运行后WebLock组件也会被自动运
>行, 因为它已经被注册成为一个XPCOM中的category. 当WebLock被调用时, 它应该做的第一个事情就是读取一个文件, 
> 这个文件列出了允许被浏览器加载的URLs. 这个文件可以位于本地系统中的任何位置, 但我们需要将其放置在距应用程序不远的地方以便 
>操作起来简单一些. 接下来在实现阶段的第一步是实现两个功能, 一是访问WebLock的白名单, 二是使用这些数据去决定哪些域是被允 
>许, 以及哪些是应该被拦截的. 为此, 我们需要使用XPCOM中的文件接口. 
738    </p>
739    <h5 id="File_Interfaces" name="File_Interfaces">
740      File Interfaces
741    </h5>
742    <p>
743      Files and directories are abstracted and encapsulated by in
>terfaces. There are a few reasons for not using strings to repres 
>ent file locations, but the most important one is that not all fi 
>le systems can be represented by a series of characters separated 
> by a slash. On the Macintosh platform, for example, files are re 
>presented as a triplet - two numbers and one string - so using a  
>string on the Macintosh does not adequately identify files on tha 
>t operating system. 
744    </p>
745    <p>
746      文件和目录是通过接口来抽象和封装的. 这里有几个原因说明为什么不使用字符串来表示文件位置, 但更重要的一点是并不是所有
>的文件系统都能够表示成斜线所分割的字符序列. 例如, 在Macintosh(Apple的系统)平台上, 文件被表示成一个tripl 
>et(意思是由三个部分组成), 两个数字一个字符串, 因此在Macintosh系统上使用字符串并不能充分在标识文件. 
747    </p>
748    <p>
749      <code>nsIFile</code>, the file interface in XPCOM, provides
> most of the functionally that file handling requires. That inter 
>face 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 ade 
>quate for the <b>WebLock</b> component. 
750    </p>
751    <p>
752      nsIFile, XPCOM中的文件接口, 提供了大多数操作文件所必须的功能. 这个接口中所包含的成员描述了文件的名字
>, 属性, 权限, 是否存在等等. 与之相关的接口nsILocalFile提供 操作特定的本地文件, 不过nsIFile的功能对于 
>WebLock组件来说已经足够了. 
753    </p>
754    <p>
755      {{ Block-title("File Interface Hierarchy") }}
756    </p>
757    <p>
758      <img alt="Image:file-iface-hierarchy.png" fileid="2658" src
>="File:cn/Media_Gallery/File-iface-hierarchy.png"> 
759    </p>
760    <div class="side-note">
761      <p>
762        {{ Block-title("Remote Files and nsIFile") }}
763      </p>
764      <p>
765        It is not inconceivable for remote files to be represente
>d 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 f 
>or a <b>WebLock</b> implementation to take advantage of files tha 
>t 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. 
766      </p>
767      <p>
768        并不难想象, 为远程文件使用nsIFile接口来表示它. 某人可以写一个nsIFile的实现用以表示一些服务器上的
>FTP文件. 已经存在的代码必须要做一些效小的修改以使WebLock的实现可以接受实际上并不是存在于磁盘上的文件. 这种类型的实现 
>虽然还并不存在, 但至少这种扩展性可以显现出一些基于接口的编程带来的灵活性. 
769      </p>
770      <p>
771        The <a href="cn/XPCOM_API_Reference">XPCOM API Reference<
>/a> contains detailed information on <code>nsIFile</code> and oth 
>er XPCOM interfaces. 
772      </p>
773    </div>
774    <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"> 
775      The Directory Service (目录服务)
776    </h4>
777    <p>
778      The file interfaces are most useful when you can use them t
>o 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, av 
>ailable as <code>nsIDirectoryService</code>, stores the location  
>of various common system locations, such as the the directory con 
>taining the running process, the user's <code>HOME</code> directo 
>ry, and others. It can be expanded so that applications and compo 
>nents can define and store their own special locations - an appli 
>cation plugin directory, for example, preference files and/or dir 
>ectories, or other application specific paths. For example, to ex 
>pose the location of the "white list" file containing all of the  
>URLs that are safe for <b>WebLock</b>, you can add its location t 
>o the <code>nsDirectoryService</code>, which clients can then que 
>ry for this infomation. 
779    </p>
780    <p>
781      文件接口较有助于当你使用它们去查找和操作与应用相关的文件. 目录服务提供了跨平台的目录与文件定位的统一方法, 这使得进
>行这种操作变得容易. 这个服务(利用nsIDirectoryService)存储了各种各样通用系统区域的位置, 例如像是包括了正在 
>运行的程序的目录, 用户的HOME目录等等. 因此它可以被扩展为应用程序和组件能够定义并且存储它们自己的特定位置(应用程序插件目录 
>), 例如, 用户自定义的文件和目录, 或者其它的应用程序的特定路径. 比如指定一个"white list"所在的位置, 它包括了 
>所有对于WebLock来讲是安全的URLs, 你可以将这个位置添加到nsDirectoryService中, 使客户端接下来可以查 
>询到这个信息. 
782    </p>
783    <p>
784      The Directory Service implements the <code>nsIProperties</c
>ode> interface, which allows you to <code>Get()</code>, <code>Set 
>()</code>, and <code>Undefine()</code> interface pointers. In the 
> case of <b>WebLock</b>, these interface pointers will be <code>n 
>sIFile</code> objects. 
785    </p>
786    <p>
787      目录服务实现了nsIProperties接口, 它允许你Get(), Set()以及Undefine()接口指针. 在
>WebLock中这些接口指针是nsIFile对象. 
788    </p>
789    <pre>
790[scriptable, uuid(78650582-4e93-4b60-8e85-26ebd3eb14ca)]
791interface nsIProperties : nsISupports
792{
793    /**
794     * Gets a property with a given name.
795     * 用给定的名字(name)取得一个属性(property)
796     *
797     * @return NS_ERROR_FAILURE if a property with that
798     * name doesn't exist.
799     * 如果给定名字的属性不存在, 函数返回NS_ERROR_FAILURE
800     * @return NS_ERROR_NO_INTERFACE if the
801     * found property fails to QI to the
802     * given iid.
803     * 如果取得的属性在以给定的iid于QI方法上调用失败, 
804     * 函数返回NS_ERROR_NO_INTERFACE
805     */
806    void get(in string prop,
807             in nsIIDRef iid,
808             [iid_is(iid),retval] out nsQIResult result);
809 
810    /**
811     * Sets a property with a given name to a given value.
812     * 用给定的名字和给定的值为设置一个属性
813     */
814    void set(in string prop, in nsISupports value);
815 
816    /**
817     * Returns true if the property with the given name exists.
818     * 如果与给定名字的属性存在, 返回true
819     */
820    boolean has(in string prop);
821 
822    /**
823     * Undefines a property. 取消一个属性的定义
824     * @return NS_ERROR_FAILURE if a property with that name does
>n't 
825     * already exist.
826     * 如果给定名字的属性还不存在, 那么函数返回NS_ERROR_FAILURE
827     */
828    void undefine(in string prop);
829 
830    /**
831     *  Returns an array of the keys.
832     *  返回一个key的集合
833     */
834    void getKeys(out PRUint32 count,
835                 [array, size_is(count), retval] out string keys)
>; 
836};
837</pre>
838    <p>
839      {{ Block-title("Directory Service Hierarchy") }}
840    </p>
841    <p>
842      <img alt="Image:directoryservice-iface-hierarchy.png" filei
>d="2657" src="File:cn/Media_Gallery/Directoryservice-iface-hierar 
>chy.png"> 
843    </p>
844    <p>
845      There are two steps involved to find directories or files w
>ith the Directory Service (<code>nsIDirectoryService</code>). You 
> must know the string key (or property) that refers to the locati 
>on you are interested in, which is published in the file <code>ns 
>DirectoryServiceDefs.h</code> that comes with the Gecko SDK (for  
>a listing of these locations, see the <a href="cn/XPCOM_API_Refer 
>ence">XPCOM API Reference</a>). The string key for the directory  
>containing the application executable is <code>NS_XPCOM_CURRENT_P 
>ROCESS_DIR</code>. Given this key, you can acquire the directory  
>service, call <code>Get()</code>, and pass the key. In the exampl 
>e below, <code>appDir</code> will point to the directory that con 
>tains the executable. 
846    </p>
847    <p>
848      这里有两个步骤有关于通过目录服务(nsIDirectoryService)查找目录或文件. 你必须要知道字符串键(或叫
>属性)用以引用你所想要的位置, 字符串键(或叫属性)被公开于随Gecko SDK一起提供的nsDirectoryServiceDe 
>fs.h文件中(可参见<a href="cn/XPCOM_API_Reference">XPCOM API Reference</ 
>a>以得到这些位置的一个列表). 包含可执行程序的目录的字符串键是NS_XPCOM_CURRENT_PROCESS_DIR. 给定 
>这个键, 你就可以通过调用Get()并将键传递到函数中以获得目录服务. 在下面的实例中, appDir将指向一个包含了可执行程序的 
>目录. 
849    </p>
850    <pre>
851nsCOMPtr&lt;nsIServiceManager&gt; servMan;
852nsresult rv = NS_GetServiceManager(getter_AddRefs(servMan));
853if (NS_FAILED(rv)) return -1;
854 
855nsCOMPtr&lt;nsIProperties&gt; directoryService;
856rv = servMan-&gt;GetServiceByContractID(NS_DIRECTORY_SERVICE_CONT
>RACTID, 
857                                     NS_GET_IID(nsIProperties),
858                                     getter_AddRefs(directoryServ
>ice)); 
859 
860if (NS_FAILED(rv)) return -1;
861 
862nsCOMPtr&lt;nsIFile&gt; appDir;
863rv = directoryService-&gt;Get(NS_XPCOM_CURRENT_PROCESS_DIR,
864                           NS_GET_IID(nsIFile),
865                           getter_AddRefs(appDir));
866 
867if (NS_FAILED(rv)) return -1;
868</pre>
869    <p>
870      Most of the useful functionality is exposed by the <code>ns
>IProperties</code> interface, but the directory service also impl 
>ements <code>nsIDirectoryService</code>. This interface allows yo 
>u 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 d 
>elayed method. The direct method is to add a new <code>nsIFile</c 
>ode> object using the <code>nsIProperties</code> interface, in wh 
>ich case you pass the <code>nsIFile</code> object as an <code>nsI 
>Supports</code> to the <code>Set()</code> method of the <code>nsI 
>Properties</code> interface. 
871    </p>
872    <p>
873      大多数有用的功能都是通过nsIProperties接口所提供, 但目录服务还实现了nsIDirectoryServic
>e. nsIDirectoryService接口允许利用目录服务你去扩展和重写nsIFile对象的注册. 当前有两种方法添加一个文 
>件位置到目录服务中:立即的与延迟的两种方法. 立即的方法是使用nsIProperties接口添加一个新的nsIFile对象, 在这 
>种情况下你要把nsIFile对象当成一个nsISupports传递给nsIProperties接口的Set()函数. 
874    </p>
875    <p>
876      In the delayed method, you register to be a callback that c
>an provide an <code>nsIFile</code>. To do this, you must get the  
>implementation like we did above. When you have it, <code>QueryIn 
>terface</code> for the <code>nsIDirectoryService</code> interface 
>. In this interface, there is a function which allows you to regi 
>ster an <code>nsIDirectoryServiceProvider</code> interface. The i 
>nterface callback looks like this: 
877    </p>
878    <pre>
879[scriptable, uuid(bbf8cab0-d43a-11d3-8cc2-00609792278c)]
880interface nsIDirectoryServiceProvider: nsISupports
881{
882/**
883* getFile
884*
885* Directory Service calls this when it gets the first request for
886* a prop or on every request if the prop is not persistent.
887*
888* @param prop The symbolic name of the file.
889* @param persistent TRUE - The returned file will be cached by Di
>rectory 
890* Service. Subsequent requests for this prop will
891* bypass the provider and use the cache.
892* FALSE - The provider will be asked for this prop
893* each time it is requested.
894*
895* @return The file represented by the property.
896*
897*/
898nsIFile getFile(in string prop, out PRBool persistent);
899};
900</pre>
901    <h4 id="Modifying_Paths_with_nsIFile" name="Modifying_Paths_w
>ith_nsIFile"> 
902      Modifying Paths with <code>nsIFile</code>
903    </h4>
904    <p>
905      The directory service returns an <code>nsIFile</code> objec
>t, but that object points to the application directory and not th 
>e file itself. To modify this <code>nsIFile</code> so that it poi 
>nts to the file, you must call the <code>Append</code> method of  
>the <code>nsIFile</code>. <code>Append</code> adds the input stri 
>ng to the path already specified in the <code>nsIFile</code>. On  
>Unix, for example, calling <code>Append("b")</code> on an <code>n 
>sIFile</code> modifies that <code>nsIFile</code> representing <co 
>de>/u/home/dougt/a</code> to point to <code>/u/home/dougt/a/b</co 
>de>. The next operation on the <code>nsIFile</code> returns resul 
>ts associated with the "b" path. If "a" wasn't a directory, furth 
>er operations would fail, even if the initial <code>Append</code> 
> was successful. This is why <code>Append</code> is considered a  
>string operation. 
906    </p>
907    <p>
908      目录服务返回一个nsIFile对象, 但nsIFile对象指向的是应用程序目录而并不是文件. 因此为了修改nsIFil
>e对象以指向文件你必须要调用nsIFile的Append函数. Append函数将字符串输入参数追加到已经被指定到nsIFile的 
>路径里. 例如在Unix里, 在一个nsIFile上调用Append("b")将使nsIFile从指向/u/home/dougt/ 
>a修改为指向/u/home/dougt/a/b. 在nsIFile上的后续操作返回的结果将是关于"b"这个路径的. 如果"a"不是 
>一个目录, 那么进一步的操作将会失败, 尽管对于Append函数的调用是成功的. 这就是为什么Append函数被认为是对字符串的操 
>作(不进行目录路径的有效性验证). 
909    </p>
910    <p>
911      The <b>WebLock</b> component manipulates a file named <code
>>weblock.txt</code>. The following snippet adjusts the <code>theF 
>ile</code> object representing that file: 
912    </p>
913    <p>
914      WebLock组件操作名为weblock.txt的文件, 以下程序片段调整了theFile对象以表示那个文件:
915    </p>
916    <pre>
917nsEmbedCString fileName("weblock.txt");
918appDir-&gt;AppendNative(fileName);
919</pre>
920    <h4 id="Manipulating_Files_with_nsIFile" name="Manipulating_F
>iles_with_nsIFile"> 
921      Manipulating Files with <code>nsIFile</code>
922    </h4>
923    <p>
924      Once you have an <code>nsIFile</code> object pointing to th
>e file that you're interested in, you can open it and read its co 
>ntents into memory. There are many ways to do this: You can use S 
>tandard ANSI File I/O, or NSPR (see {{ Anch("The Netscape Portabl 
>e Runtime Library") }} below for a brief description of NSPR), or 
> you can use the networking APIs that Gecko provides. 
925    </p>
926    <div class="side-note">
927      <p>
928        {{ Block-title("The Netscape Portable Runtime Library") }
>} 
929      </p>
930      <p>
931        The <i>Netscape Portable Runtime Library</i> (NSPR) is a 
>platform-independent library that sits below XPCOM. As a layer of 
> abstraction above the operating system, the NSPR allows Gecko ap 
>plications to be platform independent by providing the following  
>system-level facilities: 
932      </p>
933      <ul>
934        <li>Threads
935        </li>
936        <li>Thread synchronization
937        </li>
938        <li>File and network I/O
939        </li>
940        <li>Timing and intervals
941        </li>
942        <li>Memory management
943        </li>
944        <li>Shared library linking
945        </li>
946      </ul>
947      <p>
948        The NSPR is included in the Gecko SDK.
949      </p>
950    </div>
951    <p>
952      To keep things as simple as possible, we'll read the file i
>nto memory using standard ANSI file I/O, but for examples and inf 
>ormation about how to use <i>necko</i>, the Gecko networking libr 
>aries, see <a class=" external" href="http://www.mozilla.org/proj 
>ects/netlib/" rel="freelink">http://www.mozilla.org/projects/netl 
>ib/</a>. 
953    </p>
954    <h4 id="Using_nsILocalFile_for_Reading_Data" name="Using_nsIL
>ocalFile_for_Reading_Data"> 
955      Using <code>nsILocalFile</code> for Reading Data
956    </h4>
957    <p>
958      An <code>nsIFile</code> object returned from the directory 
>service may also implement the <code>nsILocalFile</code> interfac 
>e, which has a method that will return a <code>FILE</code> pointe 
>r that can be used in <code>fread()</code>. To implement the actu 
>al read, you need to allocate a buffer the length of the file, us 
>e the <code>nsILocalFile</code> interface pointer to obtain a <co 
>de>FILE *</code>, use this result with <code>fread</code>, and cl 
>ose the file pointer. 
959    </p>
960    <p>
961      The following code loads the contents of the file reference
>d by the <code>nsIFile</code> object <code>theFile</code> into th 
>e buffer <code>buf</code>: 
962    </p>
963    <pre>
964nsCOMPtr&lt;nsILocalFile&gt; localFile = do_QueryInterface(theFil
>e); 
965if (!localFile)
966  return -1;
967 
968PRBool exists;
969rv = theFile-&gt;Exists(&amp;exists);
970if (NS_FAILED(rv))
971  return -1;
972 
973char *buf = NULL;
974 
975if (exists)
976{
977  // determine file size:
978  PRUint32 fs, numread;
979  PRInt64 fileSize;
980  rv = theFile-&gt;GetFileSize(&amp;fileSize);
981  if (NS_FAILED(rv))
982    return -1;
983 
984  // Converting 64 bit value to unsigned int
985  LL_L2UI(fs, fileSize);
986 
987  FILE* openFile;
988  rv = localFile-&gt;OpenANSIFileDesc("rw", &amp;openFile);
989  if (NS_FAILED(rv))
990    return -1;
991 
992  char *buf = (char *)malloc((fs+1) * sizeof(char));
993  if (!buf)
994    return -1;
995 
996  numread = fread(buf, sizeof(char), fs, openFile);
997 
998  if (numread != fs)
999    // do something useful.
1000 
1001  // ...
1002}
1003 
1004if (buf)
1005  free(buf);
1006</pre>
1007    <p>
1008      The first line of the code calls <code>QueryInterface</code
>> on <code>theFile</code>, and if that succeeds assigns the new i 
>nterface pointer to <code>localFile</code>. If the <code>QueryInt 
>erface</code> call fails, <code>localFile</code> will have a valu 
>e of <code>NULL</code>. 
1009    </p>
1010    <div class="side-note">
1011      <p>
1012        Note that the out parameter of the method <code>GetFileSi
>ze</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 <c 
>ode>struct</code> with two fields - a high and a low 32-bit integ 
>er. So operations on this type must use special macros that do th 
>e 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: 
1013      </p>
1014      <pre>
1015PRInt64 x = 1, y = 2;
1016y = x * 2;
1017</pre>
1018      <p>
1019        However, this same snippet will not compile on a platform
> like Macintosh OS 9, where you need to use macros to perform the 
> calculation: 
1020      </p>
1021      <pre>
1022PRInt64 x, y, two;
1023LL_I2L(x, 1);
1024LL_I2L(y, 2);
1025LL_I2L(two, 2);
1026LL_MUL(y, x, two);
1027</pre>
1028      <p>
1029        A full listing of NSPR's <code>long long</code> support c
>an be found at <a class=" external" href="http://www.mozilla.org/ 
>projects/nspr/" rel="freelink">http://www.mozilla.org/projects/ns 
>pr/</a>. 
1030      </p>
1031      <p>
1032        The <b>WebLock</b> component doesn't have to deal with fi
>les that are longer than 2<sup>32</sup> bytes. Truncating this va 
>lue to whatever can fit into a 32-bit unsigned integer may not wo 
>rk for every application, but in this case it doesn't really matt 
>er. 
1033      </p>
1034    </div>
1035    <h4 id="Processing_the_White_List_Data" name="Processing_the_
>White_List_Data"> 
1036      Processing the White List Data
1037    </h4>
1038    <p>
1039      There are various ways to process the file data itself. The
> file <code>weblock.txt</code> consists of URL tokens separated b 
>y return characters, which makes them easy to read into a data st 
>ructure. 
1040    </p>
1041    <p>
1042      The white list file can be read in as soon as the component
> starts up (i.e., as <b>WebLock</b> intercepts the startup notifi 
>cation in the <code>Observe</code> method of the <code>nsIObserve 
>r</code> interface that we implement). Since we have only registe 
>red to receive a notification when XPCOM starts up, it's a safe a 
>ssumption that <code>Observe</code> will only be called during th 
>e startup event, so we can read the file data in the callback. 
1043    </p>
1044    <p>
1045      After you've read the data into memory, you need to store i
>t in some way to make data access quick and efficient. 
1046    </p>
1047    <div class="side-note">
1048      <p>
1049        {{ Block-title("URL Checking") }}
1050      </p>
1051      <p>
1052        The way in which URL checking is implemented in the <b>We
>bLock</b> component is not at all optimal. The <b>WebLock</b> com 
>ponent manages a simple linked list of URL strings. A linear sear 
>ch 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 t 
>he list grows. There's also a large bottleneck in the network req 
>uest. URL data is accessed as in the diagram below: 
1053      </p>
1054      <p>
1055        <img alt="Image:urldata-access-in-weblock.png" fileid="26
>88" src="File:cn/Media_Gallery/Urldata-access-in-weblock.png"> 
1056      </p>
1057      <p>
1058        You might construct hash values for each of the URL strin
>gs instead, or add them to some kind of database. But we leave op 
>timizations and real-world performance for web locking to the rea 
>der. 
1059      </p>
1060    </div>
1061    <h3 id="iWebLock_Method_by_Method" name="iWebLock_Method_by_M
>ethod"> 
1062      <code>iWebLock</code> Method by Method
1063    </h3>
1064    <p>
1065      The implementation of the <code>iWeblock</code> interface i
>s straightforward. <b>WebLock</b> is designed so that the user in 
>terface notifies this service when we should go into lock mode. D 
>uring 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, remo 
>ve, and enumerate the list of URLs that it knows about. 
1066    </p>
1067    <h4 id="Lock_and_Unlock" name="Lock_and_Unlock">
1068      <code>Lock</code> and <code>Unlock</code>
1069    </h4>
1070    <p>
1071      The <code>lock</code> and <code>unlock</code> methods simpl
>y set a Boolean representing state in the object. This Boolean va 
>lue will be used later to determine if we should be denying URL r 
>equests: 
1072    </p>
1073    <pre>
1074/* void lock (); */
1075NS_IMETHODIMP
1076WebLock::Lock()
1077{
1078  mLocked = PR_TRUE;
1079  return NS_OK;
1080}
1081 
1082/* void unlock (); */
1083NS_IMETHODIMP WebLock::Unlock()
1084{
1085  mLocked = PR_FALSE;
1086  return NS_OK;
1087}
1088</pre>
1089    <h4 id="AddSite" name="AddSite">
1090      <code>AddSite</code>
1091    </h4>
1092    <p>
1093      For <code>AddSite</code>, we add a new node to our linked l
>ist. The link list nodes contain a <code>char*</code> which point 
>s to the string URL that we care about and, of course, a pointer  
>to the next element in the list. 
1094    </p>
1095    <div class="side-note">
1096      <p>
1097        {{ Block-title("<code>nsMemory</code> for Cross-component
> Boundaries") }} 
1098      </p>
1099      <p>
1100        WebLock maintains ownership of all the memory it allocate
>s, so you can use just about any allocator that you want for <b>W 
>ebLock</b>, but this is not always the case. In other places, whe 
>re 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 deall 
>ocation. 
1101      </p>
1102      <p>
1103        Suppose you call <code>malloc</code> from object A and pa
>ss this buffer to another object B, for example. But if object B  
>is using a special allocator that does garbage collection, then w 
>hen object B deletes a buffer allocated by object A's allocator,  
>the results are unpredictable: probably an assertion will be rais 
>ed, 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>ns 
>Memory</code>, you are guaranteed to be using this same memory al 
>locator in all cases, and this avoids the problem described here. 
1104      </p>
1105    </div>
1106    <h4 id="RemoveSite" name="RemoveSite">
1107      <code>RemoveSite</code>
1108    </h4>
1109    <p>
1110      <code>RemoveSite</code> deletes a node from the linked list
>: 
1111    </p>
1112    <pre>
1113// a simple link list.
1114struct urlNode
1115{
1116  char* urlString;
1117  struct urlNode* next;
1118};
1119 
1120/* void addSite (in string url); */
1121NS_IMETHODIMP
1122WebLock::AddSite(const char *url)
1123{
1124  // we don't special-case duplicates here
1125  urlNode* node = (urlNode*) malloc(sizeof(urlNode));
1126  node-&gt;urlString = strdup(url);
1127  node-&gt;next = mRootURLNode;
1128  mRootURLNode = node;
1129 
1130  return NS_OK;
1131}
1132 
1133/* void removeSite (in string url); */
1134NS_IMETHODIMP
1135WebLock::RemoveSite(const char *url)
1136{
1137  // find our entry.
1138  urlNode* node = mRootURLNode;
1139  urlNode* prev = nsnull;
1140 
1141  while (node)  // test this!
1142  {
1143    if (strcmp(node-&gt;urlString, url) == 0)
1144    {
1145      free(node-&gt;urlString);
1146      if (prev)
1147        prev-&gt;next = node-&gt;next;
1148      free(node);
1149      return NS_OK;
1150    }
1151    prev = node;
1152    node = node-&gt;next;
1153  }
1154 
1155  return NS_ERROR_FAILURE;
1156}
1157</pre>
1158    <h4 id="SetSites" name="SetSites">
1159      <code>SetSites</code>
1160    </h4>
1161    <p>
1162      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>nsISimpleEnumer 
>ator</code> and shows how primitive data can be passed as an <cod 
>e>nsISupports</code> object. The <code>nsISimpleEnumerator</code> 
> interface is shown in {{ Anch("The Web Locking Interface") }}. 
1163    </p>
1164    <p>
1165      The first method returns a Boolean if there are more elemen
>ts in the set. Internally, the object knows the number of element 
>s 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 p 
>oints to a non-element, <code>hasMoreElements</code> will return  
>false. 
1166    </p>
1167    <p>
1168      There is no way to reset an <code>nsISimpleEnumerator</code
>>. For example, you can't re-enumerate the set. If you need rando 
>m access to the elements in a <code>nsISimpleEnumerator</code>, y 
>ou 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. 
1169    </p>
1170    <p>
1171      When you want to pass primitive data types like numbers, st
>rings, 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 <cod 
>e>nsISupports</code>. This allows types like the strings that rep 
>resent URLs in the <b>WebLock</b> component to be passed though m 
>ethods that take an <code>nsISupports</code> interface pointer. T 
>his becomes clear when when you see the implementation of <code>S 
>etSites</code>: 
1172    </p>
1173    <pre>
1174NS_IMETHODIMP
1175WebLock::SetSites(nsISimpleEnumerator * aSites)
1176{
1177  PRBool more = PR_TRUE;
1178  while (more)
1179  {
1180    nsCOMPtr&lt;nsISupports&gt; supports;
1181    aSites-&gt;GetNext(getter_AddRefs(supports));
1182 
1183    nsCOMPtr&lt;nsISupportsCString&gt; supportsString =  do_Query
>Interface(supports); 
1184 
1185    if (supportsString)
1186    {
1187      nsEmbedCString url;
1188      supportsString-&gt;GetData(url);
1189      AddSite(url.get());
1190    }
1191 
1192        aSites-&gt;HasMoreElements(&amp;more);
1193  }
1194 
1195  return NS_OK;
1196}
1197</pre>
1198    <h4 id="GetNext" name="GetNext">
1199      <code>GetNext</code>
1200    </h4>
1201    <p>
1202      <code>GetNext</code> is called with the <code>nsCOMPtr</cod
>e> of an <code>nsISupportsCString</code>. <code>nsCOMPtr</code>s  
>are nice because they do whatever <code>QueryInterface</code> cal 
>ls are necessary under the hood. For example, we know that the <c 
>ode>GetNext</code> method takes an <code>nsISupports</code> objec 
>t, but we may not be sure whether the return result supports the  
>interface we want, <code>nsISupportsCString</code>. But after <co 
>de>GetNext</code> returns, the <code>nsCOMPtr</code> code takes t 
>he out parameter from <code>GetNext</code> and tries to <code>Que 
>ryInterface</code> it to the <code>nsCOMPtr</code>'s type. In thi 
>s case, if the out parameter of <code>GetData</code> does not ret 
>urn something that is <code>QueryInterface</code>-able to an <cod 
>e>nsISupportsCString</code>, the variable will be set to <code>nu 
>ll</code>. Once you know that you have an <code>nsISupportsCStrin 
>g</code>, you can grab the data from the primitive supports inter 
>face. 
1203    </p>
1204    <p>
1205      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/Crea 
>ting_XPCOM_Components/Using_XPCOM_Utilities_to_Make_Things_Easier 
>#String_Classes_in_XPCOM">String Classes in XPCOM</a>. 
1206    </p>
1207    <h4 id="GetSites" name="GetSites">
1208      <code>GetSites</code>
1209    </h4>
1210    <p>
1211      The implementation of <code>GetSites</code> is more involve
>d. You must construct an implementation of <code>nsISimpleEnumera 
>tor</code> and return it when <code>GetSites</code> is called. Th 
>e class needs to walk the list of <code>urlNode</code>'s for ever 
>y call to <code>GetNext</code>, so it makes sense for the constru 
>ctor itself to take an <code>urlNode</code>: 
1212    </p>
1213    <pre>
1214class myEnumerator : public nsISimpleEnumerator
1215{
1216  public:
1217    NS_DECL_ISUPPORTS
1218    NS_DECL_NSISIMPLEENUMERATOR
1219 
1220    myEnumerator(urlNode* node) { 
1221      NS_INIT_ISUPPORTS()
1222      mNode = node; 
1223    }
1224    virtual ~myEnumerator(void) {}
1225 
1226  protected:
1227    urlNode* mNode;
1228    nsCOMPtr&lt;nsIComponentManager&gt; mCompMgr;
1229};
1230 
1231NS_IMPL_ISUPPORTS1(myEnumerator, nsISimpleEnumerator);
1232</pre>
1233    <p>
1234      The <code>myEnumerator</code> class is going to implement t
>he <code>nsISupports</code> interface and also <code>nsISimpleEnu 
>merator</code>. The only state that it needs to maintain is the c 
>urrent 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>nsISupports 
>CString</code> objects and cache the interface pointer as an opti 
>mization. 
1235    </p>
1236    <h4 id="HasMoreElements" name="HasMoreElements">
1237      <code>HasMoreElements</code>
1238    </h4>
1239    <p>
1240      <code>HasMoreElements</code> is simple. All you need to do 
>is make sure that <code>mNode</code> isn't <code>null</code>: 
1241    </p>
1242    <pre>
1243NS_IMETHODIMP
1244myEnumerator::HasMoreElements(PRBool* aResult)
1245{
1246  if (!aResult)
1247    return NS_ERROR_NULL_POINTER;
1248 
1249  if (!mNode) {
1250    *aResult = PR_FALSE;
1251    return NS_OK;
1252  }
1253 
1254  *aResult = PR_TRUE;
1255  return NS_OK;
1256}
1257</pre>
1258    <p>
1259      <code>GetNext</code> needs to create an <code>nsISupportsCS
>tring</code> so that you can pass the URL string out through the  
><code>nsISupports</code> parameter. You must also move <code>mNod 
>e</code> to point to the next <code>urlNode</code>. 
1260    </p>
1261    <pre>
1262static NS_DEFINE_CID(kSupportsCStringCID, NS_SUPPORTS_CSTRING_CID
>); 
1263 
1264NS_IMETHODIMP
1265myEnumerator::GetNext(nsISupports** aResult)
1266{
1267  if (!aResult)
1268    return NS_ERROR_NULL_POINTER;
1269 
1270  *aResult = nsnull;
1271 
1272  if (!mNode)
1273    return NS_ERROR_FAILURE;
1274 
1275  if (!mCompMgr)
1276  {
1277    NS_GetComponentManager(getter_AddRefs(mCompMgr));
1278    if (!mCompMgr)
1279      return NS_ERROR_UNEXPECTED;
1280  }
1281 
1282  nsISupportsCString* stringSupports; 
1283  mCompMgr-&gt;CreateInstance(kSupportsCStringCID,
1284                           nsnull,
1285                           NS_GET_IID(nsISupportsCString),
1286                           (void**)&amp;stringSupports);
1287  if (!stringSupports)
1288    return NS_ERROR_UNEXPECTED;
1289 
1290  nsEmbedCString str(mNode-&gt;urlString);
1291  stringSupports-&gt;SetData(str);
1292 
1293  *aResult = stringSupports; // addref'ed above.
1294 
1295  mNode = mNode-&gt;next;
1296 
1297  return NS_OK;
1298}
1299</pre>
1300    <p>
1301      在实际的<code>GetSites</code>呼叫中, 你需要做的就是产生一个<code>myEnumerator
></code>实例并且返回它. 
1302    </p>
1303    <p>
1304      此前,我们建立了一个类并且把它注册到组件管理器。当一个客户端需要获取某个接口的实现时,实际上的对象建立过程隐藏在XPC
>OM代码中。 但是其中, 你要初始化你自己的<code>nsISimpleEnumerator</code>实现. 这是一个简单的 
>事情,但是你需要注意<code>NS_ADDREF</code>. 
1305    </p>
1306    <pre>
1307NS_IMETHODIMP
1308WebLock::GetSites(nsISimpleEnumerator * *aSites)
1309{
1310  myEnumerator* enumerator = new myEnumerator(mRootURLNode);
1311  if (!enumerator)
1312    return NS_ERROR_OUT_OF_MEMORY;
1313 
1314  NS_ADDREF(*aSites = enumerator);
1315  return NS_OK;
1316}
1317</pre>
1318    <div class="side-note">
1319      <p>
1320        {{ Block-title("AddRef, Releasing, and Deleting Objects")
> }} 
1321      </p>
1322      <p>
1323        永远不要忘记调用你通过<code>new</code>建立的XPCOM对象的<code>AddRef</code>
>方法。所有的代码或者活动组件都应该有一个起码一个引用计数。忘记这点可能引起麻烦。 
1324      </p>
1325      <p>
1326        一个相关的警示试你不要忘记永远不要用<code>delete</code>删除一个XPCOM. 当系统的一部分不是
>释放而是删除一个XPCOM对象的时候,可能会引起几个小时的资源搜索并且引起崩溃。 
1327      </p>
1328    </div>
1329    <p>
1330      注意上面的实现中,当其他的线程访问链接表的时候<code>myEnumerator</code> 可能变得非法。枚举仅
>仅表现了访问URL字符串链接表的一个方法。如果你需要枚举成为URL字符串链表的一个快照,你需要重构这个实现让枚举持有一个链表的co 
>py。 
1331    </p>
1332    <p>
1333      当组件中止的时候,你也需要把链表写到磁盘里并且释放空间。我们把这个作为练习留给读者。
1334    </p>
1335    <p>
1336      {{ PreviousNext("Creating XPCOM Components:Using XPCOM Util
>ities to Make Things Easier", "Creating XPCOM Components:Finishin 
>g the Component") }} {{ CXCLicenseBlock() }} 
1337    </p>

返回历史