a) create a new nsIComponentManager with only four functions on it: CreateInstance CreateInstanceByContractID GetClassInfo GetClassInfoByContractID. b) rename the old nsIComponentManager to nsIComponentManagerObsolete. c) fixes callers which use to access the nsIComponentManager for component registration functionality. These callers will temporary use the nsIComponentManagerObsolete interface. d) Create a new API NS_GetComponentManager() which mirrors the NS_GetServiceManager() e) Perserves the old NS_GetGlobalComponentManager(). Note the cast usage. r/sr = rpotts@netscape.com alecf@netscape.com brendan@mozilla.org git-svn-id: svn://10.0.0.236/trunk@110748 18797224-902f-48f8-a5cc-f745e15eee43
1237 lines
40 KiB
C++
1237 lines
40 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.1 (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) 1999 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*
|
|
* Contributors:
|
|
* This Original Code has been modified by IBM Corporation.
|
|
* Modifications made by IBM described herein are
|
|
* Copyright (c) International Business Machines
|
|
* Corporation, 2000
|
|
*
|
|
* Modifications to Mozilla code or documentation
|
|
* identified per MPL Section 3.3
|
|
*
|
|
* Date Modified by Description of modification
|
|
* 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
|
|
*/
|
|
|
|
#include "prmem.h"
|
|
#include "prerror.h"
|
|
#include "prsystem.h" // PR_GetDirectorySeparator
|
|
#include "nsNativeComponentLoader.h"
|
|
#include "nsComponentManager.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsIModule.h"
|
|
#include "xcDll.h"
|
|
#include "nsHashtable.h"
|
|
#include "nsHashtableEnumerator.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsCRT.h"
|
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#ifndef OBSOLETE_MODULE_LOADING
|
|
#include "nsObsoleteModuleLoading.h"
|
|
#endif
|
|
|
|
#if defined(XP_MAC) // sdagley dougt fix
|
|
#include <Files.h>
|
|
#include <Errors.h>
|
|
#include "nsILocalFileMac.h"
|
|
#endif
|
|
|
|
#define PRINT_CRITICAL_ERROR_TO_SCREEN 1
|
|
#define USE_REGISTRY 1
|
|
#define XPCOM_USE_NSGETFACTORY 1
|
|
|
|
// Logging of debug output
|
|
#ifdef MOZ_LOGGING
|
|
#define FORCE_PR_LOG /* Allow logging in the release build */
|
|
#endif
|
|
#include "prlog.h"
|
|
extern PRLogModuleInfo *nsComponentManagerLog;
|
|
|
|
nsNativeComponentLoader::nsNativeComponentLoader() :
|
|
mRegistry(nsnull), mCompMgr(nsnull), mDllStore(nsnull)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
static PRBool PR_CALLBACK
|
|
nsDll_Destroy(nsHashKey *aKey, void *aData, void* closure)
|
|
{
|
|
nsDll* entry = NS_STATIC_CAST(nsDll*, aData);
|
|
delete entry;
|
|
return PR_TRUE;
|
|
}
|
|
|
|
nsNativeComponentLoader::~nsNativeComponentLoader()
|
|
{
|
|
mRegistry = nsnull;
|
|
mCompMgr = nsnull;
|
|
|
|
delete mDllStore;
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS1(nsNativeComponentLoader, nsIComponentLoader);
|
|
|
|
NS_IMETHODIMP
|
|
nsNativeComponentLoader::GetFactory(const nsIID & aCID,
|
|
const char *aLocation,
|
|
const char *aType,
|
|
nsIFactory **_retval)
|
|
{
|
|
nsresult rv;
|
|
|
|
if (!_retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
/* use a hashtable of WeakRefs to store the factory object? */
|
|
|
|
/* Should this all live in xcDll? */
|
|
nsDll *dll;
|
|
PRInt64 mod = LL_Zero(), size = LL_Zero();
|
|
rv = CreateDll(nsnull, aLocation, &mod, &size, &dll);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (!dll)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
if (!dll->IsLoaded()) {
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
|
|
("nsNativeComponentLoader: loading \"%s\"",
|
|
dll->GetDisplayPath()));
|
|
|
|
if (!dll->Load()) {
|
|
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("nsNativeComponentLoader: load FAILED"));
|
|
|
|
char errorMsg[1024] = "<unknown; can't get error from NSPR>";
|
|
|
|
if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
|
|
PR_GetErrorText(errorMsg);
|
|
|
|
DumpLoadError(dll, "GetFactory", errorMsg);
|
|
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
|
|
/* Get service manager for factory */
|
|
nsCOMPtr<nsIServiceManager> serviceMgr;
|
|
rv = NS_GetServiceManager(getter_AddRefs(serviceMgr));
|
|
if (NS_FAILED(rv))
|
|
return rv; // XXX translate error code?
|
|
|
|
rv = GetFactoryFromModule(dll, aCID, _retval);
|
|
#ifdef XPCOM_USE_NSGETFACTORY
|
|
if (NS_FAILED(rv)) {
|
|
if (rv == NS_ERROR_FACTORY_NOT_LOADED) {
|
|
rv = GetFactoryFromNSGetFactory(dll, aCID, serviceMgr, _retval);
|
|
}
|
|
}
|
|
#endif
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("nsNativeComponentLoader: Factory creation %s for %s",
|
|
(NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"),
|
|
aLocation));
|
|
|
|
// If the dll failed to get us a factory. But the dll registered that
|
|
// it would be able to create a factory for this CID. mmh!
|
|
// We cannot just delete the dll as the dll could be hosting
|
|
// other CID for which factory creation can pass.
|
|
// We will just let it be. The effect will be next time we try
|
|
// creating the object, we will query the dll again. Since the
|
|
// dll is loaded, this aint a big hit. So for optimized builds
|
|
// this is ok to limp along.
|
|
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Factory creation failed");
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNativeComponentLoader::Init(nsIComponentManager *aCompMgr, nsISupports *aReg)
|
|
{
|
|
nsresult rv;
|
|
|
|
mCompMgr = aCompMgr;
|
|
mRegistry = do_QueryInterface(aReg);
|
|
if (!mCompMgr || !mRegistry)
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
rv = mRegistry->GetSubtree(nsIRegistry::Common, xpcomComponentsKeyName,
|
|
&mXPCOMKey);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (!mDllStore) {
|
|
mDllStore = new nsObjectHashtable(nsnull, nsnull, // never copy
|
|
nsDll_Destroy, nsnull,
|
|
256, /* Thead Safe */ PR_TRUE);
|
|
if (!mDllStore)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
|
|
// Read in all dll entries and populate the mDllStore
|
|
nsCOMPtr<nsIEnumerator> dllEnum;
|
|
rv = mRegistry->EnumerateSubtrees( mXPCOMKey, getter_AddRefs(dllEnum));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = dllEnum->First();
|
|
for (; NS_SUCCEEDED(rv) && (dllEnum->IsDone() != NS_OK); (rv = dllEnum->Next()))
|
|
{
|
|
nsCOMPtr<nsISupports> base;
|
|
rv = dllEnum->CurrentItem(getter_AddRefs(base));
|
|
if (NS_FAILED(rv)) continue;
|
|
|
|
// Get specific interface.
|
|
nsIID nodeIID = NS_IREGISTRYNODE_IID;
|
|
nsCOMPtr<nsIRegistryNode> node;
|
|
rv = base->QueryInterface( nodeIID, getter_AddRefs(node) );
|
|
if (NS_FAILED(rv)) continue;
|
|
|
|
// Get library name
|
|
nsXPIDLCString library;
|
|
rv = node->GetNameUTF8(getter_Copies(library));
|
|
|
|
if (NS_FAILED(rv)) continue;
|
|
|
|
char* uLibrary;
|
|
char* eLibrary = (char*)library.operator const char*();
|
|
PRUint32 length = strlen(eLibrary);
|
|
rv = mRegistry->UnescapeKey((PRUint8*)eLibrary, 1, &length, (PRUint8**)&uLibrary);
|
|
|
|
if (NS_FAILED(rv)) continue;
|
|
|
|
if (uLibrary == nsnull)
|
|
uLibrary = eLibrary;
|
|
|
|
// Get key associated with library
|
|
nsRegistryKey libKey;
|
|
rv = node->GetKey(&libKey);
|
|
if (NS_SUCCEEDED(rv)) // Cannot continue here, because we have to free unescape
|
|
{
|
|
// Create nsDll with this name
|
|
nsDll *dll = NULL;
|
|
PRInt64 lastModTime;
|
|
PRInt64 fileSize;
|
|
GetRegistryDllInfo(libKey, &lastModTime, &fileSize);
|
|
rv = CreateDll(NULL, uLibrary, &lastModTime, &fileSize, &dll);
|
|
}
|
|
if (uLibrary && (uLibrary != eLibrary))
|
|
nsMemory::Free(uLibrary);
|
|
|
|
if (NS_FAILED(rv)) continue;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNativeComponentLoader::AutoRegisterComponents(PRInt32 aWhen,
|
|
nsIFile *aDirectory)
|
|
{
|
|
#ifdef DEBUG
|
|
/* do we _really_ want to print this every time? */
|
|
printf("nsNativeComponentLoader: autoregistering begins.\n");
|
|
#endif
|
|
|
|
nsresult rv = RegisterComponentsInDir(aWhen, aDirectory);
|
|
|
|
#ifdef DEBUG
|
|
printf("nsNativeComponentLoader: autoregistering %s\n",
|
|
NS_FAILED(rv) ? "FAILED" : "succeeded");
|
|
#endif
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::RegisterComponentsInDir(PRInt32 when,
|
|
nsIFile *dir)
|
|
{
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
PRBool isDir = PR_FALSE;
|
|
|
|
#if 0
|
|
// Going to many of these checks is a performance hit on the mac.
|
|
// Since these routines are called relatively infrequently and
|
|
// we will fail anyway down the line if a directory aint there,
|
|
// we are commenting this check out.
|
|
|
|
// Make sure we are dealing with a directory
|
|
rv = dir->IsDirectory(&isDir);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (!isDir)
|
|
return NS_ERROR_INVALID_ARG;
|
|
#endif /* 0 */
|
|
|
|
// Create a directory iterator
|
|
nsCOMPtr<nsISimpleEnumerator> dirIterator;
|
|
rv = dir->GetDirectoryEntries(getter_AddRefs(dirIterator));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// whip through the directory to register every file
|
|
nsCOMPtr<nsIFile> dirEntry;
|
|
PRBool more = PR_FALSE;
|
|
|
|
rv = dirIterator->HasMoreElements(&more);
|
|
if (NS_FAILED(rv)) return rv;
|
|
while (more == PR_TRUE)
|
|
{
|
|
rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry));
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
rv = dirEntry->IsDirectory(&isDir);
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
if (isDir == PR_TRUE)
|
|
{
|
|
// This is a directory. Grovel for components into the directory.
|
|
rv = RegisterComponentsInDir(when, dirEntry);
|
|
}
|
|
else
|
|
{
|
|
PRBool registered;
|
|
// This is a file. Try to register it.
|
|
rv = AutoRegisterComponent(when, dirEntry, ®istered);
|
|
}
|
|
}
|
|
}
|
|
rv = dirIterator->HasMoreElements(&more);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
static nsresult PR_CALLBACK
|
|
nsFreeLibrary(nsDll *dll, nsIServiceManager *serviceMgr, PRInt32 when)
|
|
{
|
|
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);
|
|
|
|
PRBool canUnload = PR_FALSE;
|
|
|
|
// Get the module object
|
|
nsCOMPtr<nsIModule> mobj;
|
|
/* XXXshaver cheat and use the global component manager */
|
|
rv = dll->GetModule(NS_STATIC_CAST(nsIComponentManager*, nsComponentManagerImpl::gComponentManager),
|
|
getter_AddRefs(mobj));
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
rv = mobj->CanUnload(nsComponentManagerImpl::gComponentManager, &canUnload);
|
|
}
|
|
#ifndef OBSOLETE_MODULE_LOADING
|
|
else
|
|
{
|
|
// Try the old method of module unloading
|
|
nsCanUnloadProc proc = (nsCanUnloadProc)dll->FindSymbol("NSCanUnload");
|
|
if (proc)
|
|
{
|
|
canUnload = proc(serviceMgr);
|
|
rv = NS_OK; // No error status returned by call.
|
|
}
|
|
else
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("nsNativeComponentLoader: Unload cant get nsIModule or NSCanUnload for %s",
|
|
dll->GetDisplayPath()));
|
|
return rv;
|
|
}
|
|
}
|
|
#endif /* OBSOLETE_MODULE_LOADING */
|
|
|
|
mobj = nsnull; // Release our reference to the module object
|
|
|
|
// When shutting down, whether we can unload the dll or not,
|
|
// we will shutdown the dll to release any memory it has got
|
|
if (when == nsIComponentManagerObsolete::NS_Shutdown)
|
|
{
|
|
dll->Shutdown();
|
|
}
|
|
|
|
// Check error status on CanUnload() call
|
|
if (NS_FAILED(rv))
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("nsNativeComponentLoader: nsIModule::CanUnload() returned error for %s.",
|
|
dll->GetDisplayPath()));
|
|
return rv;
|
|
}
|
|
|
|
if (canUnload)
|
|
{
|
|
if (dllMarkedForUnload)
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
|
|
("nsNativeComponentLoader: + Unloading \"%s\".", dll->GetDisplayPath()));
|
|
#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_DEBUG,
|
|
("nsNativeComponentLoader: Ready for unload \"%s\".", dll->GetDisplayPath()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("nsNativeComponentLoader: NOT ready for unload %s", dll->GetDisplayPath()));
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
struct freeLibrariesClosure
|
|
{
|
|
nsIServiceManager *serviceMgr;
|
|
PRInt32 when;
|
|
};
|
|
|
|
static PRBool PR_CALLBACK
|
|
nsFreeLibraryEnum(nsHashKey *aKey, void *aData, void* closure)
|
|
{
|
|
nsDll *dll = (nsDll *) aData;
|
|
struct freeLibrariesClosure *callData = (struct freeLibrariesClosure *) closure;
|
|
nsFreeLibrary(dll,
|
|
(callData ? callData->serviceMgr : NULL),
|
|
(callData ? callData->when : nsIComponentManagerObsolete::NS_Timer));
|
|
return PR_TRUE;
|
|
}
|
|
|
|
/*
|
|
* SelfRegisterDll
|
|
*
|
|
* Given a dll abstraction, this will load, selfregister the dll and
|
|
* unload the dll.
|
|
*
|
|
*/
|
|
nsresult
|
|
nsNativeComponentLoader::SelfRegisterDll(nsDll *dll,
|
|
const char *registryLocation,
|
|
PRBool deferred)
|
|
{
|
|
// Precondition: dll is not loaded already, unless we're deferred
|
|
PR_ASSERT(deferred || dll->IsLoaded() == PR_FALSE);
|
|
|
|
nsresult res;
|
|
nsCOMPtr<nsIServiceManager> serviceMgr;
|
|
res = NS_GetServiceManager(getter_AddRefs(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);
|
|
|
|
DumpLoadError(dll, "SelfRegisterDll", errorMsg);
|
|
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
|
|
("nsNativeComponentLoader: Loaded \"%s\".", dll->GetDisplayPath()));
|
|
|
|
// Tell the module to self register
|
|
nsCOMPtr<nsIModule> mobj;
|
|
res = dll->GetModule(mCompMgr, getter_AddRefs(mobj));
|
|
if (NS_SUCCEEDED(res))
|
|
{
|
|
nsCOMPtr<nsIFile> fs;
|
|
/*************************************************************
|
|
* WARNING: Why are use introducing 'res2' here and then *
|
|
* later assigning it to 'res' rather than just using 'res'? *
|
|
* This is because this code turns up a code-generation bug *
|
|
* in VC6 on NT. Assigning to 'res' on the next line causes *
|
|
* the value of 'dll' to get nulled out! The two seem to be *
|
|
* getting aliased together during compilation. *
|
|
*************************************************************/
|
|
nsresult res2 = dll->GetDllSpec(getter_AddRefs(fs)); // don't change 'res2' -- see warning, above
|
|
if (NS_SUCCEEDED(res2)) {
|
|
res = mobj->RegisterSelf(mCompMgr, fs, registryLocation,
|
|
nativeComponentType);
|
|
}
|
|
else
|
|
{
|
|
res = res2; // don't take this out -- see warning, above
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("nsNativeComponentLoader: dll->GetDllSpec() on %s FAILED.",
|
|
dll->GetDisplayPath()));
|
|
}
|
|
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, registryLocation);
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("nsNativeComponentLoader: %s using OBSOLETE NSRegisterSelf()",
|
|
dll->GetDisplayPath()));
|
|
}
|
|
}
|
|
#endif /* OBSOLETE_MODULE_LOADING */
|
|
|
|
// Update the timestamp and size of the dll in registry
|
|
// Don't enter deferred modules in the registry, because it might only be
|
|
// able to register on some later autoreg, after another component has been
|
|
// installed.
|
|
if (res != NS_ERROR_FACTORY_REGISTER_AGAIN) {
|
|
dll->Sync();
|
|
|
|
PRInt64 modTime, size;
|
|
dll->GetLastModifiedTime(&modTime);
|
|
dll->GetSize(&size);
|
|
|
|
SetRegistryDllInfo(registryLocation, &modTime, &size);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
//
|
|
// MOZ_DEMANGLE_SYMBOLS is only a linux + MOZ_DEBUG thing.
|
|
//
|
|
|
|
#if defined(MOZ_DEMANGLE_SYMBOLS)
|
|
#include "nsTraceRefcnt.h" // for nsTraceRefcnt::DemangleSymbol()
|
|
#endif
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::DumpLoadError(nsDll *dll,
|
|
const char *aCallerName,
|
|
const char *aNsprErrorMsg)
|
|
{
|
|
PR_ASSERT(aCallerName != NULL);
|
|
|
|
if (nsnull == dll || nsnull == aNsprErrorMsg)
|
|
return NS_OK;
|
|
|
|
nsCAutoString errorMsg(aNsprErrorMsg);
|
|
|
|
#if defined(MOZ_DEMANGLE_SYMBOLS)
|
|
// Demangle undefined symbols
|
|
nsCAutoString undefinedMagicString("undefined symbol:");
|
|
|
|
PRInt32 offset = errorMsg.Find(undefinedMagicString, PR_TRUE);
|
|
|
|
if (offset != kNotFound)
|
|
{
|
|
nsCAutoString symbol(errorMsg);
|
|
nsCAutoString demangledSymbol;
|
|
|
|
symbol.Cut(0,offset);
|
|
|
|
symbol.Cut(0,undefinedMagicString.Length());
|
|
|
|
symbol.StripWhitespace();
|
|
|
|
char demangled[4096] = "\0";
|
|
|
|
nsTraceRefcnt::DemangleSymbol(symbol.get(),demangled,sizeof(demangled));
|
|
|
|
if (demangled && *demangled != '\0')
|
|
demangledSymbol = demangled;
|
|
|
|
if (!demangledSymbol.IsEmpty())
|
|
{
|
|
nsCAutoString tmp(errorMsg);
|
|
|
|
|
|
tmp.Cut(offset + undefinedMagicString.Length(),
|
|
tmp.Length() - offset - undefinedMagicString.Length());
|
|
|
|
tmp += " \n";
|
|
|
|
tmp += demangledSymbol;
|
|
|
|
errorMsg = tmp;
|
|
}
|
|
}
|
|
#endif // MOZ_DEMANGLE_SYMBOLS
|
|
|
|
// Do NSPR log
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("nsNativeComponentLoader: %s(%s) Load FAILED with error:%s",
|
|
aCallerName,
|
|
dll->GetDisplayPath(),
|
|
errorMsg.get()));
|
|
|
|
|
|
// Dump to screen if needed
|
|
#ifdef PRINT_CRITICAL_ERROR_TO_SCREEN
|
|
printf("**************************************************\n"
|
|
"nsNativeComponentLoader: %s(%s) Load FAILED with error: %s\n"
|
|
"**************************************************\n",
|
|
aCallerName,
|
|
dll->GetDisplayPath(),
|
|
errorMsg.get());
|
|
#endif
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::SelfUnregisterDll(nsDll *dll)
|
|
{
|
|
nsresult res;
|
|
nsCOMPtr<nsIServiceManager> serviceMgr;
|
|
res = NS_GetServiceManager(getter_AddRefs(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<nsIModule> mobj;
|
|
res = dll->GetModule(mCompMgr, getter_AddRefs(mobj));
|
|
if (NS_SUCCEEDED(res))
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("nsNativeComponentLoader: %s using nsIModule to unregister self.", dll->GetDisplayPath()));
|
|
nsCOMPtr<nsIFile> fs;
|
|
res = dll->GetDllSpec(getter_AddRefs(fs));
|
|
if (NS_FAILED(res)) return res;
|
|
// Get registry location for spec
|
|
nsXPIDLCString registryName;
|
|
|
|
// what I want to do here is QI for a Component Registration Manager. Since this
|
|
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
|
|
nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &res);
|
|
if (obsoleteManager)
|
|
res = obsoleteManager->RegistryLocationForSpec(fs, getter_Copies(registryName));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
mobj->UnregisterSelf(mCompMgr, fs, registryName);
|
|
}
|
|
#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 */
|
|
return res;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::AutoUnregisterComponent(PRInt32 when,
|
|
nsIFile *component,
|
|
PRBool *unregistered)
|
|
{
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
nsXPIDLCString persistentDescriptor;
|
|
// what I want to do here is QI for a Component Registration Manager. Since this
|
|
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
|
|
nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
|
|
if (obsoleteManager)
|
|
rv = obsoleteManager->RegistryLocationForSpec(component,
|
|
getter_Copies(persistentDescriptor));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Notify observers, if any, of autoregistration work
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
do_GetService("@mozilla.org/observer-service;1", &rv);
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
nsCOMPtr<nsIServiceManager> mgr;
|
|
rv = NS_GetServiceManager(getter_AddRefs(mgr));
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
(void) observerService->NotifyObservers(mgr,
|
|
NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
|
|
NS_LITERAL_STRING("Unregistering native component").get());
|
|
}
|
|
}
|
|
|
|
nsDll *dll = NULL;
|
|
PRInt64 mod = LL_Zero(), size = LL_Zero();
|
|
rv = CreateDll(component, persistentDescriptor, &mod, &size, &dll);
|
|
if (NS_FAILED(rv) || dll == NULL) return rv;
|
|
|
|
rv = SelfUnregisterDll(dll);
|
|
|
|
// Remove any autoreg info about this dll
|
|
if (NS_SUCCEEDED(rv))
|
|
RemoveRegistryDllInfo(persistentDescriptor);
|
|
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("nsNativeComponentLoader: AutoUnregistration for %s %s.",
|
|
(NS_FAILED(rv) ? "FAILED" : "succeeded"), dll->GetDisplayPath()));
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::AutoRegisterComponent(PRInt32 when,
|
|
nsIFile *component,
|
|
PRBool *registered)
|
|
{
|
|
nsresult rv;
|
|
if (!registered)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
/* this should be a pref or registry entry, or something */
|
|
static const char *ValidDllExtensions[] = {
|
|
".dll", /* Windows */
|
|
".so", /* Unix */
|
|
".shlb", /* Mac ? */
|
|
".dso", /* Unix ? */
|
|
".dylib", /* Unix: Mach */
|
|
".so.1.0", /* Unix: BSD */
|
|
".sl", /* Unix: HP-UX */
|
|
#if defined(VMS)
|
|
".exe", /* Open VMS */
|
|
#endif
|
|
".dlm", /* new for all platforms */
|
|
NULL
|
|
};
|
|
|
|
*registered = PR_FALSE;
|
|
|
|
#if 0
|
|
// This is a performance hit on mac. Since we have already checked
|
|
// this; plus is we dont, load will fail anyway later on, this
|
|
// is being commented out.
|
|
|
|
// Ensure we are dealing with a file as opposed to a dir
|
|
PRBool b = PR_FALSE;
|
|
|
|
rv = component->IsFile(&b);
|
|
if (NS_FAILED(rv) || !b)
|
|
return rv;
|
|
#endif /* 0 */
|
|
|
|
// deal only with files that have a valid extension
|
|
PRBool validExtension = PR_FALSE;
|
|
|
|
#if defined(XP_MAC) // sdagley dougt fix
|
|
// rjc - on Mac, check the file's type code (skip checking the creator code)
|
|
|
|
nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(component);
|
|
if (localFileMac)
|
|
{
|
|
OSType type, creator;
|
|
rv = localFileMac->GetFileTypeAndCreator(&type, &creator);
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
// 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!
|
|
validExtension = ((type == 'shlb') || (type == 'NSPL'));
|
|
}
|
|
}
|
|
|
|
#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) nsMemory::Free(leafName);
|
|
#endif
|
|
|
|
if (validExtension == PR_FALSE)
|
|
// Skip invalid extensions
|
|
return NS_OK;
|
|
|
|
nsXPIDLCString persistentDescriptor;
|
|
// what I want to do here is QI for a Component Registration Manager. Since this
|
|
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
|
|
nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
|
|
if (obsoleteManager)
|
|
rv = obsoleteManager->RegistryLocationForSpec(component,
|
|
getter_Copies(persistentDescriptor));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
nsCStringKey key(persistentDescriptor);
|
|
|
|
// Get the registry representation of the dll, if any
|
|
nsDll *dll;
|
|
PRInt64 mod = LL_Zero(), size = LL_Zero();
|
|
rv = CreateDll(component, persistentDescriptor, &mod, &size, &dll);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (dll != NULL)
|
|
{
|
|
// Make sure the dll is OK
|
|
if (dll->GetStatus() != NS_OK)
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("nsNativeComponentLoader: + nsDll not NS_OK \"%s\". Skipping...",
|
|
dll->GetDisplayPath()));
|
|
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,
|
|
("nsNativeComponentLoader: + nsDll not changed \"%s\". Skipping...",
|
|
dll->GetDisplayPath()));
|
|
return NS_OK;
|
|
}
|
|
|
|
// Aagh! the dll has changed since the last time we saw it.
|
|
// re-register dll
|
|
|
|
|
|
// Notify observers, if any, of autoregistration work
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
do_GetService("@mozilla.org/observer-service;1", &rv);
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
nsCOMPtr<nsIServiceManager> mgr;
|
|
rv = NS_GetServiceManager(getter_AddRefs(mgr));
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
// this string can't come from a string bundle, because we
|
|
// don't have string bundles yet.
|
|
NS_ConvertASCIItoUCS2 fileName("(no name)");
|
|
|
|
// get the file name
|
|
nsCOMPtr<nsIFile> dllSpec;
|
|
if (NS_SUCCEEDED(dll->GetDllSpec(getter_AddRefs(dllSpec))) && dllSpec)
|
|
{
|
|
nsXPIDLCString dllLeafName;
|
|
dllSpec->GetLeafName(getter_Copies(dllLeafName));
|
|
fileName.AssignWithConversion(dllLeafName);
|
|
}
|
|
|
|
// this string can't come from a string bundle, because we
|
|
// don't have string bundles yet.
|
|
(void) observerService->
|
|
NotifyObservers(mgr,
|
|
NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
|
|
PromiseFlatString(NS_LITERAL_STRING("Registering native component ") +
|
|
fileName).get());
|
|
}
|
|
}
|
|
|
|
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.
|
|
nsCOMPtr<nsIServiceManager> serviceMgr;
|
|
rv = NS_GetServiceManager(getter_AddRefs(serviceMgr));
|
|
|
|
rv = nsFreeLibrary(dll, serviceMgr, when);
|
|
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,
|
|
("nsNativeComponentLoader: *** Dll already loaded. "
|
|
"Cannot unload either. Hence cannot re-register "
|
|
"\"%s\". Skipping...", dll->GetDisplayPath()));
|
|
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,
|
|
("nsNativeComponentLoader: + Unloading \"%s\". (no CanUnloadProc).",
|
|
dll->GetDisplayPath()));
|
|
}
|
|
|
|
} // 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,
|
|
("nsNativeComponentLoader: Dll still loaded. Cannot re-register "
|
|
"\"%s\". Skipping...", dll->GetDisplayPath()));
|
|
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, persistentDescriptor, PR_FALSE);
|
|
if (NS_FAILED(res))
|
|
{
|
|
if (res == NS_ERROR_FACTORY_REGISTER_AGAIN) {
|
|
/* defer for later loading */
|
|
mDeferredComponents.AppendElement(dll);
|
|
return NS_OK;
|
|
} else {
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("nsNativeComponentLoader: Autoregistration FAILED for "
|
|
"\"%s\". Skipping...", dll->GetDisplayPath()));
|
|
return NS_ERROR_FACTORY_NOT_REGISTERED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("nsNativeComponentLoader: Autoregistration Passed for "
|
|
"\"%s\".", dll->GetDisplayPath()));
|
|
// Marking dll along with modified time and size in the
|
|
// registry happens at PlatformRegister(). No need to do it
|
|
// here again.
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::RegisterDeferredComponents(PRInt32 aWhen,
|
|
PRBool *aRegistered)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "nNCL: registering deferred (%d)\n",
|
|
mDeferredComponents.Count());
|
|
#endif
|
|
*aRegistered = PR_FALSE;
|
|
if (!mDeferredComponents.Count())
|
|
return NS_OK;
|
|
|
|
for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) {
|
|
nsDll *dll = NS_STATIC_CAST(nsDll *, mDeferredComponents[i]);
|
|
nsresult rv = SelfRegisterDll(dll,
|
|
dll->GetRegistryLocation(),
|
|
PR_TRUE);
|
|
if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) {
|
|
if (NS_SUCCEEDED(rv))
|
|
*aRegistered = PR_TRUE;
|
|
mDeferredComponents.RemoveElementAt(i);
|
|
}
|
|
}
|
|
|
|
if (*aRegistered)
|
|
fprintf(stderr, "nNCL: registered deferred, %d left\n",
|
|
mDeferredComponents.Count());
|
|
else
|
|
fprintf(stderr, "nNCL: didn't register any components, %d left\n",
|
|
mDeferredComponents.Count());
|
|
/* are there any fatal errors? */
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::OnRegister(const nsIID &aCID, const char *aType,
|
|
const char *aClassName,
|
|
const char *aContractID, const char *aLocation,
|
|
PRBool aReplace, PRBool aPersist)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::UnloadAll(PRInt32 aWhen)
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsNativeComponentLoader: Unloading...."));
|
|
|
|
struct freeLibrariesClosure callData;
|
|
callData.serviceMgr = NULL; // XXX need to get this as a parameter
|
|
callData.when = aWhen;
|
|
|
|
// Cycle through the dlls checking to see if they want to be unloaded
|
|
if (mDllStore) {
|
|
mDllStore->Enumerate(nsFreeLibraryEnum, &callData);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::GetRegistryDllInfo(const char *aLocation,
|
|
PRInt64 *lastModifiedTime,
|
|
PRInt64 *fileSize)
|
|
{
|
|
nsresult rv;
|
|
PRUint32 length = strlen(aLocation);
|
|
char* eLocation;
|
|
rv = mRegistry->EscapeKey((PRUint8*)aLocation, 1, &length, (PRUint8**)&eLocation);
|
|
if (rv != NS_OK)
|
|
{
|
|
return rv;
|
|
}
|
|
if (eLocation == nsnull) // No escaping required
|
|
eLocation = (char*)aLocation;
|
|
|
|
|
|
nsRegistryKey key;
|
|
rv = mRegistry->GetSubtreeRaw(mXPCOMKey, eLocation, &key);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = GetRegistryDllInfo(key, lastModifiedTime, fileSize);
|
|
if (aLocation != eLocation)
|
|
nsMemory::Free(eLocation);
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::GetRegistryDllInfo(nsRegistryKey key,
|
|
PRInt64 *lastModifiedTime,
|
|
PRInt64 *fileSize)
|
|
{
|
|
PRInt64 lastMod;
|
|
nsresult rv = mRegistry->GetLongLong(key, lastModValueName, &lastMod);
|
|
if (NS_FAILED(rv)) return rv;
|
|
*lastModifiedTime = lastMod;
|
|
|
|
PRInt64 fsize;
|
|
rv = mRegistry->GetLongLong(key, fileSizeValueName, &fsize);
|
|
if (NS_FAILED(rv)) return rv;
|
|
*fileSize = fsize;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::SetRegistryDllInfo(const char *aLocation,
|
|
PRInt64 *lastModifiedTime,
|
|
PRInt64 *fileSize)
|
|
{
|
|
nsresult rv;
|
|
PRUint32 length = strlen(aLocation);
|
|
char* eLocation;
|
|
rv = mRegistry->EscapeKey((PRUint8*)aLocation, 1, &length, (PRUint8**)&eLocation);
|
|
if (rv != NS_OK)
|
|
{
|
|
return rv;
|
|
}
|
|
if (eLocation == nsnull) // No escaping required
|
|
eLocation = (char*)aLocation;
|
|
|
|
nsRegistryKey key;
|
|
rv = mRegistry->GetSubtreeRaw(mXPCOMKey, eLocation, &key);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = mRegistry->SetLongLong(key, lastModValueName, lastModifiedTime);
|
|
if (NS_FAILED(rv)) return rv;
|
|
rv = mRegistry->SetLongLong(key, fileSizeValueName, fileSize);
|
|
if (aLocation != eLocation)
|
|
nsMemory::Free(eLocation);
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::RemoveRegistryDllInfo(const char *aLocation)
|
|
{
|
|
nsresult rv;
|
|
PRUint32 length = strlen(aLocation);
|
|
char* eLocation;
|
|
rv = mRegistry->EscapeKey((PRUint8*)aLocation, 1, &length, (PRUint8**)&eLocation);
|
|
if (rv != NS_OK)
|
|
{
|
|
return rv;
|
|
}
|
|
if (eLocation == nsnull) // No escaping required
|
|
eLocation = (char*)aLocation;
|
|
|
|
rv = mRegistry->RemoveSubtree(mXPCOMKey, eLocation);
|
|
if (aLocation != eLocation)
|
|
nsMemory::Free(eLocation);
|
|
return rv;
|
|
}
|
|
|
|
//
|
|
// CreateDll
|
|
// The only way to create a dll or get it from the dll cache. This will
|
|
// be called in multiple situations:
|
|
//
|
|
// 1. Autoregister will create one for each dll it is trying to register. This
|
|
// call will be passing a spec in.
|
|
// {spec, NULL, 0, 0}
|
|
//
|
|
// 2. GetFactory() This will call CreateDll() with a null spec but will give
|
|
// the registry represented name of the dll. If modtime and size are zero,
|
|
// we will go the registry to find the right modtime and size.
|
|
// {NULL, rel:libpref.so, 0, 0}
|
|
//
|
|
// 3. Prepopulation of dllCache A dll object created off a registry entry.
|
|
// Specifically dll name is stored in rel: or abs: or lib: formats in the
|
|
// registry along with its lastModTime and fileSize.
|
|
// {NULL, rel:libpref.so, 8985659, 20987}
|
|
nsresult
|
|
nsNativeComponentLoader::CreateDll(nsIFile *aSpec, const char *aLocation,
|
|
PRInt64 *modificationTime, PRInt64 *fileSize,
|
|
nsDll **aDll)
|
|
{
|
|
nsDll *dll;
|
|
nsCOMPtr<nsIFile> dllSpec;
|
|
nsCOMPtr<nsIFile> spec;
|
|
nsresult rv;
|
|
|
|
nsCStringKey key(aLocation);
|
|
dll = (nsDll *)mDllStore->Get(&key);
|
|
if (dll)
|
|
{
|
|
*aDll = dll;
|
|
return NS_OK;
|
|
}
|
|
|
|
if (!aSpec)
|
|
{
|
|
if (!nsCRT::strncmp(aLocation, XPCOM_LIB_PREFIX, 4)) {
|
|
dll = new nsDll(aLocation+4, 1 /* dumb magic flag */);
|
|
if (!dll) return NS_ERROR_OUT_OF_MEMORY;
|
|
} else {
|
|
// what I want to do here is QI for a Component Registration Manager. Since this
|
|
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
|
|
nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
|
|
if (obsoleteManager)
|
|
rv = obsoleteManager->SpecForRegistryLocation(aLocation,
|
|
getter_AddRefs(spec));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spec = aSpec;
|
|
}
|
|
|
|
if (!dll)
|
|
{
|
|
PR_ASSERT(modificationTime != NULL);
|
|
PR_ASSERT(fileSize != NULL);
|
|
|
|
PRInt64 zit = LL_Zero();
|
|
|
|
if (LL_EQ(*modificationTime,zit) && LL_EQ(*fileSize,zit))
|
|
{
|
|
// Get the modtime and filesize from the registry
|
|
rv = GetRegistryDllInfo(aLocation, modificationTime, fileSize);
|
|
}
|
|
dll = new nsDll(spec, aLocation, modificationTime, fileSize);
|
|
}
|
|
|
|
if (!dll)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
*aDll = dll;
|
|
mDllStore->Put(&key, dll);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::GetFactoryFromModule(nsDll *aDll, const nsCID &aCID,
|
|
nsIFactory **aFactory)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIModule> module;
|
|
rv = aDll->GetModule(mCompMgr, getter_AddRefs(module));
|
|
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
return module->GetClassObject(mCompMgr, aCID, NS_GET_IID(nsIFactory),
|
|
(void **)aFactory);
|
|
}
|
|
|
|
nsresult
|
|
nsNativeComponentLoader::GetFactoryFromNSGetFactory(nsDll *aDll,
|
|
const nsCID &aCID,
|
|
nsIServiceManager *aServMgr,
|
|
nsIFactory **aFactory)
|
|
{
|
|
#ifdef XPCOM_USE_NSGETFACTORY
|
|
nsFactoryProc getFactory =
|
|
(nsFactoryProc) aDll->FindSymbol("NSGetFactory");
|
|
|
|
if (!getFactory)
|
|
return NS_ERROR_FACTORY_NOT_LOADED;
|
|
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
|
|
("nsNativeComponentLoader: %s using OBSOLETE NSGetFactory()\n",
|
|
aDll->GetDisplayPath()));
|
|
|
|
/*
|
|
* There was a time when CLSIDToContractID was used to get className
|
|
* and contractID, but that day is long past. This code is not long
|
|
* for this earth, so we just pass nsnull.
|
|
*/
|
|
|
|
return getFactory(aServMgr, aCID, nsnull /*className */,
|
|
nsnull /* contractID */, aFactory);
|
|
|
|
#else /* !XPCOM_USE_NSGETFACTORY */
|
|
return NS_ERROR_FACTORY_NOT_LOADED;
|
|
#endif /* XPCOM_USE_NSGETFACTORY */
|
|
}
|