/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * 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 #ifndef XP_MAC // including this on mac causes odd link errors in static initialization // stuff that we (pinkerton & scc) don't yet understand. If you want to // turn this on for mac, talk to one of us. #include #endif #include "plstr.h" #include "prlink.h" #include "prsystem.h" #include "nsRepository.h" #ifdef USE_NSREG #define XP_BEGIN_PROTOS extern "C" { #define XP_END_PROTOS }; #include "NSReg.h" #endif #if 0 #ifdef XP_MAC #ifdef MOZ_NGLAYOUT #define IMPL_MAC_REPOSITORY #include "nsMacRepository.h" #endif #endif #endif #include "xcDllStore.h" #include "nsIServiceManager.h" nsHashtable *nsRepository::factories = NULL; PRMonitor *nsRepository::monitor = NULL; nsDllStore *nsRepository::dllStore = NULL; static PRLogModuleInfo *logmodule = NULL; static NS_DEFINE_IID(kFactory2IID, NS_IFACTORY2_IID); class FactoryEntry { public: nsCID cid; nsIFactory *factory; // DO NOT DELETE THIS. Many FactoryEntry(s) could be sharing the same Dll. // This gets deleted from the dllStore going away. nsDll *dll; FactoryEntry(const nsCID &aClass, nsIFactory *aFactory, const char *aLibrary) : cid(aClass), factory(aFactory), dll(NULL) { nsDllStore *dllCollection = nsRepository::dllStore; if (aLibrary == NULL) { return; } // If dll not already in dllCollection, add it. // PR_EnterMonitor(nsRepository::monitor); dll = dllCollection->Get(aLibrary); // PR_ExitMonitor(nsRepository::monitor); if (dll == NULL) { // Add a new Dll into the nsDllStore dll = new nsDll(aLibrary); if (dll->GetStatus() != DLL_OK) { // Cant create a nsDll. Backoff. delete dll; dll = NULL; } else { // PR_EnterMonitor(nsRepository::monitor); dllCollection->Put(aLibrary, dll); // PR_ExitMonitor(nsRepository::monitor); } } } ~FactoryEntry(void) { if (factory != NULL) { factory->Release(); } // DO NOT DELETE nsDll *dll; } }; class IDKey: public nsHashKey { private: nsID id; public: IDKey(const nsID &aID) { id = aID; } PRUint32 HashValue(void) const { return id.m0; } PRBool Equals(const nsHashKey *aKey) const { return (id.Equals(((const IDKey *) aKey)->id)); } nsHashKey *Clone(void) const { return new IDKey(id); } }; #ifdef USE_NSREG #define USE_REGISTRY static nsresult platformRegister(const nsCID &aCID, const char *aLibrary) { HREG hreg; REGERR err = NR_RegOpen(NULL, &hreg); if (err == REGERR_OK) { RKEY key; err = NR_RegAddKey(hreg, ROOTKEY_COMMON, "Classes", &key); if (err == REGERR_OK) { char *cidString = aCID.ToString(); err = NR_RegSetEntryString(hreg, key, cidString, (char *) aLibrary); delete [] cidString; } NR_RegClose(hreg); } return err; } static nsresult platformUnregister(const nsCID &aCID, const char *aLibrary) { HREG hreg; REGERR err = NR_RegOpen(NULL, &hreg); if (err == REGERR_OK) { RKEY key; err = NR_RegAddKey(hreg, ROOTKEY_COMMON, "Classes", &key); if (err == REGERR_OK) { char *cidString = aCID.ToString(); err = NR_RegDeleteEntry(hreg, key, cidString); delete [] cidString; } NR_RegClose(hreg); } return err; } static FactoryEntry *platformFind(const nsCID &aCID) { FactoryEntry *res = NULL; HREG hreg; REGERR err = NR_RegOpen(NULL, &hreg); if (err == REGERR_OK) { RKEY key; err = NR_RegGetKey(hreg, ROOTKEY_COMMON, "Classes", &key); if (err == REGERR_OK) { char *cidString = aCID.ToString(); char library[256]; uint32 len = 256; err = NR_RegGetEntryString(hreg, key, cidString, library, len); delete [] cidString; if (err == REGERR_OK) { res = new FactoryEntry(aCID, NULL, library); } } NR_RegClose(hreg); } return res; } #endif // USE_NSREG nsresult nsRepository::loadFactory(FactoryEntry *aEntry, nsIFactory **aFactory) { if (aFactory == NULL) { return NS_ERROR_NULL_POINTER; } *aFactory = NULL; if (aEntry->dll->IsLoaded() == PR_FALSE) { // Load the dll PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: + Loading \"%s\".", aEntry->dll->GetFullPath())); if (aEntry->dll->Load() == PR_FALSE) { PR_LOG(logmodule, PR_LOG_ERROR, ("nsRepository: Library load unsuccessful.")); 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->GetFullPath(), aEntry->dll->GetInstance()); #endif nsFactoryProc proc = (nsFactoryProc) aEntry->dll->FindSymbol("NSGetFactory"); if (proc != NULL) { nsIServiceManager* serviceMgr = NULL; nsresult res = nsServiceManager::GetGlobalServiceManager(&serviceMgr); if (res == NS_OK) { res = proc(aEntry->cid, serviceMgr, aFactory); } return res; } PR_LOG(logmodule, PR_LOG_ERROR, ("nsRepository: NSGetFactory entrypoint not found.")); return NS_ERROR_FACTORY_NOT_LOADED; } nsresult nsRepository::FindFactory(const nsCID &aClass, nsIFactory **aFactory) { checkInitialized(); if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsRepository: Finding Factory."); PR_LogPrint("nsRepository: + %s", buf); delete [] buf; } if (aFactory == NULL) { PR_LOG(logmodule, PR_LOG_ERROR, ("nsRepository: !! NULL pointer.")); return NS_ERROR_NULL_POINTER; } PR_EnterMonitor(monitor); nsIDKey key(aClass); FactoryEntry *entry = (FactoryEntry*) factories->Get(&key); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; #ifdef USE_REGISTRY if (entry == NULL) { entry = platformFind(aClass); // If we got one, cache it in our hashtable if (entry != NULL) { factories->Put(&key, entry); } } #endif PR_ExitMonitor(monitor); if (entry != NULL) { if ((entry)->factory == NULL) { res = loadFactory(entry, aFactory); } else { *aFactory = entry->factory; (*aFactory)->AddRef(); res = NS_OK; } } PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: ! Find Factory %s", res == NS_OK ? "succeeded" : "failed")); return res; } nsresult nsRepository::checkInitialized(void) { nsresult res = NS_OK; if (factories == NULL) { res = Initialize(); } return res; } nsresult nsRepository::Initialize(void) { if (factories == NULL) { factories = new nsHashtable(); } if (monitor == NULL) { monitor = PR_NewMonitor(); } if (logmodule == NULL) { logmodule = PR_NewLogModule("nsRepository"); } if (dllStore == NULL) { dllStore = new nsDllStore(); } PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: Initialized.")); #ifdef USE_NSREG NR_StartupRegistry(); #endif // Initiate autoreg AutoRegister(NS_Startup, NULL); return NS_OK; } nsresult nsRepository::CreateInstance(const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID, void **aResult) { checkInitialized(); if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsRepository: Creating Instance."); PR_LogPrint("nsRepository: + %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); factory->Release(); return res; } return NS_ERROR_FACTORY_NOT_REGISTERED; } nsresult nsRepository::CreateInstance2(const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID, void *aSignature, void **aResult) { if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsRepository: Creating Instance."); PR_LogPrint("nsRepository: + %s.", buf); PR_LogPrint("nsRepository: + Signature = %p.", aSignature); delete [] buf; } if (aResult == NULL) { return NS_ERROR_NULL_POINTER; } *aResult = NULL; nsIFactory *factory = NULL; nsresult res = FindFactory(aClass, &factory); if (NS_SUCCEEDED(res)) { nsIFactory2 *factory2 = NULL; res = NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT; factory->QueryInterface(kFactory2IID, (void **) &factory2); if (factory2 != NULL) { res = factory2->CreateInstance2(aDelegate, aIID, aSignature, aResult); factory2->Release(); } factory->Release(); return res; } return NS_ERROR_FACTORY_NOT_REGISTERED; } nsresult nsRepository::RegisterFactory(const nsCID &aClass, nsIFactory *aFactory, PRBool aReplace) { checkInitialized(); if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsRepository: Registering Factory."); PR_LogPrint("nsRepository: + %s", buf); PR_LogPrint("nsRepository: + Replace = %d.", (int) aReplace); delete [] buf; } nsIFactory *old = NULL; FindFactory(aClass, &old); if (old != NULL) { old->Release(); if (!aReplace) { PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: ! Factory already registered.")); return NS_ERROR_FACTORY_EXISTS; } } PR_EnterMonitor(monitor); nsIDKey key(aClass); factories->Put(&key, new FactoryEntry(aClass, aFactory, NULL)); PR_ExitMonitor(monitor); PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: ! Factory register succeeded.")); return NS_OK; } nsresult nsRepository::RegisterFactory(const nsCID &aClass, const char *aLibrary, PRBool aReplace, PRBool aPersist) { checkInitialized(); if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsRepository: Registering Factory."); PR_LogPrint("nsRepository: + %s in \"%s\".", buf, aLibrary); PR_LogPrint("nsRepository: + Replace = %d, Persist = %d.", (int) aReplace, (int) aPersist); delete [] buf; } nsIFactory *old = NULL; FindFactory(aClass, &old); if (old != NULL) { old->Release(); if (!aReplace) { PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: ! Factory already registered.")); return NS_ERROR_FACTORY_EXISTS; } } PR_EnterMonitor(monitor); #ifdef USE_REGISTRY if (aPersist == PR_TRUE) { platformRegister(aClass, aLibrary); } else #endif { nsIDKey key(aClass); factories->Put(&key, new FactoryEntry(aClass, NULL, aLibrary)); } PR_ExitMonitor(monitor); PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: ! Factory register succeeded.")); return NS_OK; } nsresult nsRepository::UnregisterFactory(const nsCID &aClass, nsIFactory *aFactory) { checkInitialized(); if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsRepository: Unregistering Factory."); PR_LogPrint("nsRepository: + %s.", buf); delete [] buf; } nsIFactory *old = NULL; FindFactory(aClass, &old); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; if (old != NULL) { if (old == aFactory) { PR_EnterMonitor(monitor); nsIDKey key(aClass); FactoryEntry *entry = (FactoryEntry *) factories->Remove(&key); delete entry; PR_ExitMonitor(monitor); res = NS_OK; } old->Release(); } PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: ! Factory unregister %s.", res == NS_OK ? "succeeded" : "failed")); return res; } nsresult nsRepository::UnregisterFactory(const nsCID &aClass, const char *aLibrary) { checkInitialized(); if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); PR_LogPrint("nsRepository: Unregistering Factory."); PR_LogPrint("nsRepository: + %s in \"%s\".", buf, aLibrary); delete [] buf; } nsIDKey key(aClass); FactoryEntry *old = (FactoryEntry *) factories->Get(&key); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; PR_EnterMonitor(monitor); if (old != NULL) { if (old->dll->GetFullPath() != NULL && #ifdef XP_UNIX PL_strcasecmp(old->dll->GetFullPath(), aLibrary) #else PL_strcmp(old->dll->GetFullPath(), aLibrary) #endif ) { FactoryEntry *entry = (FactoryEntry *) factories->Remove(&key); delete entry; res = NS_OK; } } #ifdef USE_REGISTRY res = platformUnregister(aClass, aLibrary); #endif PR_ExitMonitor(monitor); PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: ! Factory unregister %s.", res == NS_OK ? "succeeded" : "failed")); return res; } static PRBool freeLibraryEnum(nsHashKey *aKey, void *aData, void* closure) { FactoryEntry *entry = (FactoryEntry *) aData; if (entry->dll->IsLoaded() == PR_TRUE) { nsCanUnloadProc proc = (nsCanUnloadProc) entry->dll->FindSymbol("NSCanUnload"); if (proc != NULL) { PRBool res = proc(); if (res) { PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: + Unloading \"%s\".", entry->dll->GetFullPath())); entry->dll->Unload(); } } } return PR_TRUE; } nsresult nsRepository::FreeLibraries(void) { PR_EnterMonitor(monitor); PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: Freeing Libraries.")); factories->Enumerate(freeLibraryEnum); PR_ExitMonitor(monitor); return NS_OK; } /** * AutoRegister(RegistrationInstant, const char *pathlist) * * Given a ; separated list of paths, this will ensure proper registration * of all components. A default pathlist is maintained in the registry at * \\HKEYROOT_COMMON\\Classes\\PathList * In addition to looking at the pathlist, the default pathlist is looked at. * * This will take care not loading already registered dlls, finding and * registering new dlls, re-registration of modified dlls * */ nsresult nsRepository::AutoRegister(NSRegistrationInstant when, const char* pathlist) { if (pathlist != NULL) { SyncComponentsInPathList(pathlist); } //XXX get default pathlist from registry //XXX Temporary hack. Registering components from current directory const char *defaultPathList = "."; SyncComponentsInPathList(defaultPathList); return (NS_OK); } nsresult nsRepository::AddToDefaultPathList(const char *pathlist) { //XXX add pathlist to the defaultpathlist in the registrys return (NS_ERROR_FAILURE); } nsresult nsRepository::SyncComponentsInPathList(const char *pathlist) { #ifndef XP_UNIX char *paths = PL_strdup(pathlist); if (paths == NULL || *paths == '\0') return(NS_ERROR_FAILURE); char *pathsMem = paths; while (paths != NULL) { char *nextpath = PL_strchr(paths, NS_PATH_SEPARATOR); if (nextpath != NULL) *nextpath = '\0'; SyncComponentsInDir(paths); paths = nextpath; } PL_strfree(pathsMem); #endif return (NS_OK); } nsresult nsRepository::SyncComponentsInDir(const char *dir) { PRDir *prdir = PR_OpenDir(dir); if (prdir == NULL) return (NS_ERROR_FAILURE); // Create a buffer that has dir/ in it so we can append // the filename each time in the loop char fullname[NS_MAX_FILENAME_LEN]; PL_strncpyz(fullname, dir, sizeof(fullname)); unsigned int n = strlen(fullname); if (n+1 < sizeof(fullname)) { fullname[n] = PR_GetDirectorySeparator(); n++; } char *filepart = fullname + n; PRDirEntry *dirent = NULL; while ((dirent = PR_ReadDir(prdir, PR_SKIP_BOTH)) != NULL) { PL_strncpyz(filepart, dirent->name, sizeof(fullname)-n); nsresult ret = SyncComponentsInFile(fullname); if (NS_FAILED(ret) && NS_ERROR_GET_CODE(ret) == NS_XPCOM_ERRORCODE_IS_DIR) { SyncComponentsInDir(fullname); } } // foreach file PR_CloseDir(prdir); return (NS_OK); } nsresult nsRepository::SyncComponentsInFile(const char *fullname) { const char *ValidDllExtensions[] = { ".dll", /* Windows */ ".dso", /* Unix */ ".so", /* Unix */ ".sl", /* Unix: HP */ "_dll", /* Mac ? */ ".dlm", /* new for all platforms */ NULL }; PRFileInfo64 statbuf; if (PR_GetFileInfo64(fullname, &statbuf) != PR_SUCCESS) { // Skip files that cannot be stat return (NS_ERROR_FAILURE); } if (statbuf.type == PR_FILE_DIRECTORY) { // Cant register a directory return (NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, NS_XPCOM_ERRORCODE_IS_DIR)); } else if (statbuf.type != PR_FILE_FILE) { // Skip non-files return (NS_ERROR_FAILURE); } // deal with only files that have the right extension PRBool validExtension = PR_FALSE; int flen = PL_strlen(fullname); 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(&(fullname[flen - extlen]), ValidDllExtensions[i]) ) { validExtension = PR_TRUE; break; } } if (validExtension == PR_FALSE) { // Skip invalid extensions return (NS_ERROR_FAILURE); } // Check if dll is one that we have already seen nsDll *dll = dllStore->Get(fullname); if (dll == NULL) { // XXX Create nsDll for this from registry and // XXX add it to our dll cache dllStore. } if (dll != NULL) { // Make sure the dll is OK if (dll->GetStatus() != NS_OK) { PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: + nsDll not NS_OK \"%s\". Skipping...", dll->GetFullPath())); return (NS_ERROR_FAILURE); } // We already have seen this dll. Check if this dll changed if (LL_EQ(dll->GetLastModifiedTime(), statbuf.modifyTime) && LL_EQ(dll->GetSize(), statbuf.size)) { // Dll hasn't changed. Skip. PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: + nsDll not changed and already " "registered \"%s\". Skipping...", dll->GetFullPath())); return (NS_OK); } // Aagh! the dll has changed since the last time we saw it. // re-register dll if (dll->IsLoaded()) { // We are screwed. We loaded the old version of the dll // and now we find that the on-disk copy if newer. // The only thing to do would be to ask the dll if it can // unload itself. It can do that if it hasn't created objects // yet. nsCanUnloadProc proc = (nsCanUnloadProc) dll->FindSymbol("NSCanUnload"); if (proc != NULL) { PRBool res = proc(/*PR_TRUE*/); if (res) { PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: + Unloading \"%s\".", dll->GetFullPath())); dll->Unload(); } else { // THIS IS THE WORST SITUATION TO BE IN. // Dll doesn't want to be unloaded. Cannot re-register // this dll. PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: *** Dll already loaded. " "Cannot unload either. Hence cannot re-register " "\"%s\". Skipping...", dll->GetFullPath())); return (NS_ERROR_FAILURE); } } } // 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(logmodule, PR_LOG_ALWAYS, ("nsRepository: Dll still loaded. Cannot re-register " "\"%s\". Skipping...", dll->GetFullPath())); return (NS_ERROR_FAILURE); } } // dll != NULL else { // Create and add the dll to the dllStore // 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(fullname); dllStore->Put(fullname, 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(logmodule, PR_LOG_ALWAYS, ("nsRepository: Autoregistration FAILED for " "\"%s\". Skipping...", dll->GetFullPath())); // XXX Mark dll as not xpcom dll along with modified time // XXX and size in the registry so that in the next // XXX session, we wont do all this again until // XXX the dll changes. ret = NS_ERROR_FAILURE; } else { PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: Autoregistration Passed for " "\"%s\". Skipping...", dll->GetFullPath())); // XXX Mark dll along with modified time and size in the // XXX registry. } return (ret); } /* * SelfRegisterDll * * Given a dll abstraction, this will load, selfregister the dll and * unload the dll. * */ nsresult nsRepository::SelfRegisterDll(nsDll *dll) { // Precondition: dll is not loaded already PR_ASSERT(dll->IsLoaded() == PR_FALSE); if (dll->Load() == PR_FALSE) { // Cannot load. Probably not a dll. return(NS_ERROR_FAILURE); } nsRegisterProc regproc = (nsRegisterProc)dll->FindSymbol("NSRegisterSelf"); nsresult res; if (regproc == NULL) { // Smart registration NSQuickRegisterData qr = (NSQuickRegisterData)dll->FindSymbol( NS_QUICKREGISTER_DATA_SYMBOL); if (qr == NULL) { return(NS_ERROR_NO_INTERFACE); } // XXX register the quick registration data on behalf of the dll } else { // Call the NSRegisterSelfProc to enable dll registration nsIServiceManager* serviceMgr = NULL; nsresult res = nsServiceManager::GetGlobalServiceManager(&serviceMgr); if (res == NS_OK) { res = regproc(/* serviceMgr, */ dll->GetFullPath()); } dll->Unload(); } return (res); } nsresult nsRepository::SelfUnregisterDll(nsDll *dll) { // Precondition: dll is not loaded PR_ASSERT(dll->IsLoaded() == PR_FALSE); if (dll->Load() == PR_FALSE) { // Cannot load. Probably not a dll. return(NS_ERROR_FAILURE); } nsUnregisterProc unregproc = (nsUnregisterProc) dll->FindSymbol("NSUnregisterSelf"); nsresult res = NS_OK; if (unregproc == NULL) { // Smart unregistration NSQuickRegisterData qr = (NSQuickRegisterData) dll->FindSymbol(NS_QUICKREGISTER_DATA_SYMBOL); if (qr == NULL) { return(NS_ERROR_NO_INTERFACE); } // XXX unregister the dll based on the quick registration data } else { // Call the NSUnregisterSelfProc to enable dll de-registration nsIServiceManager* serviceMgr = NULL; res = nsServiceManager::GetGlobalServiceManager(&serviceMgr); if (res == NS_OK) { res = unregproc(/* serviceMgr, */dll->GetFullPath()); } dll->Unload(); } return (res); }