VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp@ 104411

最後變更 在這個檔案從104411是 102348,由 vboxsync 提交於 15 月 前

libs/xpcom: Get rid of prprf.h and prprf.c, bugref:10545 [build fix]

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 19.8 KB
 
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2000
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 * Scott Collins <[email protected]>
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39#define PL_ARENA_CONST_ALIGN_MASK 7
40
41#include "nsICategoryManager.h"
42#include "nsCategoryManager.h"
43
44#include "plarena.h"
45#include "nsCOMPtr.h"
46#include "nsTHashtable.h"
47#include "nsClassHashtable.h"
48#include "nsIFactory.h"
49#include "nsIStringEnumerator.h"
50#include "nsSupportsPrimitives.h"
51#include "nsIServiceManagerUtils.h"
52#include "nsIObserver.h"
53#include "nsReadableUtils.h"
54#include "nsCRT.h"
55#include "nsEnumeratorUtils.h"
56
57#include <iprt/assert.h>
58#include <iprt/errcore.h>
59
60class nsIComponentLoaderManager;
61
62/*
63 CategoryDatabase
64 contains 0 or more 1-1 mappings of string to Category
65 each Category contains 0 or more 1-1 mappings of string keys to string values
66
67 In other words, the CategoryDatabase is a tree, whose root is a hashtable.
68 Internal nodes (or Categories) are hashtables. Leaf nodes are strings.
69
70 The leaf strings are allocated in an arena, because we assume they're not
71 going to change much ;)
72*/
73
74#define NS_CATEGORYMANAGER_ARENA_SIZE (1024 * 8)
75
76// pulled in from nsComponentManager.cpp
77char* ArenaStrdup(const char* s, PLArenaPool* aArena);
78
79//
80// BaseStringEnumerator is subclassed by EntryEnumerator and
81// CategoryEnumerator
82//
83class BaseStringEnumerator
84 : public nsISimpleEnumerator,
85 nsIUTF8StringEnumerator
86{
87public:
88 NS_DECL_ISUPPORTS
89 NS_DECL_NSISIMPLEENUMERATOR
90 NS_DECL_NSIUTF8STRINGENUMERATOR
91
92protected:
93 BaseStringEnumerator()
94 : mArray(nsnull),
95 mCount(0),
96 mSimpleCurItem(0),
97 mStringCurItem(0) { }
98
99 // A virtual destructor is needed here because subclasses of
100 // BaseStringEnumerator do not implement their own Release() method.
101
102 virtual ~BaseStringEnumerator()
103 {
104 if (mArray)
105 delete[] mArray;
106 }
107
108 const char** mArray;
109 PRUint32 mCount;
110 PRUint32 mSimpleCurItem;
111 PRUint32 mStringCurItem;
112};
113
114NS_IMPL_ISUPPORTS2(BaseStringEnumerator, nsISimpleEnumerator, nsIUTF8StringEnumerator)
115
116NS_IMETHODIMP
117BaseStringEnumerator::HasMoreElements(PRBool *_retval)
118{
119 *_retval = (mSimpleCurItem < mCount);
120
121 return NS_OK;
122}
123
124NS_IMETHODIMP
125BaseStringEnumerator::GetNext(nsISupports **_retval)
126{
127 if (mSimpleCurItem >= mCount)
128 return NS_ERROR_FAILURE;
129
130 nsSupportsDependentCString* str =
131 new nsSupportsDependentCString(mArray[mSimpleCurItem++]);
132 if (!str)
133 return NS_ERROR_OUT_OF_MEMORY;
134
135 *_retval = str;
136 NS_ADDREF(*_retval);
137 return NS_OK;
138}
139
140NS_IMETHODIMP
141BaseStringEnumerator::HasMore(PRBool *_retval)
142{
143 *_retval = (mStringCurItem < mCount);
144
145 return NS_OK;
146}
147
148NS_IMETHODIMP
149BaseStringEnumerator::GetNext(nsACString& _retval)
150{
151 if (mStringCurItem >= mCount)
152 return NS_ERROR_FAILURE;
153
154 _retval = nsDependentCString(mArray[mStringCurItem++]);
155 return NS_OK;
156}
157
158
159//
160// EntryEnumerator is the wrapper that allows nsICategoryManager::EnumerateCategory
161//
162class EntryEnumerator
163 : public BaseStringEnumerator
164{
165public:
166 static EntryEnumerator* Create(nsTHashtable<CategoryLeaf>& aTable);
167
168private:
169 static PLDHashOperator PR_CALLBACK
170 enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg);
171};
172
173
174PLDHashOperator PR_CALLBACK
175EntryEnumerator::enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg)
176{
177 EntryEnumerator* mythis = NS_STATIC_CAST(EntryEnumerator*, userArg);
178 mythis->mArray[mythis->mCount++] = aLeaf->GetKey();
179
180 return PL_DHASH_NEXT;
181}
182
183EntryEnumerator*
184EntryEnumerator::Create(nsTHashtable<CategoryLeaf>& aTable)
185{
186 EntryEnumerator* enumObj = new EntryEnumerator();
187 if (!enumObj)
188 return nsnull;
189
190 enumObj->mArray = new char const* [aTable.Count()];
191 if (!enumObj->mArray) {
192 delete enumObj;
193 return nsnull;
194 }
195
196 aTable.EnumerateEntries(enumfunc_createenumerator, enumObj);
197
198 return enumObj;
199}
200
201
202//
203// CategoryNode implementations
204//
205
206CategoryNode*
207CategoryNode::Create(PLArenaPool* aArena)
208{
209 CategoryNode* node = new(aArena) CategoryNode();
210 if (!node)
211 return nsnull;
212
213 if (!node->mTable.Init()) {
214 delete node;
215 return nsnull;
216 }
217
218 node->mLock = NIL_RTSEMFASTMUTEX;
219 int vrc = RTSemFastMutexCreate(&node->mLock);
220 if (RT_FAILURE(vrc)) {
221 delete node;
222 return nsnull;
223 }
224
225 return node;
226}
227
228CategoryNode::~CategoryNode()
229{
230 if (mLock != NIL_RTSEMFASTMUTEX)
231 {
232 RTSemFastMutexDestroy(mLock);
233 mLock = NIL_RTSEMFASTMUTEX;
234 }
235}
236
237void*
238CategoryNode::operator new(size_t aSize, PLArenaPool* aArena)
239{
240 void* p;
241 PL_ARENA_ALLOCATE(p, aArena, aSize);
242 return p;
243}
244
245NS_METHOD
246CategoryNode::GetLeaf(const char* aEntryName,
247 char** _retval)
248{
249 RTSemFastMutexRequest(mLock);
250 nsresult rv = NS_ERROR_NOT_AVAILABLE;
251 CategoryLeaf* ent =
252 mTable.GetEntry(aEntryName);
253
254 // we only want the non-persistent value
255 if (ent && ent->nonpValue) {
256 *_retval = nsCRT::strdup(ent->nonpValue);
257 if (*_retval)
258 rv = NS_OK;
259 }
260 RTSemFastMutexRelease(mLock);
261
262 return rv;
263}
264
265NS_METHOD
266CategoryNode::AddLeaf(const char* aEntryName,
267 const char* aValue,
268 PRBool aPersist,
269 PRBool aReplace,
270 char** _retval,
271 PLArenaPool* aArena)
272{
273 RTSemFastMutexRequest(mLock);
274 CategoryLeaf* leaf =
275 mTable.GetEntry(aEntryName);
276
277 nsresult rv = NS_OK;
278 if (leaf) {
279 //if the entry was found, aReplace must be specified
280 if (!aReplace && (leaf->nonpValue || (aPersist && leaf->pValue )))
281 rv = NS_ERROR_INVALID_ARG;
282 } else {
283 const char* arenaEntryName = ArenaStrdup(aEntryName, aArena);
284 if (!arenaEntryName) {
285 rv = NS_ERROR_OUT_OF_MEMORY;
286 } else {
287 leaf = mTable.PutEntry(arenaEntryName);
288 if (!leaf)
289 rv = NS_ERROR_OUT_OF_MEMORY;
290 }
291 }
292
293 if (NS_SUCCEEDED(rv)) {
294 const char* arenaValue = ArenaStrdup(aValue, aArena);
295 if (!arenaValue) {
296 rv = NS_ERROR_OUT_OF_MEMORY;
297 } else {
298 leaf->nonpValue = arenaValue;
299 if (aPersist)
300 leaf->pValue = arenaValue;
301 }
302 }
303
304 RTSemFastMutexRelease(mLock);
305 return rv;
306}
307
308NS_METHOD
309CategoryNode::DeleteLeaf(const char* aEntryName,
310 PRBool aDontPersist)
311{
312 // we don't throw any errors, because it normally doesn't matter
313 // and it makes JS a lot cleaner
314 RTSemFastMutexRequest(mLock);
315
316 if (aDontPersist) {
317 // we can just remove the entire hash entry without introspection
318 mTable.RemoveEntry(aEntryName);
319 } else {
320 // if we are keeping the persistent value, we need to look at
321 // the contents of the current entry
322 CategoryLeaf* leaf = mTable.GetEntry(aEntryName);
323 if (leaf) {
324 if (leaf->pValue) {
325 leaf->nonpValue = nsnull;
326 } else {
327 // if there is no persistent value, just remove the entry
328 mTable.RawRemoveEntry(leaf);
329 }
330 }
331 }
332 RTSemFastMutexRelease(mLock);
333
334 return NS_OK;
335}
336
337NS_METHOD
338CategoryNode::Enumerate(nsISimpleEnumerator **_retval)
339{
340 NS_ENSURE_ARG_POINTER(_retval);
341
342 RTSemFastMutexRequest(mLock);
343 EntryEnumerator* enumObj = EntryEnumerator::Create(mTable);
344 RTSemFastMutexRelease(mLock);
345
346 if (!enumObj)
347 return NS_ERROR_OUT_OF_MEMORY;
348
349 *_retval = enumObj;
350 NS_ADDREF(*_retval);
351 return NS_OK;
352}
353
354struct persistent_userstruct {
355 PRTSTREAM fd;
356 const char* categoryName;
357 PRBool success;
358};
359
360PLDHashOperator PR_CALLBACK
361enumfunc_pentries(CategoryLeaf* aLeaf, void* userArg)
362{
363 persistent_userstruct* args =
364 NS_STATIC_CAST(persistent_userstruct*, userArg);
365
366 PLDHashOperator status = PL_DHASH_NEXT;
367
368 if (aLeaf->pValue) {
369 if (RTStrmPrintf(args->fd,
370 "%s,%s,%s\n",
371 args->categoryName,
372 aLeaf->GetKey(),
373 aLeaf->pValue) == -1) {
374 args->success = PR_FALSE;
375 status = PL_DHASH_STOP;
376 }
377 }
378
379 return status;
380}
381
382PRBool
383CategoryNode::WritePersistentEntries(PRTSTREAM fd, const char* aCategoryName)
384{
385 persistent_userstruct args = {
386 fd,
387 aCategoryName,
388 PR_TRUE
389 };
390
391 RTSemFastMutexRequest(mLock);
392 mTable.EnumerateEntries(enumfunc_pentries, &args);
393 RTSemFastMutexRelease(mLock);
394
395 return args.success;
396}
397
398
399//
400// CategoryEnumerator class
401//
402
403class CategoryEnumerator
404 : public BaseStringEnumerator
405{
406public:
407 static CategoryEnumerator* Create(nsClassHashtable<nsDepCharHashKey, CategoryNode>& aTable);
408
409private:
410 static PLDHashOperator PR_CALLBACK
411 enumfunc_createenumerator(const char* aStr,
412 CategoryNode* aNode,
413 void* userArg);
414};
415
416CategoryEnumerator*
417CategoryEnumerator::Create(nsClassHashtable<nsDepCharHashKey, CategoryNode>& aTable)
418{
419 CategoryEnumerator* enumObj = new CategoryEnumerator();
420 if (!enumObj)
421 return nsnull;
422
423 enumObj->mArray = new const char* [aTable.Count()];
424 if (!enumObj->mArray) {
425 delete enumObj;
426 return nsnull;
427 }
428
429 aTable.EnumerateRead(enumfunc_createenumerator, enumObj);
430
431 return enumObj;
432}
433
434PLDHashOperator PR_CALLBACK
435CategoryEnumerator::enumfunc_createenumerator(const char* aStr, CategoryNode* aNode, void* userArg)
436{
437 CategoryEnumerator* mythis = NS_STATIC_CAST(CategoryEnumerator*, userArg);
438
439 // if a category has no entries, we pretend it doesn't exist
440 if (aNode->Count())
441 mythis->mArray[mythis->mCount++] = aStr;
442
443 return PL_DHASH_NEXT;
444}
445
446
447//
448// nsCategoryManager implementations
449//
450
451NS_IMPL_THREADSAFE_ISUPPORTS1(nsCategoryManager, nsICategoryManager)
452
453nsCategoryManager*
454nsCategoryManager::Create()
455{
456 nsCategoryManager* manager = new nsCategoryManager();
457
458 if (!manager)
459 return nsnull;
460
461 PL_INIT_ARENA_POOL(&(manager->mArena), "CategoryManagerArena",
462 NS_CATEGORYMANAGER_ARENA_SIZE); // this never fails
463
464 if (!manager->mTable.Init()) {
465 delete manager;
466 return nsnull;
467 }
468
469 manager->mLock = NIL_RTSEMFASTMUTEX;
470 int vrc = RTSemFastMutexCreate(&manager->mLock);
471 if (RT_FAILURE(vrc))
472 {
473 delete manager;
474 return nsnull;
475 }
476
477 return manager;
478}
479
480nsCategoryManager::~nsCategoryManager()
481{
482 if (mLock != NIL_RTSEMFASTMUTEX)
483 {
484 RTSemFastMutexDestroy(mLock);
485 mLock = NIL_RTSEMFASTMUTEX;
486 }
487
488 // the hashtable contains entries that must be deleted before the arena is
489 // destroyed, or else you will have PRLocks undestroyed and other Really
490 // Bad Stuff (TM)
491 mTable.Clear();
492
493 PL_FinishArenaPool(&mArena);
494}
495
496inline CategoryNode*
497nsCategoryManager::get_category(const char* aName) {
498 CategoryNode* node;
499 if (!mTable.Get(aName, &node)) {
500 return nsnull;
501 }
502 return node;
503}
504
505NS_IMETHODIMP
506nsCategoryManager::GetCategoryEntry( const char *aCategoryName,
507 const char *aEntryName,
508 char **_retval )
509{
510 NS_ENSURE_ARG_POINTER(aCategoryName);
511 NS_ENSURE_ARG_POINTER(aEntryName);
512 NS_ENSURE_ARG_POINTER(_retval);
513
514 nsresult status = NS_ERROR_NOT_AVAILABLE;
515
516 RTSemFastMutexRequest(mLock);
517 CategoryNode* category = get_category(aCategoryName);
518 RTSemFastMutexRelease(mLock);
519
520 if (category) {
521 status = category->GetLeaf(aEntryName, _retval);
522 }
523
524 return status;
525}
526
527NS_IMETHODIMP
528nsCategoryManager::AddCategoryEntry( const char *aCategoryName,
529 const char *aEntryName,
530 const char *aValue,
531 PRBool aPersist,
532 PRBool aReplace,
533 char **_retval )
534{
535 NS_ENSURE_ARG_POINTER(aCategoryName);
536 NS_ENSURE_ARG_POINTER(aEntryName);
537 NS_ENSURE_ARG_POINTER(aValue);
538
539 // Before we can insert a new entry, we'll need to
540 // find the |CategoryNode| to put it in...
541 RTSemFastMutexRequest(mLock);
542 CategoryNode* category = get_category(aCategoryName);
543
544 if (!category) {
545 // That category doesn't exist yet; let's make it.
546 category = CategoryNode::Create(&mArena);
547
548 char* categoryName = ArenaStrdup(aCategoryName, &mArena);
549 mTable.Put(categoryName, category);
550 }
551 RTSemFastMutexRelease(mLock);
552
553 if (!category)
554 return NS_ERROR_OUT_OF_MEMORY;
555
556 return category->AddLeaf(aEntryName,
557 aValue,
558 aPersist,
559 aReplace,
560 _retval,
561 &mArena);
562}
563
564NS_IMETHODIMP
565nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName,
566 const char *aEntryName,
567 PRBool aDontPersist)
568{
569 NS_ENSURE_ARG_POINTER(aCategoryName);
570 NS_ENSURE_ARG_POINTER(aEntryName);
571
572 /*
573 Note: no errors are reported since failure to delete
574 probably won't hurt you, and returning errors seriously
575 inconveniences JS clients
576 */
577
578 RTSemFastMutexRequest(mLock);
579 CategoryNode* category = get_category(aCategoryName);
580 RTSemFastMutexRelease(mLock);
581
582 if (!category)
583 return NS_OK;
584
585 return category->DeleteLeaf(aEntryName,
586 aDontPersist);
587}
588
589NS_IMETHODIMP
590nsCategoryManager::DeleteCategory( const char *aCategoryName )
591{
592 NS_ENSURE_ARG_POINTER(aCategoryName);
593
594 // the categories are arena-allocated, so we don't
595 // actually delete them. We just remove all of the
596 // leaf nodes.
597
598 RTSemFastMutexRequest(mLock);
599 CategoryNode* category = get_category(aCategoryName);
600 RTSemFastMutexRelease(mLock);
601
602 if (category)
603 category->Clear();
604
605 return NS_OK;
606}
607
608NS_IMETHODIMP
609nsCategoryManager::EnumerateCategory( const char *aCategoryName,
610 nsISimpleEnumerator **_retval )
611{
612 NS_ENSURE_ARG_POINTER(aCategoryName);
613 NS_ENSURE_ARG_POINTER(_retval);
614
615 RTSemFastMutexRequest(mLock);
616 CategoryNode* category = get_category(aCategoryName);
617 RTSemFastMutexRelease(mLock);
618
619 if (!category) {
620 return NS_NewEmptyEnumerator(_retval);
621 }
622
623 return category->Enumerate(_retval);
624}
625
626NS_IMETHODIMP
627nsCategoryManager::EnumerateCategories(nsISimpleEnumerator **_retval)
628{
629 NS_ENSURE_ARG_POINTER(_retval);
630
631 RTSemFastMutexRequest(mLock);
632 CategoryEnumerator* enumObj = CategoryEnumerator::Create(mTable);
633 RTSemFastMutexRelease(mLock);
634
635 if (!enumObj)
636 return NS_ERROR_OUT_OF_MEMORY;
637
638 *_retval = enumObj;
639 NS_ADDREF(*_retval);
640 return NS_OK;
641}
642
643struct writecat_struct {
644 PRTSTREAM fd;
645 PRBool success;
646};
647
648PLDHashOperator PR_CALLBACK
649enumfunc_categories(const char* aKey, CategoryNode* aCategory, void* userArg)
650{
651 writecat_struct* args = NS_STATIC_CAST(writecat_struct*, userArg);
652
653 PLDHashOperator result = PL_DHASH_NEXT;
654
655 if (!aCategory->WritePersistentEntries(args->fd, aKey)) {
656 args->success = PR_FALSE;
657 result = PL_DHASH_STOP;
658 }
659
660 return result;
661}
662
663NS_METHOD
664nsCategoryManager::WriteCategoryManagerToRegistry(PRTSTREAM fd)
665{
666 writecat_struct args = {
667 fd,
668 PR_TRUE
669 };
670
671 RTSemFastMutexRequest(mLock);
672 mTable.EnumerateRead(enumfunc_categories, &args);
673 RTSemFastMutexRelease(mLock);
674
675 if (!args.success) {
676 return NS_ERROR_UNEXPECTED;
677 }
678
679 return NS_OK;
680}
681
682class nsCategoryManagerFactory : public nsIFactory
683 {
684 public:
685 nsCategoryManagerFactory() { }
686
687 NS_DECL_ISUPPORTS
688 NS_DECL_NSIFACTORY
689 };
690
691NS_IMPL_ISUPPORTS1(nsCategoryManagerFactory, nsIFactory)
692
693NS_IMETHODIMP
694nsCategoryManagerFactory::CreateInstance( nsISupports* aOuter, const nsIID& aIID, void** aResult )
695 {
696 NS_ENSURE_ARG_POINTER(aResult);
697
698 *aResult = 0;
699
700 nsresult status = NS_OK;
701 if ( aOuter )
702 status = NS_ERROR_NO_AGGREGATION;
703 else
704 {
705 nsCategoryManager* raw_category_manager = nsCategoryManager::Create();
706 nsCOMPtr<nsICategoryManager> new_category_manager = raw_category_manager;
707 if ( new_category_manager )
708 status = new_category_manager->QueryInterface(aIID, aResult);
709 else
710 status = NS_ERROR_OUT_OF_MEMORY;
711 }
712
713 return status;
714 }
715
716NS_IMETHODIMP
717nsCategoryManagerFactory::LockFactory( PRBool )
718 {
719 // Not implemented...
720 return NS_OK;
721 }
722
723nsresult
724NS_CategoryManagerGetFactory( nsIFactory** aFactory )
725 {
726 // assert(aFactory);
727
728 nsresult status;
729
730 *aFactory = 0;
731 nsIFactory* new_factory = NS_STATIC_CAST(nsIFactory*, new nsCategoryManagerFactory);
732 if (new_factory)
733 {
734 *aFactory = new_factory;
735 NS_ADDREF(*aFactory);
736 status = NS_OK;
737 }
738 else
739 status = NS_ERROR_OUT_OF_MEMORY;
740
741 return status;
742 }
743
744
745
746/*
747 * CreateServicesFromCategory()
748 *
749 * Given a category, this convenience functions enumerates the category and
750 * creates a service of every CID or ContractID registered under the category.
751 * If observerTopic is non null and the service implements nsIObserver,
752 * this will attempt to notify the observer with the origin, observerTopic string
753 * as parameter.
754 */
755NS_COM nsresult
756NS_CreateServicesFromCategory(const char *category,
757 nsISupports *origin,
758 const char *observerTopic)
759{
760 nsresult rv = NS_OK;
761
762 int nFailed = 0;
763 nsCOMPtr<nsICategoryManager> categoryManager =
764 do_GetService("@mozilla.org/categorymanager;1", &rv);
765 if (!categoryManager) return rv;
766
767 nsCOMPtr<nsISimpleEnumerator> enumerator;
768 rv = categoryManager->EnumerateCategory(category,
769 getter_AddRefs(enumerator));
770 if (NS_FAILED(rv)) return rv;
771
772 nsCOMPtr<nsISupports> entry;
773 while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) {
774 // From here on just skip any error we get.
775 nsCOMPtr<nsISupportsCString> catEntry = do_QueryInterface(entry, &rv);
776 if (NS_FAILED(rv)) {
777 nFailed++;
778 continue;
779 }
780 nsCAutoString entryString;
781 rv = catEntry->GetData(entryString);
782 if (NS_FAILED(rv)) {
783 nFailed++;
784 continue;
785 }
786 nsXPIDLCString contractID;
787 rv = categoryManager->GetCategoryEntry(category,entryString.get(), getter_Copies(contractID));
788 if (NS_FAILED(rv)) {
789 nFailed++;
790 continue;
791 }
792
793 nsCOMPtr<nsISupports> instance = do_GetService(contractID, &rv);
794 if (NS_FAILED(rv)) {
795 nFailed++;
796 continue;
797 }
798
799 if (observerTopic) {
800 // try an observer, if it implements it.
801 nsCOMPtr<nsIObserver> observer = do_QueryInterface(instance, &rv);
802 if (NS_SUCCEEDED(rv) && observer)
803 observer->Observe(origin, observerTopic, EmptyString().get());
804 }
805 }
806 return (nFailed ? NS_ERROR_FAILURE : NS_OK);
807}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette