/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include #include "nsCOMPtr.h" #include "nsComponentManager.h" #include "nsIServiceManager.h" #include "nsSpecialSystemDirectory.h" #include "nsCRT.h" #include "nsIEnumerator.h" #include "nsIModule.h" #include "nsHashtableEnumerator.h" #include "nsISupportsPrimitives.h" #include "plstr.h" #include "prlink.h" #include "prsystem.h" #include "prprf.h" #include "xcDll.h" #include "prerror.h" #include "prmem.h" #include "prcmon.h" #include "prthread.h" /* XXX: only used for the NSPR initialization hack (rick) */ #ifdef XP_BEOS #include #include #endif // Logging of debug output #define FORCE_PR_LOG /* Allow logging in the release build */ #include "prlog.h" PRLogModuleInfo* nsComponentManagerLog = NULL; // Enable printing of critical errors on screen even for release builds #define PRINT_CRITICAL_ERROR_TO_SCREEN // Common Key Names const char xpcomBaseName[]="XPCOM"; const char xpcomKeyName[] ="Software/Netscape/XPCOM"; const char netscapeKeyName[]="Software/Netscape"; const char classesKeyName[]="Classes"; const char classIDKeyName[]="CLSID"; const char classesClassIDKeyName[]="Classes/CLSID"; // Common Value Names const char classIDValueName[]="CLSID"; const char versionValueName[]="VersionString"; const char lastModValueName[]="LastModTimeStamp"; const char fileSizeValueName[]="FileSize"; const char componentCountValueName[]="ComponentsCount"; const char progIDValueName[]="ProgID"; const char classNameValueName[]="ClassName"; const char inprocServerValueName[]="InprocServer"; // We define a CID that is used to indicate the non-existence of a // progid in the hash table. #define NS_NO_CID { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } static NS_DEFINE_CID(kNoCID, NS_NO_CID); // Build is using USE_NSREG to turn off xpcom using registry // but internally we use USE_REGISTRY. Map them propertly. #ifdef USE_NSREG #define USE_REGISTRY #endif /* USE_NSREG */ //////////////////////////////////////////////////////////////////////////////// // nsFactoryEntry //////////////////////////////////////////////////////////////////////////////// nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, nsDll *aDll) : cid(aClass), factory(NULL), dll(aDll) { } nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, nsIFactory *aFactory) : cid(aClass), factory(aFactory), dll(NULL) { NS_ADDREF(aFactory); } nsFactoryEntry::~nsFactoryEntry(void) { if (factory != NULL) { NS_RELEASE(factory); } // DO NOT DELETE nsDll *dll; } //////////////////////////////////////////////////////////////////////////////// // autoStringFree //////////////////////////////////////////////////////////////////////////////// // // To prevent leaks, we are using this class. Typical use would be // for each ptr to be deleted, create an object of these types with that ptr. // Once that object goes out of scope, deletion and hence memory free will // automatically happen. // class autoStringFree { public: enum DeleteModel { NSPR_Delete = 1, nsCRT_String_Delete = 2 }; autoStringFree(char *Ptr, DeleteModel whichDelete): mPtr(Ptr), mWhichDelete(whichDelete) {} ~autoStringFree() { if (mPtr) if (mWhichDelete == NSPR_Delete) { PR_FREEIF(mPtr); } else if (mWhichDelete == nsCRT_String_Delete) nsCRT::free(mPtr); else PR_ASSERT(0); } private: char *mPtr; DeleteModel mWhichDelete; }; //////////////////////////////////////////////////////////////////////////////// // nsComponentManagerImpl //////////////////////////////////////////////////////////////////////////////// nsComponentManagerImpl::nsComponentManagerImpl() : mFactories(NULL), mProgIDs(NULL), mMon(NULL), mDllStore(NULL), mRegistry(NULL), mPrePopulationDone(PR_FALSE) { NS_INIT_REFCNT(); } PRBool nsFactoryEntry_Destroy(nsHashKey *aKey, void *aData, void* closure) { nsFactoryEntry* entry = NS_STATIC_CAST(nsFactoryEntry*, aData); delete entry; return PR_TRUE; } PRBool nsCID_Destroy(nsHashKey *aKey, void *aData, void* closure) { nsCID* entry = NS_STATIC_CAST(nsCID*, aData); // nasty hack. We "know" that kNoCID was entered into the hash table. if (entry != &kNoCID) delete entry; return PR_TRUE; } PRBool nsDll_Destroy(nsHashKey *aKey, void *aData, void* closure) { nsDll* entry = NS_STATIC_CAST(nsDll*, aData); delete entry; return PR_TRUE; } nsresult nsComponentManagerImpl::Init(void) { if (nsComponentManagerLog == NULL) { nsComponentManagerLog = PR_NewLogModule("nsComponentManager"); } if (mFactories == NULL) { mFactories = new nsObjectHashtable(nsnull, nsnull, // should never be copied nsFactoryEntry_Destroy, nsnull, 256, /* Thread Safe */ PR_TRUE); if (mFactories == NULL) return NS_ERROR_OUT_OF_MEMORY; } if (mProgIDs == NULL) { mProgIDs = new nsObjectHashtable(nsnull, nsnull, // should never be copied nsCID_Destroy, nsnull, 256, /* Thread Safe */ PR_TRUE); if (mProgIDs == NULL) return NS_ERROR_OUT_OF_MEMORY; } if (mMon == NULL) { mMon = PR_NewMonitor(); if (mMon == NULL) return NS_ERROR_OUT_OF_MEMORY; } if (mDllStore == NULL) { mDllStore = new nsObjectHashtable(nsnull, nsnull, // should never be copied nsDll_Destroy, nsnull, 256, /* Thead Safe */ PR_TRUE); if (mDllStore == NULL) return NS_ERROR_OUT_OF_MEMORY; } PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Initialized.")); #ifdef USE_REGISTRY PlatformInit(); #endif return NS_OK; } nsComponentManagerImpl::~nsComponentManagerImpl() { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Beginning destruction.")); // Release all cached factories if (mFactories) delete mFactories; // Unload libraries UnloadLibraries(NULL); // Release Progid hash tables if (mProgIDs) delete mProgIDs; // Release dll abstraction storage if (mDllStore) delete mDllStore; #ifdef USE_REGISTRY // Release registry if(mRegistry) NS_RELEASE(mRegistry); #endif /* USE_REGISTRY */ // Destroy the Lock if (mMon) PR_DestroyMonitor(mMon); PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Destroyed.")); } NS_IMPL_ISUPPORTS1(nsComponentManagerImpl, nsIComponentManager) //////////////////////////////////////////////////////////////////////////////// // nsComponentManagerImpl: Platform methods //////////////////////////////////////////////////////////////////////////////// #ifdef USE_REGISTRY nsresult nsComponentManagerImpl::PlatformInit(void) { nsresult rv = NS_ERROR_FAILURE; // We need to create our registry. Since we are in the constructor // we haven't gone as far as registering the registry factory. // Hence, we hand create a registry. if (mRegistry == NULL) { nsIFactory *registryFactory = NULL; rv = NS_RegistryGetFactory(®istryFactory); if (NS_SUCCEEDED(rv)) { rv = registryFactory->CreateInstance(NULL, NS_GET_IID(nsIRegistry),(void **)&mRegistry); if (NS_FAILED(rv)) return rv; NS_RELEASE(registryFactory); } } #ifdef XP_UNIX // Create ~/.mozilla as that is the default place for the registry file /* The default registry on the unix system is $HOME/.mozilla/registry per * vr_findGlobalRegName(). vr_findRegFile() will create the registry file * if it doesn't exist. But it wont create directories. * * Hence we need to create the directory if it doesn't exist already. * * Why create it here as opposed to the app ? * ------------------------------------------ * The app cannot create the directory in main() as most of the registry * and initialization happens due to use of static variables. * And we dont want to be dependent on the order in which * these static stuff happen. * * Permission for the $HOME/.mozilla will be Read,Write,Execute * for user only. Nothing to group and others. */ char *home = getenv("HOME"); if (home != NULL) { char dotMozillaDir[1024]; PR_snprintf(dotMozillaDir, sizeof(dotMozillaDir), "%s/" NS_MOZILLA_DIR_NAME, home); if (PR_Access(dotMozillaDir, PR_ACCESS_EXISTS) != PR_SUCCESS) { PR_MkDir(dotMozillaDir, NS_MOZILLA_DIR_PERMISSION); PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Creating Directory %s", dotMozillaDir)); } } #endif /* XP_UNIX */ #ifdef XP_BEOS BPath p; const char *settings = "/boot/home/config/settings"; if(find_directory(B_USER_SETTINGS_DIRECTORY, &p) == B_OK) settings = p.Path(); char settingsMozillaDir[1024]; PR_snprintf(settingsMozillaDir, sizeof(settingsMozillaDir), "%s/" NS_MOZILLA_DIR_NAME, settings); if (PR_Access(settingsMozillaDir, PR_ACCESS_EXISTS) != PR_SUCCESS) { PR_MkDir(settingsMozillaDir, NS_MOZILLA_DIR_PERMISSION); printf("nsComponentManager: Creating Directory %s\n", settingsMozillaDir); PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Creating Directory %s", settingsMozillaDir)); } #endif // Open the App Components registry. We will keep it open forever! rv = mRegistry->OpenWellKnownRegistry(nsIRegistry::ApplicationComponentRegistry); if (NS_FAILED(rv)) return rv; // Check the version of registry. Nuke old versions. PlatformVersionCheck(); // Open common registry keys here to speed access // Do this after PlatformVersionCheck as it may re-create our keys rv = mRegistry->AddSubtree(nsIRegistry::Common, xpcomKeyName, &mXPCOMKey); if (NS_FAILED(rv)) return rv; rv = mRegistry->AddSubtree(nsIRegistry::Common, classesKeyName, &mClassesKey); if (NS_FAILED(rv)) return rv; rv = mRegistry->AddSubtree(nsIRegistry::Common, classIDKeyName, &mCLSIDKey); if (NS_FAILED(rv)) return rv; return rv; } /** * PlatformVersionCheck() * * Checks to see if the XPCOM hierarchy in the registry is the same as that of * the software as defined by NS_XPCOM_COMPONENT_MANAGER_VERSION_STRING */ nsresult nsComponentManagerImpl::PlatformVersionCheck() { nsIRegistry::Key xpcomKey; nsresult rv; rv = mRegistry->AddSubtree(nsIRegistry::Common, xpcomKeyName, &xpcomKey); if (NS_FAILED(rv)) return rv; char *buf; nsresult err = mRegistry->GetString(xpcomKey, versionValueName, &buf); autoStringFree delete_buf(buf, autoStringFree::NSPR_Delete); // If there is a version mismatch or no version string, we got an old registry. // Delete the old repository hierarchies and recreate version string if (NS_FAILED(err) || PL_strcmp(buf, NS_XPCOM_COMPONENT_MANAGER_VERSION_STRING)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Registry version mismatch (%s vs %s). Nuking xpcom " "registry hierarchy.", buf, NS_XPCOM_COMPONENT_MANAGER_VERSION_STRING)); // Delete the XPCOM and CLSID hierarchy nsIRegistry::Key netscapeKey; rv = mRegistry->GetSubtree(nsIRegistry::Common,netscapeKeyName, &netscapeKey); if(NS_FAILED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Failed To Get Subtree (%s)",netscapeKeyName)); } else { rv = mRegistry->RemoveSubtreeRaw(netscapeKey, xpcomBaseName); if(NS_FAILED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Failed To Nuke Subtree (%s)",xpcomKeyName)); return rv; } } rv = mRegistry->GetSubtree(nsIRegistry::Common,classesKeyName, &netscapeKey); if(NS_FAILED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Failed To Get Subtree (%s)",classesKeyName)); } else { rv = mRegistry->RemoveSubtreeRaw(netscapeKey, classIDKeyName); if(NS_FAILED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Failed To Nuke Subtree (%s/%s)",classesKeyName,classIDKeyName)); return rv; } } // Recreate XPCOM and CLSID keys rv = mRegistry->AddSubtree(nsIRegistry::Common,xpcomKeyName, &xpcomKey); if(NS_FAILED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Failed To Add Subtree (%s)",xpcomKeyName)); return rv; } rv = mRegistry->AddSubtree(nsIRegistry::Common,classesClassIDKeyName, NULL); if(NS_FAILED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Failed To Add Subtree (%s)",classesClassIDKeyName)); return rv; } rv = mRegistry->SetString(xpcomKey,versionValueName, NS_XPCOM_COMPONENT_MANAGER_VERSION_STRING); if(NS_FAILED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Failed To Set String (Version) Under (%s)",xpcomKeyName)); return rv; } } else { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: platformVersionCheck() passed.")); } return NS_OK; } void nsComponentManagerImpl::PlatformGetFileInfo(nsIRegistry::Key key, PRUint32 *lastModifiedTime, PRUint32 *fileSize) { PR_ASSERT(lastModifiedTime); PR_ASSERT(fileSize); nsresult rv; int32 lastMod; rv = mRegistry->GetInt(key, lastModValueName, &lastMod); if (NS_SUCCEEDED(rv)) { *lastModifiedTime = lastMod; } int32 fsize = 0; rv = mRegistry->GetInt(key, fileSizeValueName, &fsize); if (NS_SUCCEEDED(rv)) { *fileSize = fsize; } } void nsComponentManagerImpl::PlatformSetFileInfo(nsIRegistry::Key key, PRUint32 lastModifiedTime, PRUint32 fileSize) { mRegistry->SetInt(key, lastModValueName, lastModifiedTime); mRegistry->SetInt(key, fileSizeValueName, fileSize); } /** * PlatformCreateDll(const char *fullname) * * Creates a nsDll from the registry representation of dll 'fullname'. * Looks under * ROOTKEY_COMMON/Software/Netscape/XPCOM/fullname */ nsresult nsComponentManagerImpl::PlatformCreateDll(const char *fullname, nsDll* *result) { PR_ASSERT(mRegistry!=NULL); nsresult rv; nsIRegistry::Key fullnameKey; rv = mRegistry->GetSubtreeRaw(mXPCOMKey,fullname, &fullnameKey); if(NS_FAILED(rv)) { return rv; } PRUint32 lastModTime = 0; PRUint32 fileSize = 0; PlatformGetFileInfo(fullnameKey, &lastModTime, &fileSize); nsDll *dll = new nsDll(fullname, lastModTime, fileSize); if (dll == NULL) { return NS_ERROR_OUT_OF_MEMORY; } *result = dll; return NS_OK; } /** * PlatformMarkNoComponents(nsDll *dll) * * Stores the dll name, last modified time, size and 0 for number of * components in dll in the registry at location * ROOTKEY_COMMON/Software/Netscape/XPCOM/dllname */ nsresult nsComponentManagerImpl::PlatformMarkNoComponents(nsDll *dll) { PR_ASSERT(mRegistry!=NULL); nsresult rv; nsIRegistry::Key dllPathKey; rv = mRegistry->AddSubtreeRaw(mXPCOMKey, dll->GetPersistentDescriptorString(), &dllPathKey); if(NS_FAILED(rv)) { return rv; } PlatformSetFileInfo(dllPathKey, dll->GetLastModifiedTime(), dll->GetSize()); rv = mRegistry->SetInt(dllPathKey, componentCountValueName, 0); return rv; } // XXX PlatformRegister needs to deal with dllName type dlls nsresult nsComponentManagerImpl::PlatformRegister(const char *cidString, const char *className, const char * progID, nsDll *dll) { // Preconditions PR_ASSERT(cidString != NULL); PR_ASSERT(dll != NULL); PR_ASSERT(mRegistry !=NULL); nsresult rv; nsIRegistry::Key IDkey; rv = mRegistry->AddSubtreeRaw(mCLSIDKey, cidString, &IDkey); if (NS_FAILED(rv)) return (rv); rv = mRegistry->SetString(IDkey,classNameValueName, className); if (progID) { rv = mRegistry->SetString(IDkey,progIDValueName, progID); } rv = mRegistry->SetString(IDkey, inprocServerValueName, dll->GetPersistentDescriptorString()); if (progID) { nsIRegistry::Key progIDKey; rv = mRegistry->AddSubtreeRaw(mClassesKey, progID, &progIDKey); rv = mRegistry->SetString(progIDKey, classIDValueName, cidString); } // XXX Gross. LongLongs dont have a serialization format. This makes // XXX the registry non-xp. Someone beat on the nspr people to get // XXX a longlong serialization function please! nsIRegistry::Key dllPathKey; rv = mRegistry->AddSubtreeRaw(mXPCOMKey,dll->GetPersistentDescriptorString(), &dllPathKey); PlatformSetFileInfo(dllPathKey, dll->GetLastModifiedTime(), dll->GetSize()); int32 nComponents = 0; rv = mRegistry->GetInt(dllPathKey, componentCountValueName, &nComponents); nComponents++; rv = mRegistry->SetInt(dllPathKey,componentCountValueName, nComponents); return rv; } nsresult nsComponentManagerImpl::PlatformUnregister(const char *cidString, const char *aLibrary) { PR_ASSERT(mRegistry!=NULL); nsresult rv; nsIRegistry::Key cidKey; rv = mRegistry->AddSubtreeRaw(mCLSIDKey, cidString, &cidKey); char *progID = NULL; rv = mRegistry->GetString(cidKey, progIDValueName, &progID); if(NS_SUCCEEDED(rv)) { mRegistry->RemoveSubtreeRaw(mClassesKey, progID); PR_FREEIF(progID); } mRegistry->RemoveSubtree(mCLSIDKey, cidString); nsIRegistry::Key libKey; rv = mRegistry->GetSubtreeRaw(mXPCOMKey, aLibrary, &libKey); if(NS_FAILED(rv)) return rv; // We need to reduce the ComponentCount by 1. // If the ComponentCount hits 0, delete the entire key. int32 nComponents = 0; rv = mRegistry->GetInt(libKey, componentCountValueName, &nComponents); if(NS_FAILED(rv)) return rv; nComponents--; if (nComponents <= 0) { rv = mRegistry->RemoveSubtreeRaw(mXPCOMKey, aLibrary); } else { rv = mRegistry->SetInt(libKey, componentCountValueName, nComponents); } return rv; } nsresult nsComponentManagerImpl::PlatformFind(const nsCID &aCID, nsDll **aDll) { PR_ASSERT(mRegistry!=NULL); nsresult rv; char *cidString = aCID.ToString(); nsIRegistry::Key cidKey; rv = mRegistry->GetSubtreeRaw(mCLSIDKey, cidString, &cidKey); delete [] cidString; if (NS_FAILED(rv)) return rv; char *library = NULL; rv = mRegistry->GetString(cidKey, inprocServerValueName, &library); if (NS_FAILED(rv)) { // Registry inconsistent. No File name for CLSID. return rv; } autoStringFree delete_library(library, autoStringFree::NSPR_Delete); // Get the library name, modifiedtime and size PRUint32 lastModTime = 0; PRUint32 fileSize = 0; nsIRegistry::Key key; rv = mRegistry->GetSubtreeRaw(mXPCOMKey, library, &key); if (NS_SUCCEEDED(rv)) { PlatformGetFileInfo(key, &lastModTime, &fileSize); } nsDll *dll = CreateCachedDll(library, lastModTime, fileSize); if (dll == NULL) return NS_ERROR_OUT_OF_MEMORY; *aDll = dll; return NS_OK; } nsresult nsComponentManagerImpl::PlatformProgIDToCLSID(const char *aProgID, nsCID *aClass) { PR_ASSERT(aClass != NULL); PR_ASSERT(mRegistry); nsresult rv; nsIRegistry::Key progIDKey; rv = mRegistry->GetSubtreeRaw(mClassesKey, aProgID, &progIDKey); if (NS_FAILED(rv)) return rv; char *cidString; rv = mRegistry->GetString(progIDKey, classIDValueName, &cidString); if(NS_FAILED(rv)) return rv; if (!(aClass->Parse(cidString))) { rv = NS_ERROR_FAILURE; } PR_FREEIF(cidString); return NS_OK; } nsresult nsComponentManagerImpl::PlatformCLSIDToProgID(nsCID *aClass, char* *aClassName, char* *aProgID) { PR_ASSERT(aClass); PR_ASSERT(mRegistry); nsresult rv; char* cidStr = aClass->ToString(); nsIRegistry::Key cidKey; rv = mRegistry->GetSubtreeRaw(mCLSIDKey, cidStr, &cidKey); if(NS_FAILED(rv)) return rv; PR_FREEIF(cidStr); char* classnameString; rv = mRegistry->GetString(cidKey, classNameValueName, &classnameString); if(NS_FAILED(rv)) return rv; *aClassName = classnameString; char* progidString; rv = mRegistry->GetString(cidKey,progIDValueName,&progidString); if (NS_FAILED(rv)) return rv; *aProgID = progidString; return NS_OK; } nsresult nsComponentManagerImpl::PlatformPrePopulateRegistry() { // Read in all dll entries and populate the mDllStore nsCOMPtr dllEnum; nsresult rv = mRegistry->EnumerateSubtrees( mXPCOMKey, getter_AddRefs(dllEnum)); if (NS_FAILED(rv)) return rv; rv = dllEnum->First(); for (; NS_SUCCEEDED(rv) && !dllEnum->IsDone(); (rv = dllEnum->Next())) { nsCOMPtr base; rv = dllEnum->CurrentItem(getter_AddRefs(base)); if (NS_FAILED(rv)) continue; // Get specific interface. nsIID nodeIID = NS_IREGISTRYNODE_IID; nsCOMPtr node; rv = base->QueryInterface( nodeIID, getter_AddRefs(node) ); if (NS_FAILED(rv)) continue; // Get library name char *library = NULL; rv = node->GetName(&library); if (NS_FAILED(rv)) continue; // XXX make sure the following will work autoStringFree delete_library(library, autoStringFree::nsCRT_String_Delete); // Get key associated with library nsIRegistry::Key libKey; rv = node->GetKey(&libKey); if (NS_FAILED(rv)) continue; // Create nsDll with this name PRUint32 lastModTime = 0; PRUint32 fileSize = 0; PlatformGetFileInfo(libKey, &lastModTime, &fileSize); // printf("Populating dll: %s, %d, %d\n", library, lastModTime, fileSize); nsDll *dll = CreateCachedDll(library, lastModTime, fileSize); if (dll == NULL) { rv = NS_ERROR_OUT_OF_MEMORY; continue; } } // Then read in all CID entries and populate the mFactories nsCOMPtr cidEnum; rv = mRegistry->EnumerateSubtrees( mCLSIDKey, getter_AddRefs(cidEnum)); if (NS_FAILED(rv)) return rv; rv = cidEnum->First(); for (; NS_SUCCEEDED(rv) && !cidEnum->IsDone(); (rv = cidEnum->Next())) { nsCOMPtr base; rv = cidEnum->CurrentItem(getter_AddRefs(base)); if (NS_FAILED(rv)) continue; // Get specific interface. nsIID nodeIID = NS_IREGISTRYNODE_IID; nsCOMPtr node; rv = base->QueryInterface( nodeIID, getter_AddRefs(node) ); if (NS_FAILED(rv)) continue; // Get library name char *cidString = NULL; rv = node->GetName(&cidString); if (NS_FAILED(rv)) continue; autoStringFree delete_cidString(cidString, autoStringFree::nsCRT_String_Delete); // Get key associated with library nsIRegistry::Key cidKey; rv = node->GetKey(&cidKey); if (NS_FAILED(rv)) continue; // Create the CID entry char *library = NULL; rv = mRegistry->GetString(cidKey, inprocServerValueName, &library); if (NS_FAILED(rv)) continue; autoStringFree delete_library(library, autoStringFree::NSPR_Delete); nsCID aClass; if (!(aClass.Parse(cidString))) continue; nsDll *dll = CreateCachedDll(library, 0, 0); if (!dll) continue; nsFactoryEntry* entry = new nsFactoryEntry(aClass, dll); if (!entry) continue; nsIDKey key(aClass); mFactories->Put(&key, entry); } // Finally read in PROGID -> CID mappings nsCOMPtr progidEnum; rv = mRegistry->EnumerateSubtrees( mClassesKey, getter_AddRefs(progidEnum)); if (NS_FAILED(rv)) return rv; rv = progidEnum->First(); for (; NS_SUCCEEDED(rv) && !progidEnum->IsDone(); (rv = progidEnum->Next())) { nsCOMPtr base; rv = progidEnum->CurrentItem(getter_AddRefs(base)); if (NS_FAILED(rv)) continue; // Get specific interface. nsIID nodeIID = NS_IREGISTRYNODE_IID; nsCOMPtr node; rv = base->QueryInterface(nodeIID, getter_AddRefs(node)); if (NS_FAILED(rv)) continue; // Get the progid string char *progidString = NULL; rv = node->GetName(&progidString); if (NS_FAILED(rv)) continue; autoStringFree delete_progidString(progidString, autoStringFree::nsCRT_String_Delete); // Get cid string nsIRegistry::Key progidKey; rv = node->GetKey(&progidKey); if (NS_FAILED(rv)) continue; char *cidString = NULL; rv = mRegistry->GetString(progidKey, classIDValueName, &cidString); if (NS_FAILED(rv)) continue; autoStringFree delete_cidString(cidString, autoStringFree::NSPR_Delete); nsCID *aClass = new nsCID(); if (!aClass) continue; // Protect against out of memory. if (!(aClass->Parse(cidString))) { delete aClass; continue; } // put the {progid, Cid} mapping into our map nsStringKey key(progidString); mProgIDs->Put(&key, aClass); // printf("Populating [ %s, %s ]\n", cidString, progidString); } mPrePopulationDone = PR_TRUE; return NS_OK; } #endif /* USE_REGISTRY */ // // HashProgID // nsresult nsComponentManagerImpl::HashProgID(const char *aProgID, const nsCID &aClass) { if(!aProgID) { return NS_ERROR_NULL_POINTER; } nsStringKey key(aProgID); nsCID* cid = (nsCID*) mProgIDs->Get(&key); if (cid) { if (cid == &kNoCID) { // we don't delete this ptr as it's static (ugh) } else { delete cid; } } cid = new nsCID(aClass); if (!cid) { return NS_ERROR_OUT_OF_MEMORY; } mProgIDs->Put(&key, cid); return NS_OK; } nsDll* nsComponentManagerImpl::CreateCachedDllName(const char *dllName) { // Check our dllCollection for a dll with matching name nsStringKey key(dllName); nsDll *dll = (nsDll *) mDllStore->Get(&key); if (dll == NULL) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: New dll \"%s\".", dllName)); // Add a new Dll into the nsDllStore dll = new nsDll(dllName, 1 /* dummy */); if (dll == NULL) return NULL; if (dll->GetStatus() != DLL_OK) { // Cant create a nsDll. Backoff. PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: ERROR in creating nsDll from \"%s\".", dllName)); delete dll; dll = NULL; } else { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Adding New dll \"%s\" to mDllStore.", dllName)); mDllStore->Put(&key, (void *)dll); } } else { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Found in mDllStore \"%s\".", dllName)); } return dll; } nsDll* nsComponentManagerImpl::CreateCachedDll(const char *persistentDescriptor, PRUint32 modDate, PRUint32 fileSize) { // Check our dllCollection for a dll with matching name nsStringKey key(persistentDescriptor); nsDll *dll = (nsDll *) mDllStore->Get(&key); if (dll == NULL) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: New dll \"%s\".", persistentDescriptor)); // Add a new Dll into the nsDllStore dll = new nsDll(persistentDescriptor, modDate, fileSize); if (dll == NULL) return NULL; if (dll->GetStatus() != DLL_OK) { // Cant create a nsDll. Backoff. PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: ERROR in creating nsDll from \"%s\".", persistentDescriptor)); delete dll; dll = NULL; } else { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Adding New dll \"%s\" to mDllStore.", persistentDescriptor)); mDllStore->Put(&key, (void *)dll); } } else { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Found in mDllStore \"%s\".", persistentDescriptor)); // XXX We found the dll in the dllCollection. // XXX Consistency check: dll needs to have the same // XXX lastModTime and fileSize. If not that would mean // XXX that the dll wasn't registered properly. } return dll; } nsDll* nsComponentManagerImpl::CreateCachedDll(nsIFileSpec *dllSpec) { nsDll *dll = NULL; PRUint32 modDate; PRUint32 size; if (NS_FAILED(dllSpec->GetModDate(&modDate)) || NS_FAILED(dllSpec->GetFileSize(&size))) return NULL; char *persistentDescriptor = NULL; if (NS_FAILED(dllSpec->GetPersistentDescriptorString(&persistentDescriptor))) return NULL; dll = CreateCachedDll(persistentDescriptor, modDate, size); nsCRT::free(persistentDescriptor); return dll; } //////////////////////////////////////////////////////////////////////////////// // nsComponentManagerImpl: Public methods //////////////////////////////////////////////////////////////////////////////// /** * LoadFactory() * * Given a FactoryEntry, this loads the dll if it has to, find the NSGetFactory * symbol, calls the routine to create a new factory and returns it to the * caller. * * No attempt is made to store the factory in any form anywhere. */ nsresult nsComponentManagerImpl::LoadFactory(nsFactoryEntry *aEntry, nsIFactory **aFactory) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: LoadFactory() \"%s\".", aEntry->dll->GetNativePath())); if (aFactory == NULL) { return NS_ERROR_NULL_POINTER; } *aFactory = NULL; // LoadFactory() cannot be called for entries that are CID<->factory // mapping entries for the session. PR_ASSERT(aEntry->dll != NULL); if (aEntry->dll->IsLoaded() == PR_FALSE) { // Load the dll PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: + Loading \"%s\".", aEntry->dll->GetNativePath())); if (aEntry->dll->Load() == PR_FALSE) { PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: Library load unsuccessful.")); char errorMsg[1024] = "Cannot get error from nspr. Not enough memory."; if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) PR_GetErrorText(errorMsg); PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Load(%s) FAILED with error:%s", aEntry->dll->GetNativePath(), errorMsg)); #ifdef PRINT_CRITICAL_ERROR_TO_SCREEN // Put the error message on the screen. printf("**************************************************\n" "nsComponentManager: Load(%s) FAILED with error: %s\n" "**************************************************\n", aEntry->dll->GetNativePath(), errorMsg); #endif return NS_ERROR_FAILURE; } } #ifdef MOZ_TRACE_XPCOM_REFCNT // Inform refcnt tracer of new library so that calls through the // new library can be traced. nsTraceRefcnt::LoadLibrarySymbols(aEntry->dll->GetNativePath(), aEntry->dll->GetInstance()); #endif // Create the module object and get the factory nsCOMPtr mobj; nsresult rv = aEntry->dll->GetModule(gComponentManager, getter_AddRefs(mobj)); if (NS_SUCCEEDED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: %s using nsIModule to get factory.", aEntry->dll->GetNativePath())); rv = mobj->GetClassObject(gComponentManager, aEntry->cid, NS_GET_IID(nsIFactory), (void **)aFactory); return rv; } #ifndef OBSOLETE_MODULE_LOADING // Try the older OBSOLETE method nsIServiceManager* serviceMgr = NULL; rv = nsServiceManager::GetGlobalServiceManager(&serviceMgr); if (NS_FAILED(rv)) return rv; nsFactoryProc proc = (nsFactoryProc) aEntry->dll->FindSymbol("NSGetFactory"); if (proc != NULL) { char* className = NULL; char* progID = NULL; PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: %s using OBSOLETE method NSGetFactory().", aEntry->dll->GetNativePath())); // XXX dp, warren: deal with this! #if 0 rv = CLSIDToProgID(&aEntry->cid, &className, &progID); // if CLSIDToProgID fails, just pass null to NSGetFactory #endif rv = proc(serviceMgr, aEntry->cid, className, progID, aFactory); if (NS_FAILED(rv)) return rv; if (className) delete[] className; if (progID) delete[] progID; return rv; } #endif /* OBSOLETE_MODULE_LOADING */ PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: Module entrypoint not found.")); return NS_ERROR_FACTORY_NOT_LOADED; } nsFactoryEntry * nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass, PRBool checkRegistry) { nsIDKey key(aClass); nsFactoryEntry *entry = (nsFactoryEntry*) mFactories->Get(&key); if (entry) PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("\t\tfound in factory cache.")); else #ifdef USE_REGISTRY if (checkRegistry) { nsDll *dll = NULL; PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("\t\tnot found in factory cache. Looking in registry")); nsresult rv = PlatformFind(aClass, &dll); if (NS_FAILED(rv)) return NULL; entry = new nsFactoryEntry(aClass, dll); if (entry != NULL) { // If we got one, cache it in our hashtable PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("\t\tfound in registry.")); mFactories->Put(&key, entry); } } #endif /* USE_REGISTRY */ return (entry); } /** * FindFactory() * * Given a classID, this finds the factory for this CID by first searching the * local CID<->factory mapping. Next it searches for a Dll that implements * this classID and calls LoadFactory() to create the factory. * * Again, no attempt is made at storing the factory. */ nsresult nsComponentManagerImpl::FindFactory(const nsCID &aClass, nsIFactory **aFactory) { if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsComponentManager: FindFactory(%s)", buf); delete [] buf; } PR_ASSERT(aFactory != NULL); nsFactoryEntry *entry = GetFactoryEntry(aClass, PR_TRUE); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; if (entry) { if (entry->factory == NULL) { res = LoadFactory(entry, aFactory); // XXX Cache factory that we created for performance. // XXX Need a way to release this factory else dlls will never // XXX get unloaded // XXX // XXX With the new module notion, we dont need to cache the // XXX factory anylonger. The module would do that and manage // XXX it. This is simpler for making decisions of unloading. // XXX // XXX The other option we got is to make UnloadLibraries() // XXX release any cached factory before asking if a dll can // XXX be unloaded. This we can do to improve performance. if (NS_SUCCEEDED(res)) { entry->factory = *aFactory; NS_ADDREF(entry->factory); } } else { *aFactory = entry->factory; NS_ADDREF(*aFactory); res = NS_OK; } } PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tFindFactory() %s", NS_SUCCEEDED(res) ? "succeeded" : "FAILED")); return res; } /** * GetClassObject() * * Given a classID, this finds the singleton ClassObject that implements the CID. * Returns an interface of type aIID off the singleton classobject. */ nsresult nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID, void **aResult) { nsresult rv; nsCOMPtr factory; if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf); delete [] buf; } PR_ASSERT(aResult != NULL); rv = FindFactory(aClass, getter_AddRefs(factory)); if (NS_FAILED(rv)) return rv; rv = factory->QueryInterface(aIID, aResult); PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); return rv; } /** * ProgIDToCLSID() * * Mapping function from a ProgID to a classID. Directly talks to the registry. * */ nsresult nsComponentManagerImpl::ProgIDToCLSID(const char *aProgID, nsCID *aClass) { NS_PRECONDITION(aProgID != NULL, "null ptr"); if (! aProgID) return NS_ERROR_NULL_POINTER; NS_PRECONDITION(aClass != NULL, "null ptr"); if (! aClass) return NS_ERROR_NULL_POINTER; nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; #ifdef USE_REGISTRY // XXX This isn't quite the best way to do this: we should // probably move an nsArray into the FactoryEntry class, // and then have the construct/destructor of the factory entry // keep the ProgID to CID cache up-to-date. However, doing this // significantly improves performance, so it'll do for now. nsStringKey key(aProgID); nsCID* cid = (nsCID*) mProgIDs->Get(&key); if (cid) { if (cid == &kNoCID) { // we've already tried to map this ProgID to a CLSID, and found // that there _was_ no such mapping in the registry. } else { *aClass = *cid; res = NS_OK; } } else { // This is the first time someone has asked for this // ProgID. Go to the registry to find the CID. res = PlatformProgIDToCLSID(aProgID, aClass); if (NS_SUCCEEDED(res)) { // Found it. So put it into the cache. cid = new nsCID(*aClass); if (!cid) return NS_ERROR_OUT_OF_MEMORY; mProgIDs->Put(&key, cid); } else { // Didn't find it. Put a special CID in the cache so we // don't need to hit the registry on subsequent requests // for the same ProgID. mProgIDs->Put(&key, (void *)&kNoCID); } } #endif /* USE_REGISTRY */ if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf; if (NS_SUCCEEDED(res)) buf = aClass->ToString(); PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: ProgIDToCLSID(%s)->%s", aProgID, NS_SUCCEEDED(res) ? buf : "[FAILED]")); if (NS_SUCCEEDED(res)) delete [] buf; } return res; } /** * CLSIDToProgID() * * Translates a classID to a {ProgID, Class Name}. Does direct registry * access to do the translation. * * XXX Would be nice to hook in a cache here too. */ nsresult nsComponentManagerImpl::CLSIDToProgID(nsCID *aClass, char* *aClassName, char* *aProgID) { nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; #ifdef USE_REGISTRY res = PlatformCLSIDToProgID(aClass, aClassName, aProgID); #endif /* USE_REGISTRY */ if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf = aClass->ToString(); PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("nsComponentManager: CLSIDToProgID(%s)->%s", buf, NS_SUCCEEDED(res) ? *aProgID : "[FAILED]")); delete [] buf; } return res; } /** * CreateInstance() * * Create an instance of an object that implements an interface and belongs * to the implementation aClass using the factory. The factory is immediately * released and not held onto for any longer. */ nsresult nsComponentManagerImpl::CreateInstance(const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID, void **aResult) { if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsComponentManager: CreateInstance(%s)", buf); delete [] buf; } if (aResult == NULL) { return NS_ERROR_NULL_POINTER; } *aResult = NULL; nsIFactory *factory = NULL; nsresult res = FindFactory(aClass, &factory); if (NS_SUCCEEDED(res)) { res = factory->CreateInstance(aDelegate, aIID, aResult); NS_RELEASE(factory); PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("\t\tFactory CreateInstance() %s.", NS_SUCCEEDED(res) ? "succeeded" : "FAILED")); return res; } PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("\t\tCreateInstance() FAILED.")); return NS_ERROR_FACTORY_NOT_REGISTERED; } /** * CreateInstance() * * An overload of CreateInstance() that creates an instance of the object that * implements the interface aIID and whose implementation has a progID aProgID. * * This is only a convenience routine that turns around can calls the * CreateInstance() with classid and iid. * * XXX This is a function overload. We need to remove it. */ nsresult nsComponentManagerImpl::CreateInstance(const char *aProgID, nsISupports *aDelegate, const nsIID &aIID, void **aResult) { nsCID clsid; nsresult rv = ProgIDToCLSID(aProgID, &clsid); if (NS_FAILED(rv)) return rv; return CreateInstance(clsid, aDelegate, aIID, aResult); } /** * RegisterFactory() * * Register a factory to be responsible for creation of implementation of * classID aClass. Plus creates as association of aClassName and aProgID * to the classID. If replace is PR_TRUE, we replace any existing registrations * with this one. * * Once registration is complete, we add the class to the factories cache * that we maintain. The factories cache is the ONLY place where these * registrations are ever kept. */ nsresult nsComponentManagerImpl::RegisterFactory(const nsCID &aClass, const char *aClassName, const char *aProgID, nsIFactory *aFactory, PRBool aReplace) { if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsComponentManager: RegisterFactory(%s, %s, %s), replace = %d.", buf, aClassName, aProgID, (int)aReplace); delete [] buf; } nsFactoryEntry *entry = NULL; nsIDKey key(aClass); entry = GetFactoryEntry(aClass, PR_TRUE); if (entry && !aReplace) { // Already registered PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tFactory already registered.")); return NS_ERROR_FACTORY_EXISTS; } nsFactoryEntry *newEntry = new nsFactoryEntry(aClass, aFactory); if (newEntry == NULL) return NS_ERROR_OUT_OF_MEMORY; if (entry) { PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tdeleting old Factory Entry.")); mFactories->RemoveAndDelete(&key); entry = NULL; } mFactories->Put(&key, newEntry); // Update the ProgID->CLSID Map if (aProgID) { nsresult rv = HashProgID(aProgID, aClass); if(NS_FAILED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tFactory register succeeded. PROGID->CLSID mapping failed.")); return (rv); } } PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tFactory register succeeded.")); return NS_OK; } nsresult nsComponentManagerImpl::RegisterComponent(const nsCID &aClass, const char *aClassName, const char *aProgID, const char *aLibraryPersistentDescriptor, PRBool aReplace, PRBool aPersist) { nsresult rv = NS_OK; if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsComponentManager: RegisterComponent(%s, %s, %s, %s), replace = %d, persist = %d.", buf, aClassName, aProgID, aLibraryPersistentDescriptor, (int)aReplace, (int)aPersist); delete [] buf; } // Convert the persistent descriptor into a nsIFileSpec nsCOMPtrlibSpec; rv = CreateInstance(NS_FILESPEC_PROGID, NULL, NS_GET_IID(nsIFileSpec), getter_AddRefs(libSpec)); if (NS_FAILED(rv)) return rv; rv = libSpec->SetPersistentDescriptorString((char *)aLibraryPersistentDescriptor); if (NS_FAILED(rv)) return rv; // Call the register component with FileSpec routine rv = RegisterComponentSpec(aClass, aClassName, aProgID, libSpec, aReplace, aPersist); return rv; } nsresult nsComponentManagerImpl::RegisterComponentSpec(const nsCID &aClass, const char *aClassName, const char *aProgID, nsIFileSpec *aLibrarySpec, PRBool aReplace, PRBool aPersist) { nsresult rv = NS_OK; if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *fullName = NULL; aLibrarySpec->GetNativePath(&fullName); char *buf = aClass.ToString(); PR_LogPrint("nsComponentManager: RegisterComponentSpec(%s, %s, %s, %s), replace = %d, persist = %d.", buf, aClassName, aProgID, fullName, (int)aReplace, (int)aPersist); delete [] buf; if (fullName) delete [] fullName; } nsIDKey key(aClass); nsFactoryEntry *entry = GetFactoryEntry(aClass, PR_TRUE); if (entry && !aReplace) { PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tFactory already registered.")); return NS_ERROR_FACTORY_EXISTS; } #ifdef USE_REGISTRY if (aPersist) { // Add it to the registry nsDll *dll = new nsDll(aLibrarySpec); if (dll == NULL) return NS_ERROR_OUT_OF_MEMORY; char *cidString = aClass.ToString(); if (cidString == NULL) { delete dll; return NS_ERROR_OUT_OF_MEMORY; } PlatformRegister(cidString, aClassName, aProgID, dll); delete [] cidString; delete dll; } else #endif { // Create a dll from the librarySpec nsDll *dll = CreateCachedDll(aLibrarySpec); if (dll == NULL) return NS_ERROR_OUT_OF_MEMORY; // Use the dll to create a factoryEntry nsFactoryEntry *newEntry = new nsFactoryEntry(aClass, dll); if (newEntry == NULL) { delete dll; return NS_ERROR_OUT_OF_MEMORY; } if (entry) { mFactories->RemoveAndDelete(&key); entry = NULL; PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tdeleting registered Factory.")); } mFactories->Put(&key, newEntry); } // Update the ProgID->CLSID Map if this isnt stored in registry #ifdef USE_REGISTRY if (aProgID && aPersist != PR_TRUE) rv = HashProgID(aProgID, aClass); #else /* USE_REGISTRY */ if (aProgID) rv = HashProgID(aProgID, aClass); #endif /* USE_REGISTRY */ PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tFactory register %s.", NS_SUCCEEDED(rv) ? "succeeded" : "failed")); return rv; } nsresult nsComponentManagerImpl::RegisterComponentLib(const nsCID &aClass, const char *aClassName, const char *aProgID, const char *aDllName, PRBool aReplace, PRBool aPersist /* has to be PR_FALSE */) { nsresult rv = NS_OK; // XXX We cant store dllName registrations in the registry yet. PR_ASSERT(aPersist == PR_FALSE); if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsComponentManager: RegisterComponentLib(%s, %s, %s, %s), replace = %d, persist = %d.", buf, aClassName, aProgID, aDllName, (int)aReplace, (int)aPersist); delete [] buf; } nsIDKey key(aClass); nsFactoryEntry *entry = GetFactoryEntry(aClass, PR_TRUE); if (entry && !aReplace) { PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tFactory already registered.")); return NS_ERROR_FACTORY_EXISTS; } #ifdef USE_REGISTRY if (aPersist) { // Add it to the registry nsDll *dll = new nsDll(aDllName, 1/* dummy */); if (dll == NULL) rv = NS_ERROR_OUT_OF_MEMORY; char *cidString = aClass.ToString(); if (cidString == NULL) { delete dll; rv = NS_ERROR_OUT_OF_MEMORY; } PlatformRegister(cidString, aClassName, aProgID, dll); delete [] cidString; delete dll; } else #endif { // Create a dll from the DllName nsDll *dll = CreateCachedDllName(aDllName); if (dll == NULL) return NS_ERROR_OUT_OF_MEMORY; // Use the dll to create a factoryEntry nsFactoryEntry* newEntry = new nsFactoryEntry(aClass, dll); if (newEntry == NULL) { delete dll; return NS_ERROR_OUT_OF_MEMORY; } if (entry) { mFactories->RemoveAndDelete(&key); entry = NULL; PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tdeleting registered Factory.")); } mFactories->Put(&key, newEntry); } // Update the ProgID->CLSID Map if this isn't stored in registry #ifdef USE_REGISTRY if (aProgID && aPersist != PR_TRUE) rv = HashProgID(aProgID, aClass); #else /* USE_REGISTRY */ if (aProgID) rv = HashProgID(aProgID, aClass); #endif /* USE_REGISTRY */ PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("\t\tFactory register %s.", rv == NS_OK ? "succeeded" : "failed")); return rv; } nsresult nsComponentManagerImpl::UnregisterFactory(const nsCID &aClass, nsIFactory *aFactory) { if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsComponentManager: Unregistering Factory."); PR_LogPrint("nsComponentManager: + %s.", buf); delete [] buf; } nsIDKey key(aClass); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; nsFactoryEntry *old = (nsFactoryEntry *) mFactories->Get(&key); if (old != NULL) { if (old->factory == aFactory) { PR_EnterMonitor(mMon); old = (nsFactoryEntry *) mFactories->RemoveAndDelete(&key); old = NULL; PR_ExitMonitor(mMon); res = NS_OK; } } PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("nsComponentManager: ! Factory unregister %s.", NS_SUCCEEDED(res) ? "succeeded" : "failed")); return res; } nsresult nsComponentManagerImpl::UnregisterComponent(const nsCID &aClass, const char *aLibrary) { nsresult rv; if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsComponentManager: UnregisterComponentSpec(%s, %s)", buf, aLibrary); delete [] buf; } // Convert the persistent descriptor into a nsIFileSpec nsCOMPtrlibSpec; rv = CreateInstance(NS_FILESPEC_PROGID, NULL, NS_GET_IID(nsIFileSpec), getter_AddRefs(libSpec)); if (NS_FAILED(rv)) return rv; rv = libSpec->SetPersistentDescriptorString((char *)aLibrary); if (NS_FAILED(rv)) return rv; return UnregisterComponentSpec(aClass, libSpec); } nsresult nsComponentManagerImpl::UnregisterComponentSpec(const nsCID &aClass, nsIFileSpec *aLibrarySpec) { char *aLibrary; nsresult rv = aLibrarySpec->GetPersistentDescriptorString(&aLibrary); if (NS_FAILED(rv)) return NS_ERROR_INVALID_ARG; if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsComponentManager: UnregisterComponentSpec(%s, %s)", buf, aLibrary); delete [] buf; } nsIDKey key(aClass); nsFactoryEntry *old = (nsFactoryEntry *) mFactories->Get(&key); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; PR_EnterMonitor(mMon); if (old != NULL && old->dll != NULL) { if (old->dll->GetPersistentDescriptorString() != NULL && #if defined(XP_UNIX) || defined(XP_BEOS) PL_strcasecmp(old->dll->GetPersistentDescriptorString(), aLibrary) #else PL_strcmp(old->dll->GetPersistentDescriptorString(), aLibrary) #endif ) { mFactories->RemoveAndDelete(&key); old = NULL; res = NS_OK; } #ifdef USE_REGISTRY char *cidString = aClass.ToString(); res = PlatformUnregister(cidString, aLibrary); delete [] cidString; #endif } PR_ExitMonitor(mMon); PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, ("nsComponentManager: ! Factory unregister %s.", NS_SUCCEEDED(res) ? "succeeded" : "failed")); return res; } static nsresult nsFreeLibrary(nsDll *dll, nsIServiceManager *serviceMgr) { nsresult rv = NS_ERROR_FAILURE; if (!dll || dll->IsLoaded() == PR_FALSE) { return NS_ERROR_INVALID_ARG; } // Get if the dll was marked for unload in an earlier round PRBool dllMarkedForUnload = dll->IsMarkedForUnload(); // Reset dll marking for unload just in case we return with // an error. dll->MarkForUnload(PR_FALSE); // Get the module object nsCOMPtr mobj; rv = dll->GetModule(nsComponentManagerImpl::gComponentManager, getter_AddRefs(mobj)); if (NS_FAILED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Cannot get module object for %s", dll->GetNativePath())); return rv; } PRBool canUnload; rv = mobj->CanUnload(nsComponentManagerImpl::gComponentManager, &canUnload); if (NS_FAILED(rv)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: nsIModule::CanUnload() returned error for %s.", dll->GetNativePath())); return rv; } if (canUnload) { if (dllMarkedForUnload) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: + Unloading \"%s\".", dll->GetNativePath())); #if 0 // XXX dlls aren't counting their outstanding instances correctly // XXX hence, dont unload until this gets enforced. rv = dll->Unload(); #endif /* 0 */ } else { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Ready for unload \"%s\".", dll->GetNativePath())); } } else { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: + NOT Unloading %s", dll->GetNativePath())); rv = NS_ERROR_FAILURE; } return rv; } static PRBool nsFreeLibraryEnum(nsHashKey *aKey, void *aData, void* closure) { nsDll *dll = (nsDll *) aData; nsIServiceManager* serviceMgr = (nsIServiceManager*)closure; nsFreeLibrary(dll, serviceMgr); return PR_TRUE; } nsresult nsComponentManagerImpl::FreeLibraries(void) { nsIServiceManager* serviceMgr = NULL; nsresult rv = nsServiceManager::GetGlobalServiceManager(&serviceMgr); if (NS_FAILED(rv)) return rv; rv = UnloadLibraries(serviceMgr); return rv; } // Private implementation of unloading libraries nsresult nsComponentManagerImpl::UnloadLibraries(nsIServiceManager *serviceMgr) { PR_EnterMonitor(mMon); PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Unloading Libraries.")); mDllStore->Enumerate(nsFreeLibraryEnum, serviceMgr); PR_ExitMonitor(mMon); return NS_OK; } //////////////////////////////////////////////////////////////////////////////// /** * AutoRegister(RegistrationInstant, const char *directory) * * Given a directory in the following format, this will ensure proper registration * of all components. No default director is looked at. * * Directory and fullname are what NSPR will accept. For eg. * WIN y:/home/dp/mozilla/dist/bin * UNIX /home/dp/mozilla/dist/bin * MAC /Hard drive/mozilla/dist/apprunner * * This will take care not loading already registered dlls, finding and * registering new dlls, re-registration of modified dlls * */ nsresult nsComponentManagerImpl::AutoRegister(RegistrationTime when, nsIFileSpec *inDirSpec) { nsCOMPtr dirSpec; if (inDirSpec == NULL) { // Do default components directory nsSpecialSystemDirectory sysdir(nsSpecialSystemDirectory::XPCOM_CurrentProcessComponentDirectory); nsresult rv = NS_NewFileSpecWithSpec(sysdir, getter_AddRefs(dirSpec)); if (NS_FAILED(rv)) return rv; } else dirSpec = inDirSpec; char *nativePath = NULL; nsresult rv = dirSpec->GetNativePath(&nativePath); if (NS_FAILED(rv)) return rv; if (nativePath == NULL) { return NS_ERROR_INVALID_POINTER; } PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Autoregistration begins. dir = %s", nativePath)); #ifdef DEBUG printf("nsComponentManager: Autoregistration begins. dir = %s\n", nativePath); #endif /* DEBUG */ rv = SyncComponentsInDir(when, dirSpec); PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Autoregistration ends. dir = %s", nativePath)); #ifdef DEBUG printf("nsComponentManager: Autoregistration ends. dir = %s\n", nativePath); #endif /* DEBUG */ nsCRT::free(nativePath); return rv; } nsresult nsComponentManagerImpl::SyncComponentsInDir(RegistrationTime when, nsIFileSpec *dirSpec) { nsresult rv = NS_ERROR_FAILURE; PRBool isDir = PR_FALSE; // Maker sure we are dealing with a directory rv = dirSpec->IsDirectory(&isDir); if (NS_FAILED(rv)) return rv; if (isDir == PR_FALSE) { return NS_ERROR_INVALID_POINTER; } // Create a directory iterator nsCOMPtrdirIterator; rv = CreateInstance(NS_DIRECTORYITERATOR_PROGID, NULL, NS_GET_IID(nsIDirectoryIterator), getter_AddRefs(dirIterator)); if (NS_FAILED(rv)) return rv; rv = dirIterator->Init(dirSpec, PR_FALSE); if (NS_FAILED(rv)) return rv; // whip through the directory to register every file nsIFileSpec *dirEntry = NULL; PRBool more = PR_FALSE; rv = dirIterator->Exists(&more); if (NS_FAILED(rv)) return rv; while (more == PR_TRUE) { rv = dirIterator->GetCurrentSpec(&dirEntry); if (NS_FAILED(rv)) return rv; rv = dirEntry->IsDirectory(&isDir); if (NS_FAILED(rv)) return rv; if (isDir == PR_TRUE) { // This is a directory. Grovel for components into the directory. rv = SyncComponentsInDir(when, dirEntry); } else { // This is a file. Try to register it. rv = AutoRegisterComponent(when, dirEntry); } if (NS_FAILED(rv)) { // This means either of AutoRegisterComponent or // SyncComponentsInDir failed. It could be because // the file isn't a component like initpref.js // So dont break on these errors. } NS_RELEASE(dirEntry); rv = dirIterator->Next(); if (NS_FAILED(rv)) return rv; rv = dirIterator->Exists(&more); if (NS_FAILED(rv)) return rv; } return rv; } nsresult nsComponentManagerImpl::AutoRegisterComponent(RegistrationTime when, nsIFileSpec *component) { const char *ValidDllExtensions[] = { ".dll", /* Windows */ ".dso", /* Unix ? */ ".dylib", /* Unix: Rhapsody */ ".so", /* Unix */ ".so.1.0", /* Unix: BSD */ ".sl", /* Unix: HP-UX */ ".shlb", /* Mac ? */ #if defined(VMS) ".exe", /* Open VMS */ #endif ".dlm", /* new for all platforms */ NULL }; nsresult rv; // Ensure we are dealing with a file as opposed to a dir PRBool b = PR_FALSE; rv = component->IsFile(&b); if (NS_FAILED(rv)) return rv; if (b == PR_FALSE) return NS_ERROR_FAILURE; // deal only with files that have a valid extension PRBool validExtension = PR_FALSE; #ifdef XP_MAC // rjc - on Mac, check the file's type code (skip checking the creator code) nsFileSpec fs; if (NS_FAILED(rv = component->GetFileSpec(&fs))) return(rv); CInfoPBRec catInfo; OSErr err = fs.GetCatInfo(catInfo); if (!err) { // on Mac, Mozilla shared libraries are of type 'shlb' // Note: we don't check the creator (which for Mozilla is 'MOZZ') // so that 3rd party shared libraries will be noticed! if ((catInfo.hFileInfo.ioFlFndrInfo.fdType == 'shlb') /* && (catInfo.hFileInfo.ioFlFndrInfo.fdCreator == 'MOZZ') */ ) { validExtension = PR_TRUE; } } #else char *leafName = NULL; rv = component->GetLeafName(&leafName); if (NS_FAILED(rv)) return rv; int flen = PL_strlen(leafName); for (int i=0; ValidDllExtensions[i] != NULL; i++) { int extlen = PL_strlen(ValidDllExtensions[i]); // Does fullname end with this extension if (flen >= extlen && !PL_strcasecmp(&(leafName[flen - extlen]), ValidDllExtensions[i]) ) { validExtension = PR_TRUE; break; } } if (leafName) nsCRT::free(leafName); #endif if (validExtension == PR_FALSE) { // Skip invalid extensions return NS_ERROR_FAILURE; } // Get the name of the dll char *persistentDescriptor = NULL; rv = component->GetPersistentDescriptorString(&persistentDescriptor); if (NS_FAILED(rv)) return rv; autoStringFree delete_persistentDescriptor(persistentDescriptor, autoStringFree::nsCRT_String_Delete); nsStringKey key(persistentDescriptor); // Check if dll is one that we have already seen nsDll *dll = (nsDll *) mDllStore->Get(&key); rv = NS_OK; if (dll == NULL) { // Create nsDll for this from registry and // add it to our dll cache mDllStore. #ifdef USE_REGISTRY rv = PlatformCreateDll(persistentDescriptor, &dll); if (NS_SUCCEEDED(rv)) { mDllStore->Put(&key, (void *) dll); } #endif /* USE_REGISTRY */ } if (dll != NULL) { // Make sure the dll is OK if (dll->GetStatus() != NS_OK) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: + nsDll not NS_OK \"%s\". Skipping...", dll->GetNativePath())); return NS_ERROR_FAILURE; } // We already have seen this dll. Check if this dll changed if (!dll->HasChanged()) { // Dll hasn't changed. Skip. PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: + nsDll not changed \"%s\". Skipping...", dll->GetNativePath())); return NS_OK; } // Aagh! the dll has changed since the last time we saw it. // re-register dll if (dll->IsLoaded()) { // We loaded the old version of the dll and now we find that the // on-disk copy if newer. Try to unload the dll. nsIServiceManager* serviceMgr = NULL; nsServiceManager::GetGlobalServiceManager(&serviceMgr); // if getting the serviceMgr failed, we can still pass NULL to FreeLibraries rv = nsFreeLibrary(dll, serviceMgr); if (NS_FAILED(rv)) { // THIS IS THE WORST SITUATION TO BE IN. // Dll doesn't want to be unloaded. Cannot re-register // this dll. PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: *** Dll already loaded. " "Cannot unload either. Hence cannot re-register " "\"%s\". Skipping...", dll->GetNativePath())); return rv; } else { // dll doesn't have a CanUnload proc. Guess it is // ok to unload it. dll->Unload(); PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: + Unloading \"%s\". (no CanUnloadProc).", dll->GetNativePath())); } } // dll isloaded // Sanity. if (dll->IsLoaded()) { // We went through all the above to make sure the dll // is unloaded. And here we are with the dll still // loaded. Whoever taught dp programming... PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Dll still loaded. Cannot re-register " "\"%s\". Skipping...", dll->GetNativePath())); return NS_ERROR_FAILURE; } } // dll != NULL else { // Create and add the dll to the mDllStore // It is ok to do this even if the creation of nsDll // didnt succeed. That way we wont do this again // when we encounter the same dll. dll = new nsDll(persistentDescriptor); if (dll == NULL) return NS_ERROR_OUT_OF_MEMORY; mDllStore->Put(&key, (void *) dll); } // dll == NULL // Either we are seeing the dll for the first time or the dll has // changed since we last saw it and it is unloaded successfully. // // Now we can try register the dll for sure. nsresult res = SelfRegisterDll(dll); nsresult ret = NS_OK; if (NS_FAILED(res)) { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Autoregistration FAILED for " "\"%s\". Skipping...", dll->GetNativePath())); // Mark dll as not xpcom dll along with modified time and size in // the registry so that we wont need to load the dll again every // session until the dll changes. #ifdef USE_REGISTRY PlatformMarkNoComponents(dll); #endif /* USE_REGISTRY */ ret = NS_ERROR_FAILURE; } else { PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Autoregistration Passed for " "\"%s\".", dll->GetNativePath())); // Marking dll along with modified time and size in the // registry happens at PlatformRegister(). No need to do it // here again. } return ret; } /* * SelfRegisterDll * * Given a dll abstraction, this will load, selfregister the dll and * unload the dll. * */ nsresult nsComponentManagerImpl::SelfRegisterDll(nsDll *dll) { // Precondition: dll is not loaded already PR_ASSERT(dll->IsLoaded() == PR_FALSE); nsIServiceManager* serviceMgr = NULL; nsresult res = nsServiceManager::GetGlobalServiceManager(&serviceMgr); if (NS_FAILED(res)) return res; if (dll->Load() == PR_FALSE) { // Cannot load. Probably not a dll. char errorMsg[1024] = "Cannot get error from nspr. Not enough memory."; if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) PR_GetErrorText(errorMsg); PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: SelfRegisterDll(%s) Load FAILED with error:%s", dll->GetNativePath(), errorMsg)); #ifdef PRINT_CRITICAL_ERROR_TO_SCREEN printf("**************************************************\n" "nsComponentManager: Load(%s) FAILED with error: %s\n" "**************************************************\n", dll->GetNativePath(), errorMsg); #endif return NS_ERROR_FAILURE; } PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: + Loaded \"%s\".", dll->GetNativePath())); // Tell the module to self register nsCOMPtr mobj; res = dll->GetModule(gComponentManager, getter_AddRefs(mobj)); if (NS_SUCCEEDED(res)) { PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: %s using nsIModule to register self.", dll->GetNativePath())); nsCOMPtr fs; res = dll->GetDllSpec(getter_AddRefs(fs)); if (NS_SUCCEEDED(res)) res = mobj->RegisterSelf(gComponentManager, fs); else { PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: dll->GetDllSpec() on %s FAILED.", dll->GetNativePath())); } mobj = NULL; // Force a release of the Module object before unload() } #ifndef OBSOLETE_MODULE_LOADING else { res = NS_ERROR_NO_INTERFACE; nsRegisterProc regproc = (nsRegisterProc)dll->FindSymbol("NSRegisterSelf"); if (regproc) { // Call the NSRegisterSelfProc to enable dll registration res = regproc(serviceMgr, dll->GetPersistentDescriptorString()); } } #endif /* OBSOLETE_MODULE_LOADING */ dll->Unload(); return res; } nsresult nsComponentManagerImpl::SelfUnregisterDll(nsDll *dll) { // Precondition: dll is not loaded PR_ASSERT(dll->IsLoaded() == PR_FALSE); nsIServiceManager* serviceMgr = NULL; nsresult res = nsServiceManager::GetGlobalServiceManager(&serviceMgr); if (NS_FAILED(res)) return res; if (dll->Load() == PR_FALSE) { // Cannot load. Probably not a dll. return(NS_ERROR_FAILURE); } // Tell the module to self register nsCOMPtr mobj; res = dll->GetModule(gComponentManager, getter_AddRefs(mobj)); if (NS_SUCCEEDED(res)) { PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: %s using nsIModule to unregister self.", dll->GetNativePath())); nsCOMPtr fs; res = dll->GetDllSpec(getter_AddRefs(fs)); if (NS_SUCCEEDED(res)) res = mobj->UnregisterSelf(gComponentManager, fs); else { PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: dll->GetDllSpec() on %s FAILED.", dll->GetNativePath())); } mobj = NULL; // Force a release of the Module object before unload() } #ifndef OBSOLETE_MODULE_LOADING else { res = NS_ERROR_NO_INTERFACE; nsUnregisterProc unregproc = (nsUnregisterProc) dll->FindSymbol("NSUnregisterSelf"); if (unregproc) { // Call the NSUnregisterSelfProc to enable dll de-registration res = unregproc(serviceMgr, dll->GetPersistentDescriptorString()); } } #endif /* OBSOLETE_MODULE_LOADING */ dll->Unload(); return res; } nsresult nsComponentManagerImpl::IsRegistered(const nsCID &aClass, PRBool *aRegistered) { if(!aRegistered) { NS_ASSERTION(0, "null ptr"); return NS_ERROR_NULL_POINTER; } *aRegistered = (nsnull != GetFactoryEntry(aClass, PR_TRUE)); return NS_OK; } static NS_IMETHODIMP ConvertFactoryEntryToCID(nsHashKey *key, void *data, void *convert_data, nsISupports **retval) { nsComponentManagerImpl *compMgr = (nsComponentManagerImpl*) convert_data; nsresult rv; nsISupportsID* cidHolder; if(NS_SUCCEEDED(rv = compMgr->CreateInstance(NS_SUPPORTS_ID_PROGID, nsnull, NS_GET_IID(nsISupportsID), (void **)&cidHolder))) { nsFactoryEntry *fe = (nsFactoryEntry *) data; cidHolder->SetData(&fe->cid); *retval = cidHolder; } else *retval = nsnull; return rv; } static NS_IMETHODIMP ConvertProgIDKeyToString(nsHashKey *key, void *data, void *convert_data, nsISupports **retval) { nsComponentManagerImpl *compMgr = (nsComponentManagerImpl*) convert_data; nsresult rv; nsISupportsString* strHolder; if(NS_SUCCEEDED(rv = compMgr->CreateInstance(NS_SUPPORTS_STRING_PROGID, nsnull, NS_GET_IID(nsISupportsString), (void **)&strHolder))) { nsStringKey *strKey = (nsStringKey *) key; const nsString& str = strKey->GetString(); char* yetAnotherCopyOfTheString = str.ToNewCString(); if(yetAnotherCopyOfTheString) { strHolder->SetData(yetAnotherCopyOfTheString); delete [] yetAnotherCopyOfTheString; } *retval = strHolder; } else *retval = nsnull; return rv; } nsresult nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator** aEmumerator) { if(!aEmumerator) { NS_ASSERTION(0, "null ptr"); return NS_ERROR_NULL_POINTER; } *aEmumerator = nsnull; nsresult rv; if(!mPrePopulationDone) { rv = PlatformPrePopulateRegistry(); if(NS_FAILED(rv)) return rv; } return NS_NewHashtableEnumerator(mFactories, ConvertFactoryEntryToCID, this, aEmumerator); } nsresult nsComponentManagerImpl::EnumerateProgIDs(nsIEnumerator** aEmumerator) { if(!aEmumerator) { NS_ASSERTION(0, "null ptr"); return NS_ERROR_NULL_POINTER; } *aEmumerator = nsnull; nsresult rv; if(!mPrePopulationDone) { rv = PlatformPrePopulateRegistry(); if(NS_FAILED(rv)) return rv; } return NS_NewHashtableEnumerator(mProgIDs, ConvertProgIDKeyToString, this, aEmumerator); } //////////////////////////////////////////////////////////////////////////////// NS_COM nsresult NS_GetGlobalComponentManager(nsIComponentManager* *result) { nsresult rv = NS_OK; if (nsComponentManagerImpl::gComponentManager == NULL) { // XPCOM needs initialization. rv = NS_InitXPCOM(NULL); } if (NS_SUCCEEDED(rv)) { // NO ADDREF since this is never intended to be released. *result = nsComponentManagerImpl::gComponentManager; } return rv; } ////////////////////////////////////////////////////////////////////////////////