From 5f483e27f37900573fbf713c13c967081a1d1152 Mon Sep 17 00:00:00 2001 From: "benjamin%smedbergs.us" Date: Tue, 21 Mar 2006 14:43:56 +0000 Subject: [PATCH] Bug 326491 - leaked observer service leaks things on shutdown - r=darin --- docshell/base/nsDocShell.cpp | 1 - xpcom/build/nsXPCOMCID.h | 7 + xpcom/build/nsXPComInit.cpp | 10 +- xpcom/ds/nsObserverList.cpp | 134 +++++------ xpcom/ds/nsObserverList.h | 68 +++++- xpcom/ds/nsObserverService.cpp | 208 ++++++------------ xpcom/ds/nsObserverService.h | 20 +- xpcom/glue/nsTArray.h | 14 +- .../windowds/nsWindowDataSource.cpp | 3 +- 9 files changed, 221 insertions(+), 244 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 409080ebb63..966e03718b6 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -93,7 +93,6 @@ #include "nsIPrefBranch.h" #include "nsIPrefBranch2.h" #include "nsIWritablePropertyBag2.h" -#include "nsObserverService.h" // we want to explore making the document own the load group // so we can associate the document URI with the load group. diff --git a/xpcom/build/nsXPCOMCID.h b/xpcom/build/nsXPCOMCID.h index 4920322c401..26299091d0b 100644 --- a/xpcom/build/nsXPCOMCID.h +++ b/xpcom/build/nsXPCOMCID.h @@ -84,6 +84,13 @@ */ #define NS_ARRAY_CONTRACTID "@mozilla.org/array;1" +/** + * Observer Service ContractID + * The observer service implements the global nsIObserverService object. + * It should be used from the main thread only. + */ +#define NS_OBSERVERSERVICE_CONTRACTID "@mozilla.org/observer-service;1" + /** * The following are the CIDs and Contract IDs of the nsISupports wrappers for * primative types. diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index f37370fdbf1..febf92180d6 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -682,8 +682,9 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr) nsCOMPtr currentQ; NS_GetCurrentEventQ(getter_AddRefs(currentQ), eqs); - nsCOMPtr observerService = - do_GetService("@mozilla.org/observer-service;1"); + nsRefPtr observerService; + CallGetService("@mozilla.org/observer-service;1", + (nsObserverService**) getter_AddRefs(observerService)); if (observerService) { @@ -722,10 +723,13 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr) // We save the "xpcom-shutdown-loaders" observers to notify after // the observerservice is gone. - if (observerService) + if (observerService) { observerService-> EnumerateObservers(NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID, getter_AddRefs(moduleLoaders)); + + observerService->Shutdown(); + } } // XPCOM is officially in shutdown mode NOW diff --git a/xpcom/ds/nsObserverList.cpp b/xpcom/ds/nsObserverList.cpp index 6a85f8acaca..7f6e5799aca 100644 --- a/xpcom/ds/nsObserverList.cpp +++ b/xpcom/ds/nsObserverList.cpp @@ -37,53 +37,29 @@ #include "nsObserverList.h" -#include "pratom.h" -#include "nsAutoLock.h" #include "nsAutoPtr.h" -#include "nsCOMPtr.h" -#include "nsIObserver.h" +#include "nsCOMArray.h" #include "nsISimpleEnumerator.h" -#include "nsIWeakReference.h" - -nsObserverList::nsObserverList(nsresult &rv) -{ - MOZ_COUNT_CTOR(nsObserverList); - mLock = PR_NewLock(); - if (!mLock) - rv = NS_ERROR_OUT_OF_MEMORY; -} - -nsObserverList::~nsObserverList(void) -{ - MOZ_COUNT_DTOR(nsObserverList); - if (mLock) - PR_DestroyLock(mLock); -} nsresult nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak) { - NS_ENSURE_ARG(anObserver); + NS_ASSERTION(anObserver, "Null input"); - nsAutoLock lock(mLock); + if (!ownsWeak) { + ObserverRef* o = mObservers.AppendElement(anObserver); + if (!o) + return NS_ERROR_OUT_OF_MEMORY; - nsCOMPtr observerRef; - if (ownsWeak) { - nsCOMPtr - weakRefFactory(do_QueryInterface(anObserver)); - NS_ASSERTION(weakRefFactory, - "Doesn't implement nsISupportsWeakReference"); - if (weakRefFactory) - weakRefFactory-> - GetWeakReference((nsIWeakReference**)(nsISupports**) - getter_AddRefs(observerRef)); - } else { - observerRef = anObserver; + return NS_OK; } - if (!observerRef) - return NS_ERROR_FAILURE; + + nsCOMPtr weak = do_GetWeakReference(anObserver); + if (!weak) + return NS_NOINTERFACE; - if (!mObservers.AppendObject(observerRef)) + ObserverRef *o = mObservers.AppendElement(weak); + if (!o) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; @@ -92,51 +68,25 @@ nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak) nsresult nsObserverList::RemoveObserver(nsIObserver* anObserver) { - NS_ENSURE_ARG(anObserver); + NS_ASSERTION(anObserver, "Null input"); - nsAutoLock lock(mLock); - - if (mObservers.RemoveObject(anObserver)) + if (mObservers.RemoveElement(NS_STATIC_CAST(nsISupports*, anObserver))) return NS_OK; - nsCOMPtr - weakRefFactory(do_QueryInterface(anObserver)); - if (!weakRefFactory) - return NS_ERROR_FAILURE; - - nsCOMPtr observerRef; - weakRefFactory->GetWeakReference(getter_AddRefs(observerRef)); - + nsCOMPtr observerRef = do_GetWeakReference(anObserver); if (!observerRef) return NS_ERROR_FAILURE; - if (!mObservers.RemoveObject(observerRef)) + if (!mObservers.RemoveElement(observerRef)) return NS_ERROR_FAILURE; return NS_OK; } -class nsObserverEnumerator : public nsISimpleEnumerator -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSISIMPLEENUMERATOR - - nsObserverEnumerator(nsCOMArray &aObservers); - -private: - ~nsObserverEnumerator() { } - - PRUint32 mIndex; // Counts down, ends at 0 - nsCOMArray mObservers; -}; - nsresult nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator) { - nsAutoLock lock(mLock); - - nsRefPtr e(new nsObserverEnumerator(mObservers)); + nsRefPtr e(new nsObserverEnumerator(this)); if (!e) return NS_ERROR_OUT_OF_MEMORY; @@ -144,41 +94,65 @@ nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator) return NS_OK; } -nsObserverEnumerator::nsObserverEnumerator(nsCOMArray &aObservers) +void +nsObserverList::FillObserverArray(nsCOMArray &aArray) { - for (PRInt32 i = 0; i < aObservers.Count(); ++i) { - nsCOMPtr weak(do_QueryInterface(aObservers[i])); - if (weak) { - nsCOMPtr strong(do_QueryReferent(weak)); - if (strong) - mObservers.AppendObject(strong); + aArray.SetCapacity(mObservers.Length()); + + for (PRInt32 i = mObservers.Length() - 1; i >= 0; --i) { + if (mObservers[i].isWeakRef) { + nsCOMPtr o(do_QueryReferent(mObservers[i].asWeak())); + if (o) { + aArray.AppendObject(o); + } + else { + // the object has gone away, remove the weakref + mObservers.RemoveElementAt(i); + } } else { - mObservers.AppendObject(aObservers[i]); + aArray.AppendObject(mObservers[i].asObserver()); } } +} - mIndex = mObservers.Count(); +void +nsObserverList::NotifyObservers(nsISupports *aSubject, + const char *aTopic, + const PRUnichar *someData) +{ + nsCOMArray observers; + FillObserverArray(observers); + + for (PRInt32 i = 0; i < observers.Count(); ++i) { + observers[i]->Observe(aSubject, aTopic, someData); + } } NS_IMPL_ISUPPORTS1(nsObserverEnumerator, nsISimpleEnumerator) +nsObserverEnumerator::nsObserverEnumerator(nsObserverList* aObserverList) + : mIndex(0) +{ + aObserverList->FillObserverArray(mObservers); +} + NS_IMETHODIMP nsObserverEnumerator::HasMoreElements(PRBool *aResult) { - *aResult = (mIndex > 0); + *aResult = (mIndex < mObservers.Count()); return NS_OK; } NS_IMETHODIMP nsObserverEnumerator::GetNext(nsISupports* *aResult) { - if (!mIndex) { + if (mIndex == mObservers.Count()) { NS_ERROR("Enumerating after HasMoreElements returned false."); return NS_ERROR_UNEXPECTED; } - --mIndex; NS_ADDREF(*aResult = mObservers[mIndex]); + ++mIndex; return NS_OK; } diff --git a/xpcom/ds/nsObserverList.h b/xpcom/ds/nsObserverList.h index 6706cae65b7..e55ce236743 100644 --- a/xpcom/ds/nsObserverList.h +++ b/xpcom/ds/nsObserverList.h @@ -39,25 +39,75 @@ #define nsObserverList_h___ #include "nsISupports.h" +#include "nsTArray.h" +#include "nsCOMPtr.h" #include "nsCOMArray.h" +#include "nsIObserver.h" +#include "nsIWeakReference.h" +#include "nsHashKeys.h" +#include "nsISimpleEnumerator.h" -class nsISimpleEnumerator; -class nsIObserver; +struct ObserverRef +{ + ObserverRef(const ObserverRef& o) : + isWeakRef(o.isWeakRef), ref(o.ref) { } + + ObserverRef(nsIObserver* aObserver) : isWeakRef(PR_FALSE), ref(aObserver) { } + ObserverRef(nsIWeakReference* aWeak) : isWeakRef(PR_TRUE), ref(aWeak) { } -class nsObserverList + PRBool isWeakRef; + nsCOMPtr ref; + + nsIObserver* asObserver() { + NS_ASSERTION(!isWeakRef, "Isn't a strong ref."); + return NS_STATIC_CAST(nsIObserver*, (nsISupports*) ref); + } + + nsIWeakReference* asWeak() { + NS_ASSERTION(isWeakRef, "Isn't a weak ref."); + return NS_STATIC_CAST(nsIWeakReference*, (nsISupports*) ref); + } + + PRBool operator==(nsISupports* b) const { return ref == b; } +}; + +class nsObserverList : public nsCharPtrHashKey { public: - nsObserverList(nsresult &rv); - ~nsObserverList(); + nsObserverList(const char *key) : nsCharPtrHashKey(key) + { MOZ_COUNT_CTOR(nsObserverList); } + + ~nsObserverList() { MOZ_COUNT_DTOR(nsObserverList); } nsresult AddObserver(nsIObserver* anObserver, PRBool ownsWeak); nsresult RemoveObserver(nsIObserver* anObserver); + + void NotifyObservers(nsISupports *aSubject, + const char *aTopic, + const PRUnichar *someData); nsresult GetObserverList(nsISimpleEnumerator** anEnumerator); - -protected: - PRLock* mLock; - nsCOMArray mObservers; + + // Fill an array with the observers of this category. + // The array is filled in last-added-first order. + void FillObserverArray(nsCOMArray &aArray); + +private: + nsTArray mObservers; }; +class nsObserverEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + nsObserverEnumerator(nsObserverList* aObserverList); + +private: + ~nsObserverEnumerator() { } + + PRInt32 mIndex; // Counts up from 0 + nsCOMArray mObservers; +}; #endif /* nsObserverList_h___ */ diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index ea93aff8c31..c5b11be88f9 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -37,7 +37,7 @@ * ***** END LICENSE BLOCK ***** */ #include "prlog.h" -#include "prlock.h" +#include "nsAutoPtr.h" #include "nsIFactory.h" #include "nsIServiceManager.h" #include "nsIComponentManager.h" @@ -48,6 +48,8 @@ #include "nsObserverList.h" #include "nsHashtable.h" #include "nsIWeakReference.h" +#include "nsIThread.h" +#include "nsIEnumerator.h" #define NOTIFY_GLOBAL_OBSERVERS @@ -68,17 +70,26 @@ PRLogModuleInfo* observerServiceLog = nsnull; // nsObserverService Implementation -NS_IMPL_THREADSAFE_ISUPPORTS1(nsObserverService, nsIObserverService) +NS_IMPL_THREADSAFE_ISUPPORTS2(nsObserverService, nsIObserverService, nsObserverService) -nsObserverService::nsObserverService() - : mObserverTopicTable(nsnull) +nsObserverService::nsObserverService() : + mShuttingDown(PR_FALSE) { + mObserverTopicTable.Init(); } nsObserverService::~nsObserverService(void) { - if(mObserverTopicTable) - delete mObserverTopicTable; + Shutdown(); +} + +void +nsObserverService::Shutdown() +{ + mShuttingDown = PR_TRUE; + + if (mObserverTopicTable.IsInitialized()) + mObserverTopicTable.Clear(); } NS_METHOD @@ -89,158 +100,85 @@ nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstanc observerServiceLog = PR_NewLogModule("ObserverService"); #endif - nsresult rv; - nsObserverService* os = new nsObserverService(); - if (os == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(os); - rv = os->QueryInterface(aIID, aInstancePtr); - NS_RELEASE(os); - return rv; -} + nsRefPtr os = new nsObserverService(); -static PRBool PR_CALLBACK -ReleaseObserverList(nsHashKey *aKey, void *aData, void* closure) -{ - nsObserverList* observerList = NS_STATIC_CAST(nsObserverList*, aData); - delete(observerList); - return PR_TRUE; -} - -nsresult nsObserverService::GetObserverList(const char* aTopic, nsObserverList** anObserverList) -{ - if (anObserverList == nsnull) - return NS_ERROR_NULL_POINTER; - - if(mObserverTopicTable == nsnull) - { - mObserverTopicTable = new nsObjectHashtable(nsnull, - nsnull, // should never be cloned - ReleaseObserverList, - nsnull, - 256, - PR_TRUE); - if (mObserverTopicTable == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - } - - - nsCStringKey key(aTopic); - - nsObserverList *topicObservers; - topicObservers = (nsObserverList *) mObserverTopicTable->Get(&key); - - if (topicObservers) - { - *anObserverList = topicObservers; - return NS_OK; - } - - nsresult rv = NS_OK; - topicObservers = new nsObserverList(rv); - if (!topicObservers) + // The cast is required for MSVC6, otherwise it complains about calling + // a private function. + if (!os || !((nsObserverService*) os)->mObserverTopicTable.IsInitialized()) return NS_ERROR_OUT_OF_MEMORY; - if (NS_FAILED(rv)) { - delete topicObservers; - return rv; + return os->QueryInterface(aIID, aInstancePtr); +} + +#define NS_ENSURE_VALIDCALL \ + if (!nsIThread::IsMainThread()) { \ + NS_ERROR("Using observer service off the main thread!"); \ + return NS_ERROR_UNEXPECTED; \ + } \ + if (mShuttingDown) { \ + NS_ERROR("Using observer service after XPCOM shutdown!"); \ + return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; \ } - - *anObserverList = topicObservers; - mObserverTopicTable->Put(&key, topicObservers); - - return NS_OK; + +NS_IMETHODIMP +nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic, + PRBool ownsWeak) +{ + NS_ENSURE_VALIDCALL + NS_ENSURE_ARG(anObserver && aTopic); + + nsObserverList *observerList = mObserverTopicTable.PutEntry(aTopic); + if (!observerList) + return NS_ERROR_OUT_OF_MEMORY; + + return observerList->AddObserver(anObserver, ownsWeak); } -NS_IMETHODIMP nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic, PRBool ownsWeak) +NS_IMETHODIMP +nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic) { - nsObserverList* anObserverList; - nsresult rv; + NS_ENSURE_VALIDCALL + NS_ENSURE_ARG(anObserver && aTopic); - if (anObserver == nsnull || aTopic == nsnull) - return NS_ERROR_NULL_POINTER; + nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic); + if (!observerList) + return NS_ERROR_FAILURE; - rv = GetObserverList(aTopic, &anObserverList); - if (NS_FAILED(rv)) return rv; - - return anObserverList->AddObserver(anObserver, ownsWeak); + return observerList->RemoveObserver(anObserver); } -NS_IMETHODIMP nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic) +NS_IMETHODIMP +nsObserverService::EnumerateObservers(const char* aTopic, + nsISimpleEnumerator** anEnumerator) { - nsObserverList* anObserverList; - nsresult rv; + NS_ENSURE_VALIDCALL + NS_ENSURE_ARG(aTopic && anEnumerator); - if (anObserver == nsnull || aTopic == nsnull) - return NS_ERROR_NULL_POINTER; + nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic); + if (!observerList) + return NS_NewEmptyEnumerator(anEnumerator); - rv = GetObserverList(aTopic, &anObserverList); - if (NS_FAILED(rv)) return rv; - - return anObserverList->RemoveObserver(anObserver); -} - -NS_IMETHODIMP nsObserverService::EnumerateObservers(const char* aTopic, nsISimpleEnumerator** anEnumerator) -{ - nsObserverList* anObserverList; - nsresult rv; - - if (anEnumerator == nsnull || aTopic == nsnull) - return NS_ERROR_NULL_POINTER; - - rv = GetObserverList(aTopic, &anObserverList); - if (NS_FAILED(rv)) return rv; - - return anObserverList->GetObserverList(anEnumerator); + return observerList->GetObserverList(anEnumerator); } // Enumerate observers of aTopic and call Observe on each. NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports *aSubject, const char *aTopic, - const PRUnichar *someData) { - nsresult rv = NS_OK; -#ifdef NOTIFY_GLOBAL_OBSERVERS - nsCOMPtr globalObservers; -#endif - nsCOMPtr observers; - nsCOMPtr observerRef; + const PRUnichar *someData) +{ + NS_ENSURE_VALIDCALL + NS_ENSURE_ARG(aTopic); + + nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic); + if (observerList) + observerList->NotifyObservers(aSubject, aTopic, someData); #ifdef NOTIFY_GLOBAL_OBSERVERS - EnumerateObservers("*", getter_AddRefs(globalObservers)); -#endif - rv = EnumerateObservers(aTopic, getter_AddRefs(observers)); -#ifdef NOTIFY_GLOBAL_OBSERVERS - /* If there are no global observers and we failed to get normal observers - * then we return the error indicating failure to get normal observers. - */ - if (!globalObservers && NS_FAILED(rv)) - return rv; + observerList = mObserverTopicTable.GetEntry("*"); + if (observerList) + observerList->NotifyObservers(aSubject, aTopic, someData); #endif - do - { - PRBool more = PR_FALSE; - /* If observers is non null then null it out unless it really - * has more elements (i.e. that call doesn't fail). - */ - if (observers && NS_FAILED(observers->HasMoreElements(&more)) || !more) - { -#ifdef NOTIFY_GLOBAL_OBSERVERS - if (observers = globalObservers) - globalObservers = nsnull; -#else - observers = nsnull; -#endif - } - else - { - observers->GetNext(getter_AddRefs(observerRef)); - nsCOMPtr observer = do_QueryInterface(observerRef); - if (observer) - observer->Observe(aSubject, aTopic, someData); - } - } while (observers); return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// diff --git a/xpcom/ds/nsObserverService.h b/xpcom/ds/nsObserverService.h index 0a08f2aeab5..1f30b79c14a 100644 --- a/xpcom/ds/nsObserverService.h +++ b/xpcom/ds/nsObserverService.h @@ -39,37 +39,37 @@ #define nsObserverService_h___ #include "nsIObserverService.h" +#include "nsObserverList.h" +#include "nsTHashtable.h" #define NS_OBSERVERSERVICE_CONTRACTID "@mozilla.org/observer-service;1" #define NS_OBSERVERSERVICE_CLASSNAME "Observer Service" -class nsObserverList; -class nsObjectHashtable; - // {D07F5195-E3D1-11d2-8ACD-00105A1B8860} #define NS_OBSERVERSERVICE_CID \ { 0xd07f5195, 0xe3d1, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } } class nsObserverService : public nsIObserverService { public: - NS_DEFINE_STATIC_CID_ACCESSOR( NS_OBSERVERSERVICE_CID ) + NS_DECLARE_STATIC_IID_ACCESSOR(NS_OBSERVERSERVICE_CID) nsObserverService(); - + NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVERSERVICE + void Shutdown(); + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); private: ~nsObserverService(void); - nsObjectHashtable* mObserverTopicTable; - - nsresult GetObserverList(const char* aTopic, nsObserverList** anObserverList); - - + PRBool mShuttingDown; + nsTHashtable mObserverTopicTable; }; +NS_DEFINE_STATIC_IID_ACCESSOR(nsObserverService, NS_OBSERVERSERVICE_CID) + #endif /* nsObserverService_h___ */ diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index faeae00c8cf..b4a73708f3f 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -482,18 +482,22 @@ class nsTArray : public nsTArray_base { // and destroy" the first element that is equal to the given element. // @param item The item to search for. // @param comp The Comparator used to determine element equality. + // @return PR_TRUE if the element was found template - void RemoveElement(const Item& item, const Comparator& comp) { + PRBool RemoveElement(const Item& item, const Comparator& comp) { index_type i = IndexOf(item, 0, comp); - if (i != NoIndex) - RemoveElementAt(i); + if (i == NoIndex) + return PR_FALSE; + + RemoveElementAt(i); + return PR_TRUE; } // A variation on the RemoveElement method defined above that assumes // that 'operator==' is defined for elem_type. template - void RemoveElement(const Item& item) { - RemoveElement(item, nsDefaultComparator()); + PRBool RemoveElement(const Item& item) { + return RemoveElement(item, nsDefaultComparator()); } // diff --git a/xpfe/components/windowds/nsWindowDataSource.cpp b/xpfe/components/windowds/nsWindowDataSource.cpp index 1a0f66b809b..e1444a98673 100644 --- a/xpfe/components/windowds/nsWindowDataSource.cpp +++ b/xpfe/components/windowds/nsWindowDataSource.cpp @@ -41,8 +41,9 @@ #include "nsIRDFContainerUtils.h" #include "nsIServiceManager.h" #include "nsReadableUtils.h" -#include "nsObserverService.h" +#include "nsIObserverService.h" #include "nsIWindowMediator.h" +#include "nsXPCOMCID.h" // just to do the reverse-lookup! sheesh. #include "nsIInterfaceRequestorUtils.h"