Back to index

lightning-sunbird  0.9+nobinonly
nsNativeComponentLoader.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org Code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK *****
00037  * This Original Code has been modified by IBM Corporation.
00038  * Modifications made by IBM described herein are
00039  * Copyright (c) International Business Machines
00040  * Corporation, 2000
00041  *
00042  * Modifications to Mozilla code or documentation
00043  * identified per MPL Section 3.3
00044  *
00045  * Date             Modified by     Description of modification
00046  * 04/20/2000       IBM Corp.      Added PR_CALLBACK for Optlink use in OS2
00047  */
00048 
00049 #include "prmem.h"
00050 #include "prerror.h"
00051 #include "prsystem.h"           // PR_GetDirectorySeparator
00052 #include "nsNativeComponentLoader.h"
00053 #include "nsComponentManager.h"
00054 #include "nsCOMPtr.h"
00055 #include "nsIServiceManager.h"
00056 #include "nsIModule.h"
00057 #include "xcDll.h"
00058 #include "nsHashtable.h"
00059 #include "nsXPIDLString.h"
00060 #include "nsCRT.h"
00061 #include "nsIObserverService.h"
00062 
00063 #if defined(XP_MAC)  // sdagley dougt fix
00064 #include <Files.h>
00065 #include <Errors.h>
00066 #include "nsILocalFileMac.h"
00067 #endif
00068 
00069 #include "prlog.h"
00070 extern NS_COM PRLogModuleInfo *nsComponentManagerLog;
00071 
00072 static PRBool PR_CALLBACK
00073 DLLStore_Destroy(nsHashKey *aKey, void *aData, void* closure)
00074 {
00075     nsDll* entry = NS_STATIC_CAST(nsDll*, aData);
00076     delete entry;
00077     return PR_TRUE;
00078 }
00079 
00080 nsNativeComponentLoader::nsNativeComponentLoader() :
00081     mCompMgr(nsnull),
00082     mDllStore(nsnull, nsnull, DLLStore_Destroy, 
00083               nsnull, 256, PR_TRUE)
00084 {
00085 }
00086 
00087 NS_IMPL_THREADSAFE_ISUPPORTS1(nsNativeComponentLoader, 
00088                               nsIComponentLoader)
00089 
00090 NS_IMETHODIMP
00091 nsNativeComponentLoader::GetFactory(const nsIID & aCID,
00092                                     const char *aLocation,
00093                                     const char *aType,
00094                                     nsIFactory **_retval)
00095 {
00096     nsresult rv;
00097 
00098     if (!_retval)
00099         return NS_ERROR_NULL_POINTER;
00100     
00101     /* use a hashtable of WeakRefs to store the factory object? */
00102 
00103     /* Should this all live in xcDll? */
00104     nsDll *dll;
00105     rv = CreateDll(nsnull, aLocation, &dll);
00106     if (NS_FAILED(rv))
00107         return rv;
00108 
00109     if (!dll)
00110         return NS_ERROR_OUT_OF_MEMORY;
00111 
00112     if (!dll->IsLoaded()) {
00113 #ifdef PR_LOGGING
00114         nsXPIDLCString displayPath;
00115         dll->GetDisplayPath(displayPath);
00116 
00117         PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
00118                ("nsNativeComponentLoader: loading \"%s\"",
00119                 displayPath.get()));
00120 #endif
00121         if (!dll->Load()) {
00122 
00123             PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
00124                    ("nsNativeComponentLoader: load FAILED"));
00125         
00126             char errorMsg[1024] = "<unknown; can't get error from NSPR>";
00127 
00128             if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
00129                 PR_GetErrorText(errorMsg);
00130 
00131             DumpLoadError(dll, "GetFactory", errorMsg);
00132 
00133             return NS_ERROR_FAILURE;
00134         }
00135     }
00136 
00137     /* Get service manager for factory */
00138     nsCOMPtr<nsIServiceManager> serviceMgr;
00139     rv = NS_GetServiceManager(getter_AddRefs(serviceMgr));
00140     if (NS_FAILED(rv))
00141         return rv;      // XXX translate error code?
00142     
00143     rv = GetFactoryFromModule(dll, aCID, _retval);
00144 
00145     PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR,
00146            ("nsNativeComponentLoader: Factory creation %s for %s",
00147             (NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"),
00148             aLocation));
00149 
00150     // If the dll failed to get us a factory. But the dll registered that
00151     // it would be able to create a factory for this CID. mmh!
00152     // We cannot just delete the dll as the dll could be hosting
00153     // other CID for which factory creation can pass.
00154     // We will just let it be. The effect will be next time we try
00155     // creating the object, we will query the dll again. Since the
00156     // dll is loaded, this aint a big hit. So for optimized builds
00157     // this is ok to limp along.
00158     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Factory creation failed");
00159     
00160     return rv;
00161 }
00162 
00163 NS_IMETHODIMP
00164 nsNativeComponentLoader::Init(nsIComponentManager *aCompMgr, nsISupports *aReg)
00165 {
00166     mCompMgr = aCompMgr;
00167     if (!mCompMgr)
00168         return NS_ERROR_INVALID_ARG;
00169 
00170     return NS_OK;
00171 }
00172 
00173 NS_IMETHODIMP
00174 nsNativeComponentLoader::AutoRegisterComponents(PRInt32 aWhen,
00175                                                 nsIFile *aDirectory)
00176 {
00177 #ifdef DEBUG
00178     /* do we _really_ want to print this every time? */
00179     fprintf(stderr, "nsNativeComponentLoader: autoregistering begins.\n");
00180 #endif
00181 
00182     nsresult rv = RegisterComponentsInDir(aWhen, aDirectory);
00183 
00184 #ifdef DEBUG
00185     fprintf(stderr, "nsNativeComponentLoader: autoregistering %s\n",
00186            NS_FAILED(rv) ? "FAILED" : "succeeded");
00187 #endif
00188 
00189     return rv;
00190 }
00191 
00192 nsresult
00193 nsNativeComponentLoader::RegisterComponentsInDir(PRInt32 when,
00194                                                  nsIFile *dir)
00195 {
00196     nsresult rv = NS_ERROR_FAILURE;
00197     PRBool isDir = PR_FALSE;
00198 
00199 #if 0
00200     // Going to many of these checks is a performance hit on the mac.
00201     // Since these routines are called relatively infrequently and
00202     // we will fail anyway down the line if a directory aint there,
00203     // we are commenting this check out.
00204 
00205     // Make sure we are dealing with a directory
00206     rv = dir->IsDirectory(&isDir);
00207     if (NS_FAILED(rv)) return rv;
00208 
00209     if (!isDir)
00210         return NS_ERROR_INVALID_ARG;
00211 #endif /* 0 */
00212 
00213     // Create a directory iterator
00214     nsCOMPtr<nsISimpleEnumerator> dirIterator;
00215     rv = dir->GetDirectoryEntries(getter_AddRefs(dirIterator));
00216     
00217     if (NS_FAILED(rv)) return rv;
00218     
00219     // whip through the directory to register every file
00220     nsCOMPtr<nsIFile> dirEntry;
00221     PRBool more = PR_FALSE;
00222 
00223     rv = dirIterator->HasMoreElements(&more);
00224     if (NS_FAILED(rv)) return rv;
00225     while (more == PR_TRUE)
00226     {
00227         rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry));
00228         if (NS_SUCCEEDED(rv))
00229         {
00230             rv = dirEntry->IsDirectory(&isDir);
00231             if (NS_SUCCEEDED(rv))
00232             {
00233                 if (isDir == PR_TRUE)
00234                 {
00235                     // This is a directory. Grovel for components into the directory.
00236                     rv = RegisterComponentsInDir(when, dirEntry);
00237                 }
00238                 else
00239                 {
00240                     PRBool registered;
00241                     // This is a file. Try to register it.
00242                     rv = AutoRegisterComponent(when, dirEntry, &registered);
00243                 }
00244             }
00245         }
00246         rv = dirIterator->HasMoreElements(&more);
00247         if (NS_FAILED(rv)) return rv;
00248     }
00249     
00250     return rv;
00251 }
00252 
00253 static nsresult PR_CALLBACK
00254 nsFreeLibrary(nsDll *dll, nsIServiceManager *serviceMgr, PRInt32 when)
00255 {
00256     nsresult rv = NS_ERROR_FAILURE;
00257 
00258     if (!dll || dll->IsLoaded() == PR_FALSE)
00259     {
00260         return NS_ERROR_INVALID_ARG;
00261     }
00262 
00263     // Get if the dll was marked for unload in an earlier round
00264     PRBool dllMarkedForUnload = dll->IsMarkedForUnload();
00265 
00266     // Reset dll marking for unload just in case we return with
00267     // an error.
00268     dll->MarkForUnload(PR_FALSE);
00269 
00270     PRBool canUnload = PR_FALSE;
00271 
00272     // Get the module object
00273     nsCOMPtr<nsIModule> mobj;
00274     /* XXXshaver cheat and use the global component manager */
00275     rv = dll->GetModule(NS_STATIC_CAST(nsIComponentManager*, nsComponentManagerImpl::gComponentManager),
00276                         getter_AddRefs(mobj));
00277     if (NS_SUCCEEDED(rv))
00278     {
00279         rv = mobj->CanUnload(nsComponentManagerImpl::gComponentManager, &canUnload);
00280     }
00281 
00282     mobj = nsnull; // Release our reference to the module object
00283     // When shutting down, whether we can unload the dll or not,
00284     // we will shutdown the dll to release any memory it has got
00285     if (when == nsIComponentManagerObsolete::NS_Shutdown)
00286     {
00287         dll->Shutdown();
00288     }
00289         
00290     // Check error status on CanUnload() call
00291     if (NS_FAILED(rv))
00292     {
00293 #ifdef PR_LOGGING
00294         nsXPIDLCString displayPath;
00295         dll->GetDisplayPath(displayPath);
00296 
00297         PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
00298                ("nsNativeComponentLoader: nsIModule::CanUnload() returned error for %s.",
00299                 displayPath.get()));
00300 #endif
00301         return rv;
00302     }
00303 
00304     if (canUnload)
00305     {
00306         if (dllMarkedForUnload)
00307         {
00308 #ifdef PR_LOGGING
00309             nsXPIDLCString displayPath;
00310             dll->GetDisplayPath(displayPath);
00311 
00312             PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, 
00313                    ("nsNativeComponentLoader: + Unloading \"%s\".", displayPath.get()));
00314 #endif
00315 
00316 #ifdef DEBUG_dougt
00317             // XXX dlls aren't counting their outstanding instances correctly
00318             // XXX hence, dont unload until this gets enforced.
00319             rv = dll->Unload();
00320 #endif /* 0 */
00321         }
00322         else
00323         {
00324 #ifdef PR_LOGGING
00325             nsXPIDLCString displayPath;
00326             dll->GetDisplayPath(displayPath);
00327 
00328             PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
00329                    ("nsNativeComponentLoader: Ready for unload \"%s\".", displayPath.get()));
00330 #endif
00331         }
00332     }
00333     else
00334     {
00335 #ifdef PR_LOGGING
00336         nsXPIDLCString displayPath;
00337         dll->GetDisplayPath(displayPath);
00338 
00339         PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, 
00340                ("nsNativeComponentLoader: NOT ready for unload %s", displayPath.get()));
00341 #endif
00342         rv = NS_ERROR_FAILURE;
00343     }
00344     return rv;
00345 }
00346 
00347 struct freeLibrariesClosure
00348 {
00349     nsIServiceManager *serviceMgr;
00350     PRInt32 when;
00351 };
00352 
00353 static PRBool PR_CALLBACK
00354 nsFreeLibraryEnum(nsHashKey *aKey, void *aData, void* closure) 
00355 {
00356     nsDll *dll = (nsDll *) aData;
00357     struct freeLibrariesClosure *callData = (struct freeLibrariesClosure *) closure;
00358     nsFreeLibrary(dll,
00359                   (callData ? callData->serviceMgr : NULL),
00360                   (callData ? callData->when : nsIComponentManagerObsolete::NS_Timer));
00361     return PR_TRUE;
00362 }
00363 
00364 /*
00365  * SelfRegisterDll
00366  *
00367  * Given a dll abstraction, this will load, selfregister the dll and
00368  * unload the dll.
00369  *
00370  */
00371 nsresult
00372 nsNativeComponentLoader::SelfRegisterDll(nsDll *dll,
00373                                          const char *registryLocation,
00374                                          PRBool deferred)
00375 {
00376     // Precondition: dll is not loaded already, unless we're deferred
00377     PR_ASSERT(deferred || dll->IsLoaded() == PR_FALSE);
00378 
00379     nsresult res;
00380     nsCOMPtr<nsIServiceManager> serviceMgr;
00381     res = NS_GetServiceManager(getter_AddRefs(serviceMgr));
00382     if (NS_FAILED(res)) return res;
00383 
00384     if (dll->Load() == PR_FALSE)
00385     {
00386         // Cannot load. Probably not a dll.
00387         char errorMsg[1024] = "Cannot get error from nspr. Not enough memory.";
00388         if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
00389             PR_GetErrorText(errorMsg);
00390 
00391         DumpLoadError(dll, "SelfRegisterDll", errorMsg);
00392 
00393         return NS_ERROR_FAILURE;
00394     }
00395 
00396 #ifdef PR_LOGGING
00397     nsXPIDLCString displayPath;
00398     dll->GetDisplayPath(displayPath);
00399     
00400     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
00401            ("nsNativeComponentLoader: Loaded \"%s\".", displayPath.get()));
00402 #endif
00403 
00404     // Tell the module to self register
00405     nsCOMPtr<nsIFile> fs;
00406     nsCOMPtr<nsIModule> mobj;
00407     res = dll->GetModule(mCompMgr, getter_AddRefs(mobj));
00408     if (NS_SUCCEEDED(res))
00409     {
00410         /*************************************************************
00411          * WARNING: Why are use introducing 'res2' here and then     *
00412          * later assigning it to 'res' rather than just using 'res'? *
00413          * This is because this code turns up a code-generation bug  *
00414          * in VC6 on NT. Assigning to 'res' on the next line causes  *
00415          * the value of 'dll' to get nulled out! The two seem to be  *
00416          * getting aliased together during compilation.              *
00417          *************************************************************/
00418         nsresult res2 = dll->GetDllSpec(getter_AddRefs(fs));    // don't change 'res2' -- see warning, above
00419         if (NS_SUCCEEDED(res2)) {
00420             res = mobj->RegisterSelf(mCompMgr, fs, registryLocation,
00421                                      nativeComponentType);
00422         }
00423         else
00424         {
00425             res = res2;         // don't take this out -- see warning, above
00426 
00427 #ifdef PR_LOGGING
00428             nsXPIDLCString displayPath;
00429             dll->GetDisplayPath(displayPath);
00430             PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, 
00431                    ("nsNativeComponentLoader: dll->GetDllSpec() on %s FAILED.",
00432                     displayPath.get()));
00433 #endif
00434         }
00435         mobj = NULL;    // Force a release of the Module object before unload()
00436     }
00437 
00438     // Update the timestamp and size of the dll in registry
00439     // Don't enter deferred modules in the registry, because it might only be
00440     // able to register on some later autoreg, after another component has been
00441     // installed.
00442     if (res != NS_ERROR_FACTORY_REGISTER_AGAIN) {
00443         PRInt64 modTime;
00444         if (!fs)
00445             return res;
00446         
00447         fs->GetLastModifiedTime(&modTime);
00448         nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(mCompMgr);
00449         if (!manager)
00450             return NS_ERROR_FAILURE;
00451         
00452         nsCOMPtr<nsIFile> fs;
00453         res = dll->GetDllSpec(getter_AddRefs(fs));
00454         if (NS_FAILED(res)) return res;
00455         
00456         manager->SaveFileInfo(fs, registryLocation, modTime);
00457     }
00458 
00459     return res;
00460 }
00461 
00462 //
00463 // MOZ_DEMANGLE_SYMBOLS is only a linux + MOZ_DEBUG thing.
00464 //
00465 
00466 #if defined(MOZ_DEMANGLE_SYMBOLS)
00467 #include "nsTraceRefcntImpl.h" // for nsTraceRefcntImpl::DemangleSymbol()
00468 #endif
00469 
00470 nsresult 
00471 nsNativeComponentLoader::DumpLoadError(nsDll *dll, 
00472                                        const char *aCallerName,
00473                                        const char *aNsprErrorMsg)
00474 {
00475     PR_ASSERT(aCallerName != NULL);
00476     
00477     if (nsnull == dll || nsnull == aNsprErrorMsg)
00478         return NS_OK;
00479 
00480     nsCAutoString errorMsg(aNsprErrorMsg);
00481 
00482 #if defined(MOZ_DEMANGLE_SYMBOLS)
00483     // Demangle undefined symbols
00484     nsCAutoString undefinedMagicString("undefined symbol:");
00485     
00486     PRInt32 offset = errorMsg.Find(undefinedMagicString, PR_TRUE);
00487     
00488     if (offset != kNotFound)
00489     {
00490         nsCAutoString symbol(errorMsg);
00491         nsCAutoString demangledSymbol;
00492         
00493         symbol.Cut(0,offset);
00494         
00495         symbol.Cut(0,undefinedMagicString.Length());
00496         
00497         symbol.StripWhitespace();
00498         
00499         char demangled[4096] = "\0";
00500         
00501         nsTraceRefcntImpl::DemangleSymbol(symbol.get(),demangled,sizeof(demangled));
00502         
00503         if (demangled && *demangled != '\0')
00504             demangledSymbol = demangled;
00505         
00506         if (!demangledSymbol.IsEmpty())
00507         {
00508             nsCAutoString tmp(errorMsg);
00509             
00510             
00511             tmp.Cut(offset + undefinedMagicString.Length(),
00512                     tmp.Length() - offset - undefinedMagicString.Length());
00513             
00514             tmp += " \n";
00515             
00516             tmp += demangledSymbol;
00517             
00518             errorMsg = tmp;
00519         }    
00520     }
00521 #endif // MOZ_DEMANGLE_SYMBOLS
00522     nsXPIDLCString displayPath;
00523     dll->GetDisplayPath(displayPath);
00524 
00525 #ifdef DEBUG
00526     fprintf(stderr, 
00527             "nsNativeComponentLoader: %s(%s) Load FAILED with error: %s\n", 
00528             aCallerName,
00529             displayPath.get(), 
00530             errorMsg.get());
00531 #endif
00532 
00533     // Do NSPR log
00534 #ifdef PR_LOGGING
00535     PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
00536            ("nsNativeComponentLoader: %s(%s) Load FAILED with error: %s", 
00537             aCallerName,
00538             displayPath.get(), 
00539             errorMsg.get()));
00540 #endif
00541     return NS_OK;
00542 }
00543 
00544 nsresult
00545 nsNativeComponentLoader::SelfUnregisterDll(nsDll *dll)
00546 {
00547     nsresult res;
00548     nsCOMPtr<nsIServiceManager> serviceMgr;
00549     res = NS_GetServiceManager(getter_AddRefs(serviceMgr));
00550     if (NS_FAILED(res)) return res;
00551 
00552     if (dll->Load() == PR_FALSE)
00553     {
00554         // Cannot load. Probably not a dll.
00555         return(NS_ERROR_FAILURE);
00556     }
00557         
00558     // Tell the module to self register
00559     nsCOMPtr<nsIModule> mobj;
00560     res = dll->GetModule(mCompMgr, getter_AddRefs(mobj));
00561     if (NS_SUCCEEDED(res))
00562     {
00563 #ifdef PR_LOGGING
00564         nsXPIDLCString displayPath;
00565         dll->GetDisplayPath(displayPath);
00566 
00567         PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, 
00568                ("nsNativeComponentLoader: %s using nsIModule to unregister self.", displayPath.get()));
00569 #endif
00570         nsCOMPtr<nsIFile> fs;
00571         res = dll->GetDllSpec(getter_AddRefs(fs));
00572         if (NS_FAILED(res)) return res;
00573         // Get registry location for spec
00574         nsXPIDLCString registryName;
00575                 
00576         // what I want to do here is QI for a Component Registration Manager.  Since this 
00577         // has not been invented yet, QI to the obsolete manager.  Kids, don't do this at home.
00578         nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &res);
00579         if (obsoleteManager)
00580             res = obsoleteManager->RegistryLocationForSpec(fs, getter_Copies(registryName));
00581 
00582         if (NS_FAILED(res)) return res;
00583         mobj->UnregisterSelf(mCompMgr, fs, registryName);
00584     }
00585     return res;
00586 }
00587 
00588 nsresult
00589 nsNativeComponentLoader::AutoUnregisterComponent(PRInt32 when,
00590                                                  nsIFile *component,
00591                                                  PRBool *unregistered)
00592 {
00593 
00594     nsresult rv = NS_ERROR_FAILURE;
00595 
00596     *unregistered = PR_FALSE;
00597 
00598     nsXPIDLCString persistentDescriptor;
00599     // what I want to do here is QI for a Component Registration Manager.  Since this 
00600     // has not been invented yet, QI to the obsolete manager.  Kids, don't do this at home.
00601     nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
00602     if (obsoleteManager)
00603         rv = obsoleteManager->RegistryLocationForSpec(component,
00604                                                       getter_Copies(persistentDescriptor));
00605     if (NS_FAILED(rv)) return rv;
00606 
00607     // Notify observers, if any, of autoregistration work
00608     nsCOMPtr<nsIObserverService> observerService = 
00609              do_GetService("@mozilla.org/observer-service;1", &rv);
00610     if (NS_SUCCEEDED(rv))
00611     {
00612       nsCOMPtr<nsIServiceManager> mgr;
00613       rv = NS_GetServiceManager(getter_AddRefs(mgr));
00614       if (NS_SUCCEEDED(rv))
00615       {
00616         (void) observerService->NotifyObservers(mgr,
00617                                                 NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
00618                                                 NS_LITERAL_STRING("Unregistering native component").get());
00619       }
00620     }
00621 
00622     nsDll *dll = NULL;
00623     rv = CreateDll(component, persistentDescriptor, &dll);
00624     if (NS_FAILED(rv) || dll == NULL) return rv;
00625 
00626     rv = SelfUnregisterDll(dll);
00627 
00628 #ifdef PR_LOGGING
00629     nsXPIDLCString displayPath;
00630     dll->GetDisplayPath(displayPath);
00631 
00632     PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR,
00633            ("nsNativeComponentLoader: AutoUnregistration for %s %s.",
00634             (NS_FAILED(rv) ? "FAILED" : "succeeded"), displayPath.get()));
00635 #endif
00636 
00637     if (NS_FAILED(rv))
00638         return rv;
00639 
00640     // Remove any autoreg info about this dll
00641     nsCStringKey key(persistentDescriptor);
00642     mDllStore.RemoveAndDelete(&key);
00643     
00644     nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(mCompMgr);
00645     NS_ASSERTION(manager, "Something is terribly wrong");
00646 
00647     manager->RemoveFileInfo(component, nsnull);
00648 
00649     *unregistered = PR_TRUE;
00650     return rv;
00651 }
00652 
00653 nsresult
00654 nsNativeComponentLoader::AutoRegisterComponent(PRInt32 when,
00655                                                nsIFile *component,
00656                                                PRBool *registered)
00657 {
00658     nsresult rv;
00659     if (!registered)
00660         return NS_ERROR_NULL_POINTER;
00661 
00662     *registered = PR_FALSE;
00663 
00664     /* this should be a pref or registry entry, or something */
00665     static const char *ValidDllExtensions[] = {
00666         ".dll",     /* Windows */
00667         ".so",      /* Unix */
00668         ".shlb",    /* Mac ? */
00669         ".dso",     /* Unix ? */
00670         ".dylib",   /* Unix: Mach */
00671         ".so.1.0",  /* Unix: BSD */
00672         ".sl",      /* Unix: HP-UX */
00673 #if defined(VMS)
00674         ".exe",     /* Open VMS */
00675 #endif
00676         ".dlm",     /* new for all platforms */
00677         NULL
00678     };
00679 
00680     *registered = PR_FALSE;
00681 
00682 #if 0
00683     // This is a performance hit on mac. Since we have already checked
00684     // this; plus is we dont, load will fail anyway later on, this
00685     // is being commented out.
00686 
00687     // Ensure we are dealing with a file as opposed to a dir
00688     PRBool b = PR_FALSE;
00689 
00690     rv = component->IsFile(&b);
00691     if (NS_FAILED(rv) || !b)
00692         return rv;
00693 #endif /* 0 */
00694 
00695     // deal only with files that have a valid extension
00696     PRBool validExtension = PR_FALSE;
00697 
00698 #if defined(XP_MAC)  // sdagley dougt fix
00699     // rjc - on Mac, check the file's type code (skip checking the creator code)
00700     
00701     nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(component);
00702     if (localFileMac)
00703     {
00704       OSType    type;
00705       rv = localFileMac->GetFileType(&type);
00706       if (NS_SUCCEEDED(rv))
00707       {
00708         // on Mac, Mozilla shared libraries are of type 'shlb'
00709         // Note: we don't check the creator (which for Mozilla is 'MOZZ')
00710         // so that 3rd party shared libraries will be noticed!
00711         validExtension = ((type == 'shlb') || (type == 'NSPL'));
00712       }
00713     }
00714 
00715 #else
00716     nsCAutoString leafName;
00717     rv = component->GetNativeLeafName(leafName);
00718     if (NS_FAILED(rv)) return rv;
00719     int flen = leafName.Length();
00720     for (int i=0; ValidDllExtensions[i] != NULL; i++)
00721     {
00722         int extlen = PL_strlen(ValidDllExtensions[i]);
00723             
00724         // Does fullname end with this extension
00725         if (flen >= extlen &&
00726             !PL_strcasecmp(leafName.get() + (flen - extlen), ValidDllExtensions[i])
00727             )
00728         {
00729             validExtension = PR_TRUE;
00730             break;
00731         }
00732     }
00733 #endif
00734         
00735     if (validExtension == PR_FALSE)
00736         // Skip invalid extensions
00737         return NS_OK;
00738 
00739     nsXPIDLCString persistentDescriptor;
00740     // what I want to do here is QI for a Component Registration Manager.  Since this 
00741     // has not been invented yet, QI to the obsolete manager.  Kids, don't do this at home.
00742     nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
00743     if (obsoleteManager)
00744         rv = obsoleteManager->RegistryLocationForSpec(component, 
00745                                                       getter_Copies(persistentDescriptor));
00746     if (NS_FAILED(rv))
00747         return rv;
00748 
00749     nsCStringKey key(persistentDescriptor);
00750 
00751     // Get the registry representation of the dll, if any
00752     nsDll *dll;
00753     rv = CreateDll(component, persistentDescriptor, &dll);
00754     if (NS_FAILED(rv))
00755         return rv;
00756 
00757     if (dll != NULL)
00758     {
00759         // We already have seen this dll. Check if this dll changed
00760         if (!dll->HasChanged())
00761         {
00762 #ifdef PR_LOGGING
00763             nsXPIDLCString displayPath;
00764             dll->GetDisplayPath(displayPath);
00765             
00766             // Dll hasn't changed. Skip.
00767             PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, 
00768                    ("nsNativeComponentLoader: + nsDll not changed \"%s\". Skipping...",
00769                     displayPath.get()));
00770 #endif
00771             *registered = PR_TRUE;
00772             return NS_OK;
00773         }
00774 
00775         // Aagh! the dll has changed since the last time we saw it.
00776         // re-register dll
00777 
00778 
00779         // Notify observers, if any, of autoregistration work
00780         nsCOMPtr<nsIObserverService> observerService = 
00781                  do_GetService("@mozilla.org/observer-service;1", &rv);
00782         if (NS_SUCCEEDED(rv))
00783         {
00784           nsCOMPtr<nsIServiceManager> mgr;
00785           rv = NS_GetServiceManager(getter_AddRefs(mgr));
00786           if (NS_SUCCEEDED(rv))
00787           {
00788             // this string can't come from a string bundle, because we
00789             // don't have string bundles yet.
00790             NS_ConvertASCIItoUCS2 fileName("(no name)");
00791             
00792             // get the file name
00793             nsCOMPtr<nsIFile> dllSpec;
00794             if (NS_SUCCEEDED(dll->GetDllSpec(getter_AddRefs(dllSpec))) && dllSpec)
00795             {
00796               dllSpec->GetLeafName(fileName);
00797             }
00798             
00799             // this string can't come from a string bundle, because we
00800             // don't have string bundles yet.
00801             (void) observerService->
00802                 NotifyObservers(mgr,
00803                                 NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
00804                                 PromiseFlatString(NS_LITERAL_STRING("Registering native component ") +
00805                                                   fileName).get());
00806           }
00807         }
00808 
00809         if (dll->IsLoaded())
00810         {
00811             // We loaded the old version of the dll and now we find that the
00812             // on-disk copy if newer. Try to unload the dll.
00813             nsCOMPtr<nsIServiceManager> serviceMgr;
00814             rv = NS_GetServiceManager(getter_AddRefs(serviceMgr));
00815           
00816             rv = nsFreeLibrary(dll, serviceMgr, when);
00817             if (NS_FAILED(rv))
00818             {
00819                 // THIS IS THE WORST SITUATION TO BE IN.
00820                 // Dll doesn't want to be unloaded. Cannot re-register
00821                 // this dll.
00822 #ifdef PR_LOGGING
00823                 nsXPIDLCString displayPath;
00824                 dll->GetDisplayPath(displayPath);
00825                 
00826                 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
00827                        ("nsNativeComponentLoader: *** Dll already loaded. "
00828                         "Cannot unload either. Hence cannot re-register "
00829                         "\"%s\". Skipping...", displayPath.get()));
00830 #endif
00831                 return rv;
00832             }
00833             else {
00834                                 // dll doesn't have a CanUnload proc. Guess it is
00835                                 // ok to unload it.
00836                 dll->Unload();
00837 #ifdef PR_LOGGING
00838                 nsXPIDLCString displayPath;
00839                 dll->GetDisplayPath(displayPath);
00840                 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, 
00841                        ("nsNativeComponentLoader: + Unloading \"%s\". (no CanUnloadProc).",
00842                         displayPath.get()));
00843 #endif
00844             }
00845                 
00846         } // dll isloaded
00847             
00848         // Sanity.
00849         if (dll->IsLoaded())
00850         {
00851             // We went through all the above to make sure the dll
00852             // is unloaded. And here we are with the dll still
00853             // loaded. Whoever taught dp programming...
00854 #ifdef PR_LOGGING
00855             nsXPIDLCString displayPath;
00856             dll->GetDisplayPath(displayPath);
00857             PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
00858                    ("nsNativeComponentLoader: Dll still loaded. Cannot re-register "
00859                     "\"%s\". Skipping...", displayPath.get()));
00860 #endif
00861             return NS_ERROR_FAILURE;
00862         }
00863     } // dll != NULL
00864     else
00865     {
00866         // Create and add the dll to the mDllStore
00867         // It is ok to do this even if the creation of nsDll
00868         // didnt succeed. That way we wont do this again
00869         // when we encounter the same dll.
00870         dll = new nsDll(component, this);
00871         if (dll == NULL)
00872             return NS_ERROR_OUT_OF_MEMORY;
00873         mDllStore.Put(&key, (void *) dll);
00874     } // dll == NULL
00875         
00876     // Either we are seeing the dll for the first time or the dll has
00877     // changed since we last saw it and it is unloaded successfully.
00878     //
00879     // Now we can try register the dll for sure. 
00880     nsresult res = SelfRegisterDll(dll, persistentDescriptor, PR_FALSE);
00881     if (NS_FAILED(res))
00882     {
00883         if (res == NS_ERROR_FACTORY_REGISTER_AGAIN) {
00884             /* defer for later loading */
00885             mDeferredComponents.AppendElement(dll);
00886             *registered = PR_TRUE;
00887             return NS_OK;
00888         } else {
00889 #ifdef PR_LOGGING
00890             nsXPIDLCString displayPath;
00891             dll->GetDisplayPath(displayPath);
00892 
00893             PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
00894                    ("nsNativeComponentLoader: Autoregistration FAILED for "
00895                     "\"%s\". Skipping...", displayPath.get()));
00896 #endif
00897             return NS_ERROR_FACTORY_NOT_REGISTERED;
00898         }
00899     }
00900     else
00901     {
00902 #ifdef PR_LOGGING
00903         nsXPIDLCString displayPath;
00904         dll->GetDisplayPath(displayPath);
00905 
00906         PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
00907                ("nsNativeComponentLoader: Autoregistration Passed for "
00908                 "\"%s\".", displayPath.get()));
00909 #endif
00910         // Marking dll along with modified time and size in the
00911         // registry happens at PlatformRegister(). No need to do it
00912         // here again.
00913         *registered = PR_TRUE;
00914     }
00915     return NS_OK;
00916 }
00917 
00918 nsresult
00919 nsNativeComponentLoader::RegisterDeferredComponents(PRInt32 aWhen,
00920                                                     PRBool *aRegistered)
00921 {
00922 #ifdef DEBUG 
00923     fprintf(stderr, "nsNativeComponentLoader: registering deferred (%d)\n",
00924             mDeferredComponents.Count());
00925 #endif
00926     *aRegistered = PR_FALSE;
00927     if (!mDeferredComponents.Count())
00928         return NS_OK;
00929     
00930     for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) {
00931         nsDll *dll = NS_STATIC_CAST(nsDll *, mDeferredComponents[i]);
00932         nsresult rv = SelfRegisterDll(dll,
00933                                       nsnull,
00934                                       PR_TRUE);
00935         if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) {
00936             if (NS_SUCCEEDED(rv))
00937                 *aRegistered = PR_TRUE;
00938             mDeferredComponents.RemoveElementAt(i);
00939         }
00940     }
00941 #ifdef DEBUG
00942     if (*aRegistered)
00943         fprintf(stderr,
00944                 "nsNativeComponentLoader: registered deferred, %d left\n",
00945                 mDeferredComponents.Count());
00946     else
00947         fprintf(stderr,
00948                 "nsNativeComponentLoader: "
00949                 "didn't register any components, %d left\n",
00950                 mDeferredComponents.Count());
00951 #endif
00952     /* are there any fatal errors? */
00953     return NS_OK;
00954 }
00955 
00956 nsresult
00957 nsNativeComponentLoader::OnRegister(const nsIID &aCID, const char *aType,
00958                                     const char *aClassName,
00959                                     const char *aContractID, 
00960                                     const char *aLocation,
00961                                     PRBool aReplace, 
00962                                     PRBool aPersist)
00963 {
00964     return NS_OK;
00965 }
00966 
00967 nsresult
00968 nsNativeComponentLoader::UnloadAll(PRInt32 aWhen)
00969 {
00970     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsNativeComponentLoader: Unloading...."));
00971 
00972     struct freeLibrariesClosure callData;
00973     callData.serviceMgr = NULL; // XXX need to get this as a parameter
00974     callData.when = aWhen;
00975 
00976     // Cycle through the dlls checking to see if they want to be unloaded
00977     mDllStore.Enumerate(nsFreeLibraryEnum, &callData);
00978     return NS_OK;
00979 }
00980 
00981 //
00982 // CreateDll
00983 // The only way to create a dll or get it from the dll cache. This will
00984 // be called in multiple situations:
00985 //
00986 // 1. Autoregister will create one for each dll it is trying to register. This
00987 //    call will be passing a spec in.
00988 //    {spec, NULL, 0, 0}
00989 //
00990 // 2. GetFactory() This will call CreateDll() with a null spec but will give
00991 //    the registry represented name of the dll. If modtime and size are zero,
00992 //    we will go the registry to find the right modtime and size.
00993 //    {NULL, rel:libpref.so, 0, 0}
00994 //
00995 // 3. Prepopulation of dllCache A dll object created off a registry entry.
00996 //    Specifically dll name is stored    in rel: or abs: or lib: formats in the
00997 //    registry along with its    lastModTime and fileSize.
00998 //    {NULL, rel:libpref.so, 8985659, 20987}
00999 nsresult
01000 nsNativeComponentLoader::CreateDll(nsIFile *aSpec, 
01001                                    const char *aLocation,
01002                                    nsDll **aDll)
01003 {
01004     nsDll *dll;
01005     nsCOMPtr<nsIFile> dllSpec;
01006     nsCOMPtr<nsIFile> spec;
01007     nsresult rv;
01008 
01009     nsCStringKey key(aLocation);
01010     dll = (nsDll *)mDllStore.Get(&key);
01011     if (dll)
01012     {
01013         *aDll = dll;
01014         return NS_OK;
01015     }
01016 
01017     if (!aSpec)
01018     {
01019         // what I want to do here is QI for a Component Registration Manager.  Since this 
01020         // has not been invented yet, QI to the obsolete manager.  Kids, don't do this at home.
01021         nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
01022         if (obsoleteManager)
01023             rv = obsoleteManager->SpecForRegistryLocation(aLocation,
01024                                                           getter_AddRefs(spec));
01025         if (NS_FAILED(rv))
01026             return rv;
01027     }
01028     else
01029     {
01030         spec = aSpec;
01031     }
01032 
01033     if (!dll)
01034     {
01035         dll = new nsDll(spec, this);
01036         if (!dll)
01037             return NS_ERROR_OUT_OF_MEMORY;
01038     }
01039 
01040     *aDll = dll;
01041     mDllStore.Put(&key, dll);
01042     return NS_OK;
01043 }
01044 
01045 nsresult
01046 nsNativeComponentLoader::GetFactoryFromModule(nsDll *aDll, const nsCID &aCID,
01047                                               nsIFactory **aFactory)
01048 {
01049     nsresult rv;
01050 
01051     nsCOMPtr<nsIModule> module;
01052     rv = aDll->GetModule(mCompMgr, getter_AddRefs(module));
01053 
01054     if (NS_FAILED(rv))
01055         return rv;
01056 
01057     return module->GetClassObject(mCompMgr, aCID, NS_GET_IID(nsIFactory),
01058                                   (void **)aFactory);
01059 }