pjs/xpcom/components/nsComponentManager.cpp

3434 строки
106 KiB
C++
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* 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
*/
1999-06-22 18:02:58 +04:00
#include <stdlib.h>
#include "nscore.h"
#include "nsISupports.h"
// this after nsISupports, to pick up IID
// so that xpt stuff doesn't try to define it itself...
#include "xptinfo.h"
#include "nsIInterfaceInfoManager.h"
1999-06-22 18:02:58 +04:00
#include "nsCOMPtr.h"
#include "nsComponentManager.h"
#include "nsIServiceManager.h"
#include "nsICategoryManager.h"
1999-07-02 07:35:09 +04:00
#include "nsCRT.h"
#include "nsIEnumerator.h"
1999-08-09 09:40:51 +04:00
#include "nsIModule.h"
#include "nsHashtableEnumerator.h"
#include "nsISupportsPrimitives.h"
#include "nsIComponentLoader.h"
#include "nsNativeComponentLoader.h"
#include "nsXPIDLString.h"
#include "nsIObserverService.h"
2000-01-25 00:28:28 +03:00
#include "nsILocalFile.h"
#include "nsLocalFile.h"
#include "nsDirectoryService.h"
#include "nsDirectoryServiceDefs.h"
2000-01-25 00:28:28 +03:00
#include "plstr.h"
#include "prlink.h"
#include "prsystem.h"
#include "prprf.h"
#include "xcDll.h"
#include "prerror.h"
#include "prmem.h"
#include "nsIFile.h"
//#include "mozreg.h"
#include "NSReg.h"
#include "prcmon.h"
#include "prthread.h" /* XXX: only used for the NSPR initialization hack (rick) */
1999-06-29 14:27:58 +04:00
#ifdef XP_BEOS
#include <FindDirectory.h>
#include <Path.h>
#endif
#include "nsRegistry.h"
// Logging of debug output
#ifdef MOZ_LOGGING
1999-06-29 01:51:46 +04:00
#define FORCE_PR_LOG /* Allow logging in the release build */
#endif
#include "prlog.h"
PRLogModuleInfo* nsComponentManagerLog = NULL;
#include "nsAutoLock.h"
// Enable printing of critical errors on screen even for release builds
#define PRINT_CRITICAL_ERROR_TO_SCREEN
// Loader Types
#define NS_LOADER_DATA_ALLOC_STEP 6
// Common Key Names
2000-02-16 10:45:20 +03:00
const char xpcomKeyName[]="software/mozilla/XPCOM";
const char classesKeyName[]="contractID";
const char classIDKeyName[]="classID";
2000-02-16 10:45:20 +03:00
const char componentsKeyName[]="components";
const char componentLoadersKeyName[]="componentLoaders";
const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components";
// Common Value Names
const char classIDValueName[]="ClassID";
const char versionValueName[]="VersionString";
const char lastModValueName[]="LastModTimeStamp";
const char fileSizeValueName[]="FileSize";
const char componentCountValueName[]="ComponentsCount";
const char contractIDValueName[]="ContractID";
const char classNameValueName[]="ClassName";
const char inprocServerValueName[]="InprocServer";
const char componentTypeValueName[]="ComponentType";
const char nativeComponentType[]="application/x-mozilla-native";
const char staticComponentType[]="application/x-mozilla-static";
const static char XPCOM_ABSCOMPONENT_PREFIX[] = "abs:";
const static char XPCOM_RELCOMPONENT_PREFIX[] = "rel:";
const char XPCOM_LIB_PREFIX[] = "lib:";
// Nonexistent factory entry
// This is used to mark non-existent contractid mappings
static nsFactoryEntry * kNonExistentContractID = (nsFactoryEntry*) 1;
#define NS_EMPTY_IID \
{ \
0x00000000, \
0x0000, \
0x0000, \
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \
}
NS_DEFINE_CID(kEmptyCID, NS_EMPTY_IID);
nsIServiceManager* gServiceManager = NULL;
PRBool gShuttingDown = PR_FALSE;
// Build is using USE_NSREG to turn off xpcom using registry
// but internally we use USE_REGISTRY. Map them propertly.
#ifdef USE_NSREG
#define USE_REGISTRY
#endif /* USE_NSREG */
nsresult
nsCreateInstanceByCID::operator()( const nsIID& aIID, void** aInstancePtr ) const
{
nsresult status = nsComponentManager::CreateInstance(mCID, mOuter, aIID, aInstancePtr);
if ( !NS_SUCCEEDED(status) )
*aInstancePtr = 0;
if ( mErrorPtr )
*mErrorPtr = status;
return status;
}
nsresult
nsCreateInstanceByContractID::operator()( const nsIID& aIID, void** aInstancePtr ) const
{
nsresult status;
if ( mContractID )
{
if ( !NS_SUCCEEDED(status = nsComponentManager::CreateInstance(mContractID, mOuter, aIID, aInstancePtr)) )
*aInstancePtr = 0;
}
else
status = NS_ERROR_NULL_POINTER;
if ( mErrorPtr )
*mErrorPtr = status;
return status;
}
nsresult
nsCreateInstanceFromCategory::operator()( const nsIID& aIID,
void** aInstancePtr ) const
{
/*
* If I were a real man, I would consolidate this with
* nsGetServiceFromContractID::operator().
*/
nsresult status;
nsXPIDLCString value;
nsCOMPtr<nsICategoryManager> catman =
do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &status);
if (NS_FAILED(status)) goto error;
if (!mCategory || !mEntry) {
// when categories have defaults, use that for null mEntry
status = NS_ERROR_NULL_POINTER;
goto error;
}
/* find the contractID for category.entry */
status = catman->GetCategoryEntry(mCategory, mEntry,
getter_Copies(value));
if (NS_FAILED(status)) goto error;
if (!value) {
status = NS_ERROR_SERVICE_NOT_FOUND;
goto error;
}
status = nsComponentManager::CreateInstance(value, mOuter, aIID,
aInstancePtr);
error:
if (NS_FAILED(status)) {
*aInstancePtr = 0;
}
*mErrorPtr = status;
return status;
}
nsresult
nsGetServiceByCID::operator()( const nsIID& aIID, void** aInstancePtr ) const
{
nsresult status;
// Too bad |nsServiceManager| isn't an |nsIServiceManager|, then this could have been one call
if ( mServiceManager )
status = mServiceManager->GetService(mCID, aIID, NS_REINTERPRET_CAST(nsISupports**, aInstancePtr), 0);
else
status = nsServiceManager::GetService(mCID, aIID, NS_REINTERPRET_CAST(nsISupports**, aInstancePtr), 0);
if ( !NS_SUCCEEDED(status) )
*aInstancePtr = 0;
if ( mErrorPtr )
*mErrorPtr = status;
return status;
}
nsresult
nsGetServiceByContractID::operator()( const nsIID& aIID, void** aInstancePtr ) const
{
nsresult status;
if ( mContractID )
{
// Too bad |nsServiceManager| isn't an |nsIServiceManager|, then this could have been one call
if ( mServiceManager )
status = mServiceManager->GetService(mContractID, aIID, NS_REINTERPRET_CAST(nsISupports**, aInstancePtr), 0);
else
status = nsServiceManager::GetService(mContractID, aIID, NS_REINTERPRET_CAST(nsISupports**, aInstancePtr), 0);
if ( !NS_SUCCEEDED(status) )
*aInstancePtr = 0;
}
else
status = NS_ERROR_NULL_POINTER;
if ( mErrorPtr )
*mErrorPtr = status;
return status;
}
nsresult
nsGetServiceFromCategory::operator()( const nsIID& aIID, void** aInstancePtr)
const
{
nsresult status;
nsXPIDLCString value;
nsCOMPtr<nsICategoryManager> catman =
do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &status);
if (NS_FAILED(status)) goto error;
if (!mCategory || !mEntry) {
// when categories have defaults, use that for null mEntry
status = NS_ERROR_NULL_POINTER;
goto error;
}
/* find the contractID for category.entry */
status = catman->GetCategoryEntry(mCategory, mEntry,
getter_Copies(value));
if (NS_FAILED(status)) goto error;
if (!value) {
status = NS_ERROR_SERVICE_NOT_FOUND;
goto error;
}
// Too bad |nsServiceManager| isn't an |nsIServiceManager|, then
// this could have been one call.
if ( mServiceManager )
status =
mServiceManager->GetService(value, aIID,
NS_REINTERPRET_CAST(nsISupports**,
aInstancePtr), 0);
else
status =
nsServiceManager::GetService(value, aIID,
NS_REINTERPRET_CAST(nsISupports**,
aInstancePtr), 0);
if (NS_FAILED(status)) {
error:
*aInstancePtr = 0;
}
*mErrorPtr = status;
return status;
}
/*
* CreateServicesFromCategory()
*
* Given a category, this convenience functions enumerates the category and
* creates a service of every CID or ContractID registered under the category.
* If observerTopic is non null and the service implements nsIObserver,
* this will attempt to notify the observer with the origin, observerTopic string
* as parameter.
*/
nsresult
NS_CreateServicesFromCategory(const char *category,
nsISupports *origin,
const PRUnichar *observerTopic)
{
nsresult rv = NS_OK;
int nFailed = 0;
nsCOMPtr<nsICategoryManager> categoryManager =
do_GetService("@mozilla.org/categorymanager;1", &rv);
if (!categoryManager) return rv;
nsCOMPtr<nsISimpleEnumerator> enumerator;
rv = categoryManager->EnumerateCategory(category,
getter_AddRefs(enumerator));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISupports> entry;
while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) {
// From here on just skip any error we get.
nsCOMPtr<nsISupportsString> catEntry = do_QueryInterface(entry, &rv);
if (NS_FAILED(rv)) {
nFailed++;
continue;
}
nsXPIDLCString entryString;
rv = catEntry->GetData(getter_Copies(entryString));
if (NS_FAILED(rv)) {
nFailed++;
continue;
}
nsXPIDLCString contractID;
rv = categoryManager->GetCategoryEntry(category,(const char *)entryString, getter_Copies(contractID));
if (NS_FAILED(rv)) {
nFailed++;
continue;
}
nsCOMPtr<nsISupports> instance = do_GetService(contractID, &rv);
if (NS_FAILED(rv)) {
nFailed++;
continue;
}
if (observerTopic) {
// try an observer, if it implements it.
nsCOMPtr<nsIObserver> observer = do_QueryInterface(instance, &rv);
if (NS_SUCCEEDED(rv) && observer)
observer->Observe(origin, observerTopic, NS_LITERAL_STRING("").get());
}
}
return (nFailed ? NS_ERROR_FAILURE : NS_OK);
}
// Get a service with control to not create it
// The right way to do this is to add this into the nsIServiceManager
// api. Changing the api however will break a whole bunch of modules -
// plugins and other embedding clients. So until we figure out how to
// make new apis and maintain backward compabitility etc, we are adding
// this api.
//
// WARNING: USE AT YOUR OWN RISK. THIS FUNCTION WILL NOT BE SUPPORTED
// IN FUTURE RELEASES.
NS_COM nsresult
NS_GetService(const char *aContractID, const nsIID& aIID, PRBool aDontCreate, nsISupports** result)
{
if (!aDontCreate) {
// This is the same as the old get service.
return nsServiceManager::GetService(aContractID, aIID, result, nsnull);
}
nsComponentManagerImpl* mgr;
nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager **)&mgr);
if (NS_FAILED(rv))
return rv;
return mgr->FetchService(aContractID, aIID, result);
}
nsresult
nsComponentManagerImpl::FetchService(const char *aContractID, const nsIID& aIID, nsISupports** result)
{
// Now we want to get the service if we already got it. If not, we dont want
// to create an instance of it. mmh!
// test this first, since there's no point in returning a service during
// shutdown -- whether it's available or not would depend on the order it
// occurs in the list
if (gShuttingDown) {
// When processing shutdown, dont process new GetService() requests
NS_WARNING("Creating new service on shutdown. Denied.");
return NS_ERROR_UNEXPECTED;
}
nsresult rv = NS_ERROR_SERVICE_NOT_FOUND;
nsCStringKey key(aContractID);
nsFactoryEntry *entry = (nsFactoryEntry *) mContractIDs->Get(&key);
nsServiceEntry* serviceEntry;
if (entry && entry != kNonExistentContractID && entry->mServiceEntry) {
serviceEntry = entry->mServiceEntry;
if (!serviceEntry->mObject)
return NS_ERROR_NULL_POINTER;
nsISupports* service; // keep as raw point (avoid extra addref/release)
rv = serviceEntry->mObject->QueryInterface(aIID, (void**)&service);
*result = service;
// If someone else requested the service to be shut down,
// and we just asked to get it again before it could be
// released, then cancel their shutdown request:
if (serviceEntry->mShuttingDown) {
serviceEntry->mShuttingDown = PR_FALSE;
NS_ADDREF(service); // Released in UnregisterService
}
}
return rv;
}
/* prototypes for the Mac */
PRBool PR_CALLBACK
nsFactoryEntry_Destroy(nsHashKey *aKey, void *aData, void* closure);
nsServiceEntry::nsServiceEntry(nsISupports* service, nsFactoryEntry* factEntry)
: mObject(service),
mListeners(NULL),
mShuttingDown(PR_FALSE),
mFactoryEntry(factEntry)
{
NS_ASSERTION(mObject, "Service Entry initialized with null service");
NS_IF_ADDREF(mObject);
}
nsServiceEntry::~nsServiceEntry()
{
NotifyListeners();
//special case the nsComponentManagerImpl.
// XXX review-notes we need to see why we need to do this
if ((void*)mObject != (void*)nsComponentManagerImpl::gComponentManager)
NS_IF_RELEASE(mObject);
}
nsresult
nsServiceEntry::AddListener(nsIShutdownListener* listener)
{
if (listener == NULL)
return NS_OK;
if (mListeners == NULL) {
mListeners = new nsVoidArray();
if (mListeners == NULL)
return NS_ERROR_OUT_OF_MEMORY;
}
PRInt32 rv = mListeners->AppendElement(listener);
NS_ADDREF(listener);
return rv == -1 ? NS_ERROR_FAILURE : NS_OK;
}
nsresult
nsServiceEntry::RemoveListener(nsIShutdownListener* listener)
{
if (listener == NULL)
return NS_OK;
NS_ASSERTION(mListeners, "no listeners added yet");
if ( mListeners->RemoveElement(listener) )
return NS_OK;
NS_ASSERTION(0, "unregistered shutdown listener");
return NS_ERROR_FAILURE;
}
nsresult
nsServiceEntry::NotifyListeners(void)
{
if (mListeners && mFactoryEntry) {
PRUint32 size = mListeners->Count();
for (PRUint32 i = 0; i < size; i++) {
nsIShutdownListener* listener = (nsIShutdownListener*)(*mListeners)[0];
nsresult rv = listener->OnShutdown(mFactoryEntry->cid,
mObject);
if (NS_FAILED(rv)) return rv;
NS_RELEASE(listener);
mListeners->RemoveElementAt(0);
}
NS_ASSERTION(mListeners->Count() == 0, "failed to notify all listeners");
delete mListeners;
mListeners = NULL;
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsFactoryEntry
////////////////////////////////////////////////////////////////////////////////
MOZ_DECL_CTOR_COUNTER(nsFactoryEntry)
nsFactoryEntry::nsFactoryEntry(const nsCID &aClass,
const char *aLocation,
int aType)
: cid(aClass), location(aLocation), mServiceEntry(nsnull), typeIndex(aType)
{
MOZ_COUNT_CTOR(nsFactoryEntry);
}
nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, nsIFactory *aFactory)
: cid(aClass), mServiceEntry(nsnull), typeIndex(NS_COMPONENT_TYPE_FACTORY_ONLY)
{
MOZ_COUNT_CTOR(nsFactoryEntry);
factory = aFactory;
}
nsFactoryEntry::~nsFactoryEntry(void)
{
MOZ_COUNT_DTOR(nsFactoryEntry);
factory = 0;
}
nsresult
nsFactoryEntry::ReInit(const nsCID &aClass, const char *aLocation, int aType)
{
NS_ENSURE_TRUE(typeIndex != NS_COMPONENT_TYPE_FACTORY_ONLY, NS_ERROR_INVALID_ARG);
// cid has to match
// SERVICE_ONLY entries can be promoted to an entry of another type
NS_ENSURE_TRUE((typeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY || cid.Equals(aClass)),
NS_ERROR_INVALID_ARG);
location = aLocation;
typeIndex = aType;
return NS_OK;
}
nsresult
nsFactoryEntry::ReInit(const nsCID &aClass, nsIFactory *aFactory)
{
// cids has to match
// SERVICE_ONLY entries can be promoted to an entry of another type
NS_ENSURE_TRUE((typeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY || cid.Equals(aClass)),
NS_ERROR_INVALID_ARG);
// We are going to let native component be overridden by a factory.
factory = aFactory;
typeIndex = NS_COMPONENT_TYPE_FACTORY_ONLY;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsComponentManagerImpl
////////////////////////////////////////////////////////////////////////////////
nsComponentManagerImpl::nsComponentManagerImpl()
: mFactories(NULL), mContractIDs(NULL), mMon(NULL),
mRegistry(NULL), mPrePopulationDone(PR_FALSE),
mNativeComponentLoader(0),
mStaticComponentLoader(0),
mShuttingDown(NS_SHUTDOWN_NEVERHAPPENED), mLoaderData(nsnull)
{
NS_INIT_REFCNT();
}
2001-09-07 02:10:51 +04:00
PR_STATIC_CALLBACK(PRBool)
nsFactoryEntry_mFactoryDestroy(nsHashKey *aKey, void *aData, void* closure)
1999-07-28 12:01:03 +04:00
{
nsFactoryEntry* entry = NS_STATIC_CAST(nsFactoryEntry*, aData);
delete entry;
return PR_TRUE;
}
2001-09-07 02:10:51 +04:00
PR_STATIC_CALLBACK(PRBool)
nsFactoryEntry_mContractIDsDestory(nsHashKey *aKey, void *aData, void* closure)
{
nsFactoryEntry* entry = NS_STATIC_CAST(nsFactoryEntry*, aData);
if (entry != kNonExistentContractID &&
entry->typeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY &&
entry->cid.Equals(kEmptyCID)) {
// this object is owned by the hash. Time to delete it.
delete entry;
}
return PR_TRUE;
}
nsresult nsComponentManagerImpl::Init(void)
{
PR_ASSERT(mShuttingDown != NS_SHUTDOWN_INPROGRESS);
if (mShuttingDown == NS_SHUTDOWN_INPROGRESS)
return NS_ERROR_FAILURE;
mShuttingDown = NS_SHUTDOWN_NEVERHAPPENED;
if (nsComponentManagerLog == NULL)
{
nsComponentManagerLog = PR_NewLogModule("nsComponentManager");
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("xpcom-log-version : " NS_XPCOM_COMPONENT_MANAGER_VERSION_STRING));
}
if (mFactories == NULL) {
1999-07-28 12:01:03 +04:00
mFactories = new nsObjectHashtable(nsnull, nsnull, // should never be copied
nsFactoryEntry_mFactoryDestroy, nsnull,
1999-07-28 12:01:03 +04:00
256, /* Thread Safe */ PR_TRUE);
if (mFactories == NULL)
return NS_ERROR_OUT_OF_MEMORY;
}
if (mContractIDs == NULL) {
// This hashtable holds references to the factory entry. All entries are non-owning
// unless the typeIndex is NS_COMPONENT_TYPE_SERVICE_ONLY.
// The owning ref is from the mFactories hash table.
mContractIDs = new nsObjectHashtable(nsnull, nsnull, // should never be copied
nsFactoryEntry_mContractIDsDestory, nsnull,
256, /* Thread Safe */ PR_TRUE);
if (mContractIDs == NULL)
return NS_ERROR_OUT_OF_MEMORY;
}
if (mMon == NULL) {
mMon = PR_NewMonitor();
if (mMon == NULL)
return NS_ERROR_OUT_OF_MEMORY;
}
if (mNativeComponentLoader == nsnull) {
/* Create the NativeComponentLoader */
mNativeComponentLoader = new nsNativeComponentLoader();
if (!mNativeComponentLoader)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mNativeComponentLoader);
}
// Add predefined loaders
mLoaderData = (nsLoaderdata *) PR_Malloc(sizeof(nsLoaderdata) * NS_LOADER_DATA_ALLOC_STEP);
if (!mLoaderData)
return NS_ERROR_OUT_OF_MEMORY;
mMaxNLoaderData = NS_LOADER_DATA_ALLOC_STEP;
mNLoaderData = NS_COMPONENT_TYPE_NATIVE;
mLoaderData[mNLoaderData].type = PL_strdup(nativeComponentType);
mLoaderData[mNLoaderData].loader = mNativeComponentLoader;
NS_ADDREF(mLoaderData[mNLoaderData].loader);
mNLoaderData++;
#ifdef ENABLE_STATIC_COMPONENT_LOADER
if (mStaticComponentLoader == nsnull) {
extern nsresult NS_NewStaticComponentLoader(nsIComponentLoader **);
NS_NewStaticComponentLoader(&mStaticComponentLoader);
if (!mStaticComponentLoader)
return NS_ERROR_OUT_OF_MEMORY;
}
mLoaderData[mNLoaderData].type = PL_strdup(staticComponentType);
mLoaderData[mNLoaderData].loader = mStaticComponentLoader;
NS_ADDREF(mLoaderData[mNLoaderData].loader);
mNLoaderData++;
#endif
#ifdef USE_REGISTRY
2000-01-25 00:28:28 +03:00
NR_StartupRegistry();
{
nsresult ret;
ret = PlatformInit();
if( NS_FAILED( ret ) ) {
return ret;
}
}
#endif
2000-01-25 00:28:28 +03:00
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("nsComponentManager: Initialized."));
return NS_OK;
}
nsresult nsComponentManagerImpl::Shutdown(void)
{
PR_ASSERT(mShuttingDown == NS_SHUTDOWN_NEVERHAPPENED);
if (mShuttingDown != NS_SHUTDOWN_NEVERHAPPENED)
return NS_ERROR_FAILURE;
mShuttingDown = NS_SHUTDOWN_INPROGRESS;
// Shutdown the component manager
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Beginning Shutdown."));
// Release all cached factories
delete mContractIDs;
delete mFactories;
// Unload libraries
UnloadLibraries(NULL, NS_Shutdown);
#ifdef USE_REGISTRY
// Release registry
NS_IF_RELEASE(mRegistry);
#endif /* USE_REGISTRY */
// This is were the nsFileSpec was deleted, so I am
// going to assign zero to
mComponentsDir = 0;
// Release all the component data - loaders and type strings
for(int i=0; i < mNLoaderData; i++) {
NS_IF_RELEASE(mLoaderData[i].loader);
PL_strfree((char *)mLoaderData[i].type);
}
PR_Free(mLoaderData);
mLoaderData = nsnull;
// we have an extra reference on this one, which is probably a good thing
NS_IF_RELEASE(mNativeComponentLoader);
#ifdef ENABLE_STATIC_COMPONENT_LOADER
NS_IF_RELEASE(mStaticComponentLoader);
#endif
// Destroy the Lock
if (mMon)
PR_DestroyMonitor(mMon);
#ifdef USE_REGISTRY
NR_ShutdownRegistry();
#endif /* USE_REGISTRY */
mShuttingDown = NS_SHUTDOWN_COMPLETE;
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Shutdown complete."));
return NS_OK;
}
nsComponentManagerImpl::~nsComponentManagerImpl()
{
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Beginning destruction."));
if (mShuttingDown != NS_SHUTDOWN_COMPLETE)
Shutdown();
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Destroyed."));
}
NS_IMPL_ISUPPORTS4(nsComponentManagerImpl,
nsIComponentManager,
nsIServiceManager,
nsISupportsWeakReference,
nsIInterfaceRequestor)
////////////////////////////////////////////////////////////////////////////////
// nsComponentManagerImpl: Platform methods
////////////////////////////////////////////////////////////////////////////////
#ifdef USE_REGISTRY
nsresult
nsComponentManagerImpl::PlatformInit(void)
{
nsresult rv = NS_ERROR_FAILURE;
1999-06-22 18:02:58 +04:00
// We need to create our registry. Since we are in the constructor
// we haven't gone as far as registering the registry factory.
// Hence, we hand create a registry.
if (mRegistry == NULL) {
nsIFactory *registryFactory = NULL;
rv = NS_RegistryGetFactory(&registryFactory);
if (NS_SUCCEEDED(rv))
{
rv = registryFactory->CreateInstance(NULL, NS_GET_IID(nsIRegistry),(void **)&mRegistry);
if (NS_FAILED(rv)) return rv;
NS_RELEASE(registryFactory);
}
}
1999-06-09 23:18:24 +04:00
// Open the App Components registry. We will keep it open forever!
rv = mRegistry->OpenWellKnownRegistry(nsIRegistry::ApplicationComponentRegistry);
if (NS_FAILED(rv)) return rv;
// Set larger-than-standard buffer size to speed startup.
// This will be re-set at the end of PrePopulateRegistry()
mRegistry->SetBufferSize(500*1024);
// Check the version of registry. Nuke old versions.
2000-02-16 10:45:20 +03:00
nsRegistryKey xpcomRoot;
rv = PlatformVersionCheck(&xpcomRoot);
if (NS_FAILED(rv)) return rv;
1999-05-06 17:29:37 +04:00
// Open common registry keys here to speed access
// Do this after PlatformVersionCheck as it may re-create our keys
2000-02-16 10:45:20 +03:00
rv = mRegistry->AddSubtree(xpcomRoot, componentsKeyName, &mXPCOMKey);
if (NS_FAILED(rv)) return rv;
2000-02-16 10:45:20 +03:00
rv = mRegistry->AddSubtree(xpcomRoot, classesKeyName, &mClassesKey);
if (NS_FAILED(rv)) return rv;
2000-02-16 10:45:20 +03:00
rv = mRegistry->AddSubtree(xpcomRoot, classIDKeyName, &mCLSIDKey);
if (NS_FAILED(rv)) return rv;
2000-01-25 00:28:28 +03:00
nsCOMPtr<nsIProperties> directoryService;
rv = nsDirectoryService::Create(nsnull,
NS_GET_IID(nsIProperties),
getter_AddRefs(directoryService));
directoryService->Get(NS_XPCOM_COMPONENT_DIR, NS_GET_IID(nsIFile), getter_AddRefs(mComponentsDir));
if (!mComponentsDir)
return NS_ERROR_OUT_OF_MEMORY;
2000-01-25 00:28:28 +03:00
char* componentDescriptor;
mComponentsDir->GetPath(&componentDescriptor);
if (!componentDescriptor)
return NS_ERROR_NULL_POINTER;
2000-02-01 10:54:46 +03:00
mComponentsOffset = strlen(componentDescriptor);
if (componentDescriptor)
nsMemory::Free(componentDescriptor);
2000-02-01 10:54:46 +03:00
if (mNativeComponentLoader) {
/* now that we have the registry, Init the native loader */
rv = mNativeComponentLoader->Init(this, mRegistry);
} else {
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
("no native component loader available for init"));
}
#ifdef ENABLE_STATIC_COMPONENT_LOADER
if (mStaticComponentLoader) {
/* now that we have the registry, Init the static loader */
rv = mStaticComponentLoader->Init(this, mRegistry);
}
#endif
return rv;
}
/**
* PlatformVersionCheck()
*
* Checks to see if the XPCOM hierarchy in the registry is the same as that of
* the software as defined by NS_XPCOM_COMPONENT_MANAGER_VERSION_STRING
*/
nsresult
2000-02-16 10:45:20 +03:00
nsComponentManagerImpl::PlatformVersionCheck(nsRegistryKey *aXPCOMRootKey)
{
nsRegistryKey xpcomKey;
nsresult rv;
rv = mRegistry->AddSubtree(nsIRegistry::Common, xpcomKeyName, &xpcomKey);
if (NS_FAILED(rv)) return rv;
nsXPIDLCString buf;
nsresult err = mRegistry->GetStringUTF8(xpcomKey, versionValueName,
getter_Copies(buf));
// If there is a version mismatch or no version string, we got an old registry.
// Delete the old repository hierarchies and recreate version string
1999-05-06 17:29:37 +04:00
if (NS_FAILED(err) || PL_strcmp(buf, NS_XPCOM_COMPONENT_MANAGER_VERSION_STRING))
{
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("nsComponentManager: Registry version mismatch (old:%s vs new:%s)."
"Nuking xpcom registry hierarchy.", (const char *)buf,
NS_XPCOM_COMPONENT_MANAGER_VERSION_STRING));
2000-02-16 10:45:20 +03:00
// Delete the XPCOM hierarchy
rv = mRegistry->RemoveSubtree(nsIRegistry::Common, xpcomKeyName);
if(NS_FAILED(rv))
{
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
2000-02-16 10:45:20 +03:00
("nsComponentManager: Failed To Nuke Subtree (%s)",xpcomKeyName));
return rv;
}
2000-02-16 10:45:20 +03:00
// The top-level Classes and CLSID trees are from an early alpha version,
// we can probably remove these two deletions after the second beta or so.
(void) mRegistry->RemoveSubtree(nsIRegistry::Common, classIDKeyName);
(void) mRegistry->RemoveSubtree(nsIRegistry::Common, classesKeyName);
2000-02-16 10:45:20 +03:00
// Recreate XPCOM key and version
rv = mRegistry->AddSubtree(nsIRegistry::Common,xpcomKeyName, &xpcomKey);
if(NS_FAILED(rv))
{
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
2000-02-16 10:45:20 +03:00
("nsComponentManager: Failed To Add Subtree (%s)",xpcomKeyName));
return rv;
}
rv = mRegistry->SetStringUTF8(xpcomKey,versionValueName, NS_XPCOM_COMPONENT_MANAGER_VERSION_STRING);
if(NS_FAILED(rv))
{
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("nsComponentManager: Failed To Set String (Version) Under (%s)",xpcomKeyName));
return rv;
}
}
2000-02-16 10:45:20 +03:00
else
{
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("nsComponentManager: platformVersionCheck() passed."));
}
2000-02-16 10:45:20 +03:00
// return the XPCOM key (null check deferred so cleanup always happens)
2000-02-16 10:45:20 +03:00
if (!aXPCOMRootKey)
return NS_ERROR_NULL_POINTER;
else
*aXPCOMRootKey = xpcomKey;
return NS_OK;
}
#if 0
// If ever revived, this code is not fully updated to escape the dll location
1999-06-22 18:02:58 +04:00
void
nsComponentManagerImpl::PlatformSetFileInfo(nsRegistryKey key, PRUint32 lastModifiedTime, PRUint32 fileSize)
1999-06-22 18:02:58 +04:00
{
mRegistry->SetInt(key, lastModValueName, lastModifiedTime);
mRegistry->SetInt(key, fileSizeValueName, fileSize);
}
/**
* PlatformMarkNoComponents(nsDll *dll)
*
* Stores the dll name, last modified time, size and 0 for number of
* components in dll in the registry at location
* ROOTKEY_COMMON/Software/Mozilla/XPCOM/Components/dllname
*/
nsresult
nsComponentManagerImpl::PlatformMarkNoComponents(nsDll *dll)
{
PR_ASSERT(mRegistry!=NULL);
nsresult rv;
nsRegistryKey dllPathKey;
1999-06-22 18:02:58 +04:00
rv = mRegistry->AddSubtreeRaw(mXPCOMKey, dll->GetPersistentDescriptorString(), &dllPathKey);
if(NS_FAILED(rv))
{
return rv;
}
1999-06-22 18:02:58 +04:00
PlatformSetFileInfo(dllPathKey, dll->GetLastModifiedTime(), dll->GetSize());
rv = mRegistry->SetInt(dllPathKey, componentCountValueName, 0);
return rv;
}
nsresult
nsComponentManagerImpl::PlatformRegister(const char *cidString,
const char *className,
const char * contractID, nsDll *dll)
{
// Preconditions
PR_ASSERT(cidString != NULL);
PR_ASSERT(dll != NULL);
PR_ASSERT(mRegistry !=NULL);
nsresult rv;
nsRegistryKey IDkey;
rv = mRegistry->AddSubtreeRaw(mCLSIDKey, cidString, &IDkey);
if (NS_FAILED(rv)) return (rv);
rv = mRegistry->SetStringUTF8(IDkey,classNameValueName, className);
if (contractID)
{
rv = mRegistry->SetStringUTF8(IDkey,contractIDValueName, contractID);
}
rv = mRegistry->SetBytesUTF8(IDkey, inprocServerValueName,
strlen(dll->GetPersistentDescriptorString()) + 1,
NS_REINTERPRET_CAST(char*, dll->GetPersistentDescriptorString()));
if (contractID)
{
nsRegistryKey contractIDKey;
rv = mRegistry->AddSubtreeRaw(mClassesKey, contractID, &contractIDKey);
rv = mRegistry->SetStringUTF8(contractIDKey, classIDValueName, cidString);
}
nsRegistryKey dllPathKey;
1999-06-22 18:02:58 +04:00
rv = mRegistry->AddSubtreeRaw(mXPCOMKey,dll->GetPersistentDescriptorString(), &dllPathKey);
1999-06-22 18:02:58 +04:00
PlatformSetFileInfo(dllPathKey, dll->GetLastModifiedTime(), dll->GetSize());
PRInt32 nComponents = 0;
rv = mRegistry->GetInt(dllPathKey, componentCountValueName, &nComponents);
nComponents++;
rv = mRegistry->SetInt(dllPathKey,componentCountValueName, nComponents);
return rv;
}
#endif
nsresult
nsComponentManagerImpl::PlatformUnregister(const char *cidString,
const char *aLibrary)
{
nsresult rv;
PRUint32 length = strlen(aLibrary);
char* eLibrary;
rv = mRegistry->EscapeKey((PRUint8*)aLibrary, 1, &length, (PRUint8**)&eLibrary);
if (rv != NS_OK)
{
return rv;
}
if (eLibrary == nsnull) // No escaping required
eLibrary = (char*)aLibrary;
PR_ASSERT(mRegistry!=NULL);
nsRegistryKey cidKey;
rv = mRegistry->AddSubtreeRaw(mCLSIDKey, cidString, &cidKey);
char *contractID = NULL;
rv = mRegistry->GetStringUTF8(cidKey, contractIDValueName, &contractID);
if(NS_SUCCEEDED(rv))
{
mRegistry->RemoveSubtreeRaw(mClassesKey, contractID);
PR_FREEIF(contractID);
}
mRegistry->RemoveSubtree(mCLSIDKey, cidString);
nsRegistryKey libKey;
rv = mRegistry->GetSubtreeRaw(mXPCOMKey, eLibrary, &libKey);
if(NS_FAILED(rv)) return rv;
// We need to reduce the ComponentCount by 1.
// If the ComponentCount hits 0, delete the entire key.
PRInt32 nComponents = 0;
rv = mRegistry->GetInt(libKey, componentCountValueName, &nComponents);
if(NS_FAILED(rv)) return rv;
nComponents--;
if (nComponents <= 0)
{
rv = mRegistry->RemoveSubtreeRaw(mXPCOMKey, eLibrary);
}
else
{
rv = mRegistry->SetInt(libKey, componentCountValueName, nComponents);
}
if (eLibrary != aLibrary)
nsMemory::Free(eLibrary);
return rv;
}
nsresult
nsComponentManagerImpl::PlatformFind(const nsCID &aCID, nsFactoryEntry* *result)
{
PR_ASSERT(mRegistry!=NULL);
nsresult rv;
char *cidString = aCID.ToString();
nsRegistryKey cidKey;
1999-05-06 08:19:06 +04:00
rv = mRegistry->GetSubtreeRaw(mCLSIDKey, cidString, &cidKey);
delete [] cidString;
if (NS_FAILED(rv)) return rv;
nsXPIDLCString library;
PRUint32 tmp;
rv = mRegistry->GetBytesUTF8(cidKey, inprocServerValueName,
&tmp, (PRUint8**)getter_Copies(library).operator char**());
if (NS_FAILED(rv))
{
// Registry inconsistent. No File name for CLSID.
return rv;
}
nsXPIDLCString componentTypeStr;
rv = mRegistry->GetStringUTF8(cidKey, componentTypeValueName,
getter_Copies(componentTypeStr));
const char* componentType = componentTypeStr.get();
int type = NS_COMPONENT_TYPE_FACTORY_ONLY;
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_REG_NOT_FOUND) {
/* missing componentType, we assume application/x-moz-native */
type = NS_COMPONENT_TYPE_NATIVE;
}
else
return rv; // XXX translate error code?
}
if (type < 0) {
// Find the right loader type index
type = GetLoaderType(componentType);
}
nsFactoryEntry *res = new nsFactoryEntry(aCID, library, type);
if (res == NULL)
return NS_ERROR_OUT_OF_MEMORY;
*result = res;
return NS_OK;
}
nsresult
nsComponentManagerImpl::PlatformContractIDToCLSID(const char *aContractID, nsCID *aClass)
{
PR_ASSERT(aClass != NULL);
PR_ASSERT(mRegistry);
nsresult rv;
nsRegistryKey contractIDKey;
rv = mRegistry->GetSubtreeRaw(mClassesKey, aContractID, &contractIDKey);
if (NS_FAILED(rv)) return NS_ERROR_FACTORY_NOT_REGISTERED;
char *cidString;
rv = mRegistry->GetStringUTF8(contractIDKey, classIDValueName, &cidString);
if(NS_FAILED(rv)) return rv;
if (!(aClass->Parse(cidString)))
{
1999-06-22 18:02:58 +04:00
rv = NS_ERROR_FAILURE;
}
1999-06-22 18:02:58 +04:00
PR_FREEIF(cidString);
return rv;
}
nsresult
nsComponentManagerImpl::PlatformCLSIDToContractID(const nsCID *aClass,
char* *aClassName, char* *aContractID)
{
PR_ASSERT(aClass);
PR_ASSERT(mRegistry);
nsresult rv;
char* cidStr = aClass->ToString();
nsRegistryKey cidKey;
rv = mRegistry->GetSubtreeRaw(mCLSIDKey, cidStr, &cidKey);
if(NS_FAILED(rv)) return rv;
PR_FREEIF(cidStr);
char* classnameString;
rv = mRegistry->GetStringUTF8(cidKey, classNameValueName, &classnameString);
if(NS_FAILED(rv)) return rv;
*aClassName = classnameString;
char* contractidString;
rv = mRegistry->GetStringUTF8(cidKey,contractIDValueName,&contractidString);
if (NS_FAILED(rv)) return rv;
*aContractID = contractidString;
return NS_OK;
}
1999-07-02 07:35:09 +04:00
nsresult nsComponentManagerImpl::PlatformPrePopulateRegistry()
{
nsresult rv;
1999-07-02 07:35:09 +04:00
if (mPrePopulationDone)
return NS_OK;
(void)mRegistry->SetBufferSize( 500*1024 );
// Read in all CID entries and populate the mFactories
1999-07-02 07:35:09 +04:00
nsCOMPtr<nsIEnumerator> cidEnum;
rv = mRegistry->EnumerateSubtrees( mCLSIDKey, getter_AddRefs(cidEnum));
if (NS_FAILED(rv)) return rv;
2001-02-01 01:05:28 +03:00
nsCOMPtr<nsIRegistryEnumerator> regEnum(do_QueryInterface(cidEnum, &rv));
if (NS_FAILED(rv)) return rv;
1999-07-02 07:35:09 +04:00
for (rv = regEnum->First();
NS_SUCCEEDED(rv) && (regEnum->IsDone() != NS_OK);
rv = regEnum->Next())
{
const char *cidString;
nsRegistryKey cidKey;
/*
* CurrentItemInPlaceUTF8 will give us back a _shared_ pointer in
* cidString. This is bad XPCOM practice. It is evil, and requires
* great care with the relative lifetimes of cidString and regEnum.
*
* It is also faster, and less painful in the allocation department.
*/
rv = regEnum->CurrentItemInPlaceUTF8(&cidKey, &cidString);
if (NS_FAILED(rv)) continue;
1999-07-02 07:35:09 +04:00
// Create the CID entry
nsXPIDLCString library;
PRUint32 tmp;
rv = mRegistry->GetBytesUTF8(cidKey, inprocServerValueName,
&tmp, (PRUint8**)getter_Copies(library).operator char**());
1999-07-02 07:35:09 +04:00
if (NS_FAILED(rv)) continue;
nsCID aClass;
1999-07-02 07:35:09 +04:00
if (!(aClass.Parse(cidString))) continue;
nsXPIDLCString componentType;
if (NS_FAILED(mRegistry->GetStringUTF8(cidKey, componentTypeValueName,
getter_Copies(componentType))))
continue;
int loadertype = GetLoaderType(componentType);
if (loadertype < 0) {
loadertype = AddLoaderType(componentType);
}
nsFactoryEntry* entry =
new nsFactoryEntry(aClass, library, loadertype);
if (!entry)
continue;
1999-07-02 07:35:09 +04:00
nsIDKey key(aClass);
mFactories->Put(&key, entry);
}
// Finally read in CONTRACTID -> CID mappings
nsCOMPtr<nsIEnumerator> contractidEnum;
rv = mRegistry->EnumerateSubtrees( mClassesKey, getter_AddRefs(contractidEnum));
if (NS_FAILED(rv)) return rv;
regEnum = do_QueryInterface(contractidEnum, &rv);
if (NS_FAILED(rv)) return rv;
for (rv = regEnum->First();
NS_SUCCEEDED(rv) && (regEnum->IsDone() != NS_OK);
rv = regEnum->Next())
{
const char *contractidString;
nsRegistryKey contractidKey;
/*
* CurrentItemInPlaceUTF8 will give us back a _shared_ pointer in
* contractidString. This is bad XPCOM practice. It is evil, and requires
* great care with the relative lifetimes of contractidString and regEnum.
*
* It is also faster, and less painful in the allocation department.
*/
rv = regEnum->CurrentItemInPlaceUTF8(&contractidKey, &contractidString);
if (NS_FAILED(rv)) continue;
nsXPIDLCString cidString;
rv = mRegistry->GetStringUTF8(contractidKey, classIDValueName,
getter_Copies(cidString));
if (NS_FAILED(rv)) continue;
nsCID aClass;
if (!(aClass.Parse(cidString)))
{
continue;
}
// put the {contractid, Cid} mapping into our map
HashContractID(contractidString, aClass);
// printf("Populating [ %s, %s ]\n", cidString, contractidString);
}
1999-07-02 07:35:09 +04:00
//(void)mRegistry->SetBufferSize( 10*1024 );
mPrePopulationDone = PR_TRUE;
1999-07-02 07:35:09 +04:00
return NS_OK;
}
#endif /* USE_REGISTRY */
1999-06-22 18:02:58 +04:00
//
// HashContractID
1999-06-22 18:02:58 +04:00
//
nsresult
nsComponentManagerImpl::HashContractID(const char *aContractID, const nsCID &aClass, nsFactoryEntry **pfe)
{
nsIDKey cidKey(aClass);
return HashContractID(aContractID, aClass, cidKey, pfe);
}
nsresult
nsComponentManagerImpl::HashContractID(const char *aContractID, const nsCID &aClass, nsIDKey &cidKey, nsFactoryEntry **pfe)
1999-06-22 18:02:58 +04:00
{
if(!aContractID)
1999-06-22 18:02:58 +04:00
{
return NS_ERROR_NULL_POINTER;
}
// Find the factory entry corresponding to the CID.
nsFactoryEntry *entry = GetFactoryEntry(aClass, cidKey);
if (!entry) {
// Non existent. We use the special kNonExistentContractID to mark
// that this contractid does not have a mapping.
entry = kNonExistentContractID;
1999-06-22 18:02:58 +04:00
}
nsresult rv = HashContractID(aContractID, entry);
if (NS_FAILED(rv))
return rv;
// Fill the entry out parameter
if (pfe) *pfe = entry;
return NS_OK;
}
nsresult
nsComponentManagerImpl::HashContractID(const char *aContractID, nsFactoryEntry *fe)
{
if(!aContractID)
return NS_ERROR_NULL_POINTER;
1999-06-22 18:02:58 +04:00
nsCStringKey key(aContractID);
mContractIDs->Put(&key, fe);
1999-06-22 18:02:58 +04:00
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsComponentManagerImpl: Public methods
////////////////////////////////////////////////////////////////////////////////
/**
* LoadFactory()
*
* Given a FactoryEntry, this loads the dll if it has to, find the NSGetFactory
* symbol, calls the routine to create a new factory and returns it to the
* caller.
*
* No attempt is made to store the factory in any form anywhere.
*/
nsresult
nsComponentManagerImpl::LoadFactory(nsFactoryEntry *aEntry,
nsIFactory **aFactory)
{
if (!aFactory)
return NS_ERROR_NULL_POINTER;
*aFactory = NULL;
nsresult rv;
rv = aEntry->GetFactory(aFactory, this);
if (NS_FAILED(rv)) {
1999-08-09 09:40:51 +04:00
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
("nsComponentManager: FAILED to load factory from %s (%s)\n",
(const char *)aEntry->location, mLoaderData[aEntry->typeIndex].type));
return rv;
}
return NS_OK;
}
nsFactoryEntry *
nsComponentManagerImpl::GetFactoryEntry(const char *aContractID, int checkRegistry)
{
nsCStringKey key(aContractID);
nsFactoryEntry *fe = (nsFactoryEntry *) mContractIDs->Get(&key);
#ifdef USE_REGISTRY
if (!fe)
{
if (checkRegistry < 0) {
// default
checkRegistry = !mPrePopulationDone;
}
if (checkRegistry)
{
nsCID cid;
nsresult rv = PlatformContractIDToCLSID(aContractID, &cid);
if (NS_SUCCEEDED(rv)) {
HashContractID(aContractID, cid, &fe);
}
}
}
#endif /* USE_REGISTRY */
// If no mapping found, add a special non-existent mapping
// so the next time around, we dont have to waste time doing the
// same mapping over and over again
if (!fe) {
fe = kNonExistentContractID;
HashContractID(aContractID, fe);
}
return (fe);
}
nsFactoryEntry *
nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass, int checkRegistry)
{
nsIDKey cidKey(aClass);
return GetFactoryEntry(aClass, cidKey, checkRegistry);
}
nsFactoryEntry *
nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass, nsIDKey &cidKey, int checkRegistry)
{
nsFactoryEntry *entry = (nsFactoryEntry*) mFactories->Get(&cidKey);
#ifdef USE_REGISTRY
if (!entry)
{
if (checkRegistry < 0) {
// default
checkRegistry = !mPrePopulationDone;
}
if (checkRegistry) {
nsresult rv = PlatformFind(aClass, &entry);
// If we got one, cache it in our hashtable
if (NS_SUCCEEDED(rv))
{
mFactories->Put(&cidKey, entry);
}
}
}
#endif /* USE_REGISTRY */
return (entry);
}
/**
* FindFactory()
*
* Given a classID, this finds the factory for this CID by first searching the
* local CID<->factory mapping. Next it searches for a Dll that implements
* this classID and calls LoadFactory() to create the factory.
*
* Again, no attempt is made at storing the factory.
*/
nsresult
nsComponentManagerImpl::FindFactory(const nsCID &aClass,
nsIFactory **aFactory)
{
PR_ASSERT(aFactory != NULL);
nsFactoryEntry *entry = GetFactoryEntry(aClass);
if (!entry)
return NS_ERROR_FACTORY_NOT_REGISTERED;
return entry->GetFactory(aFactory, this);
}
nsresult
nsComponentManagerImpl::FindFactory(const char *contractID,
nsIFactory **aFactory)
{
PR_ASSERT(aFactory != NULL);
nsFactoryEntry *entry = GetFactoryEntry(contractID);
if (!entry || entry == kNonExistentContractID)
return NS_ERROR_FACTORY_NOT_REGISTERED;
return entry->GetFactory(aFactory, this);
}
/**
* GetClassObject()
*
* Given a classID, this finds the singleton ClassObject that implements the CID.
* Returns an interface of type aIID off the singleton classobject.
*/
nsresult
nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID,
void **aResult)
{
nsresult rv;
nsCOMPtr<nsIFactory> factory;
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
{
char *buf = aClass.ToString();
PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
delete [] buf;
}
PR_ASSERT(aResult != NULL);
rv = FindFactory(aClass, getter_AddRefs(factory));
if (NS_FAILED(rv)) return rv;
rv = factory->QueryInterface(aIID, aResult);
PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
return rv;
}
/**
* ContractIDToClassID()
*
* Mapping function from a ContractID to a classID. Directly talks to the registry.
*
*/
nsresult
nsComponentManagerImpl::ContractIDToClassID(const char *aContractID, nsCID *aClass)
{
NS_PRECONDITION(aContractID != NULL, "null ptr");
if (! aContractID)
return NS_ERROR_NULL_POINTER;
NS_PRECONDITION(aClass != NULL, "null ptr");
if (! aClass)
return NS_ERROR_NULL_POINTER;
nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED;
nsFactoryEntry *fe = GetFactoryEntry(aContractID);
if (fe && fe != kNonExistentContractID) {
*aClass = fe->cid;
res = NS_OK;
}
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) {
char *buf = 0;
if (NS_SUCCEEDED(res))
buf = aClass->ToString();
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("nsComponentManager: ContractIDToClassID(%s)->%s", aContractID,
NS_SUCCEEDED(res) ? buf : "[FAILED]"));
if (NS_SUCCEEDED(res))
delete [] buf;
}
return res;
}
/**
* CLSIDToContractID()
*
* Translates a classID to a {ContractID, Class Name}. Does direct registry
* access to do the translation.
*
* NOTE: Since this isn't heavily used, we arent caching this.
*/
nsresult
nsComponentManagerImpl::CLSIDToContractID(const nsCID &aClass,
char* *aClassName,
char* *aContractID)
{
nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED;
#ifdef USE_REGISTRY
res = PlatformCLSIDToContractID(&aClass, aClassName, aContractID);
#endif /* USE_REGISTRY */
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
{
1999-09-05 10:27:42 +04:00
char *buf = aClass.ToString();
PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
("nsComponentManager: CLSIDToContractID(%s)->%s", buf,
NS_SUCCEEDED(res) ? *aContractID : "[FAILED]"));
delete [] buf;
}
return res;
}
/**
* CreateInstance()
*
* Create an instance of an object that implements an interface and belongs
* to the implementation aClass using the factory. The factory is immediately
* released and not held onto for any longer.
*/
nsresult
nsComponentManagerImpl::CreateInstance(const nsCID &aClass,
nsISupports *aDelegate,
const nsIID &aIID,
void **aResult)
{
// test this first, since there's no point in creating a component during
// shutdown -- whether it's available or not would depend on the order it
// occurs in the list
if (gShuttingDown) {
// When processing shutdown, dont process new GetService() requests
#ifdef DEBUG_dp
NS_WARN_IF_FALSE(PR_FALSE, "Creating new instance on shutdown. Denied.");
#endif /* DEBUG_dp */
return NS_ERROR_UNEXPECTED;
}
if (aResult == NULL)
{
return NS_ERROR_NULL_POINTER;
}
*aResult = NULL;
nsIFactory *factory = NULL;
nsresult res = FindFactory(aClass, &factory);
if (NS_SUCCEEDED(res))
{
res = factory->CreateInstance(aDelegate, aIID, aResult);
NS_RELEASE(factory);
}
else
{
// Translate error values
res = NS_ERROR_FACTORY_NOT_REGISTERED;
}
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
{
char *buf = aClass.ToString();
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("nsComponentManager: CreateInstance(%s) %s", buf,
NS_SUCCEEDED(res) ? "succeeded" : "FAILED"));
delete [] buf;
}
return res;
}
/**
* CreateInstanceByContractID()
*
* A variant of CreateInstance() that creates an instance of the object that
* implements the interface aIID and whose implementation has a contractID aContractID.
*
* This is only a convenience routine that turns around can calls the
* CreateInstance() with classid and iid.
*/
nsresult
nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID,
1999-09-05 10:27:42 +04:00
nsISupports *aDelegate,
const nsIID &aIID,
void **aResult)
{
// test this first, since there's no point in creating a component during
// shutdown -- whether it's available or not would depend on the order it
// occurs in the list
if (gShuttingDown) {
// When processing shutdown, dont process new GetService() requests
#ifdef DEBUG_dp
NS_WARN_IF_FALSE(PR_FALSE, "Creating new instance on shutdown. Denied.");
#endif /* DEBUG_dp */
return NS_ERROR_UNEXPECTED;
}
if (aResult == NULL)
{
return NS_ERROR_NULL_POINTER;
}
*aResult = NULL;
nsIFactory *factory = NULL;
nsresult res = FindFactory(aContractID, &factory);
if (NS_SUCCEEDED(res))
{
res = factory->CreateInstance(aDelegate, aIID, aResult);
NS_RELEASE(factory);
}
else
{
// Translate error values
res = NS_ERROR_FACTORY_NOT_REGISTERED;
}
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
NS_SUCCEEDED(res) ? "succeeded" : "FAILED"));
return res;
}
// Service Manager Impl
2001-09-07 02:10:51 +04:00
PR_STATIC_CALLBACK(PRBool) FreeServiceEntry(nsHashKey *aKey, void *aData, void* aClosure)
{
nsFactoryEntry* entry = NS_STATIC_CAST(nsFactoryEntry*, aData);
if (!entry || entry == kNonExistentContractID)
return PR_TRUE;
if (entry->mServiceEntry) {
delete entry->mServiceEntry;
entry->mServiceEntry = nsnull;
}
return PR_TRUE;
}
nsresult
nsComponentManagerImpl::FreeServices()
{
if (mFactories)
mFactories->Enumerate(FreeServiceEntry);
if (mContractIDs)
mContractIDs->Enumerate(FreeServiceEntry);
return NS_OK;
}
NS_IMETHODIMP
nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
nsISupports* *result,
nsIShutdownListener* shutdownListener)
{
nsAutoMonitor mon(mMon);
// test this first, since there's no point in returning a service during
// shutdown -- whether it's available or not would depend on the order it
// occurs in the list
if (gShuttingDown) {
// When processing shutdown, dont process new GetService() requests
NS_WARNING("Creating new service on shutdown. Denied.");
return NS_ERROR_UNEXPECTED;
}
nsresult rv = NS_OK;
nsIDKey key(aClass);
nsFactoryEntry* entry = (nsFactoryEntry*)mFactories->Get(&key);
nsServiceEntry* serviceEntry;
if (entry && entry->mServiceEntry) {
serviceEntry = entry->mServiceEntry;
if (!serviceEntry->mObject)
return NS_ERROR_NULL_POINTER;
nsISupports* service; // keep as raw point (avoid extra addref/release)
rv = serviceEntry->mObject->QueryInterface(aIID, (void**)&service);
if (NS_SUCCEEDED(rv)) {
// The refcount acquired in QI() above is "returned" to
// the caller.
if (shutdownListener) {
rv = serviceEntry->AddListener(shutdownListener);
if (NS_FAILED(rv)) {
NS_RELEASE(service);
return rv;
}
}
*result = service;
// If someone else requested the service to be shut down,
// and we just asked to get it again before it could be
// released, then cancel their shutdown request:
if (serviceEntry->mShuttingDown) {
serviceEntry->mShuttingDown = PR_FALSE;
NS_ADDREF(service); // Released in UnregisterService
}
}
return rv;
}
nsISupports* service;
// We need to not be holding the service manager's monitor while calling
// CreateInstance, because it invokes user code which could try to re-enter
// the service manager:
mon.Exit();
rv = CreateInstance(aClass, NULL, aIID, (void**)&service);
mon.Enter();
if (NS_FAILED(rv))
return rv;
if (!entry) { // second hash lookup for GetService
entry = (nsFactoryEntry*)mFactories->Get(&key);
NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
if (!entry) return NS_ERROR_FAILURE;
}
serviceEntry = new nsServiceEntry(service, entry);
if (serviceEntry == NULL) {
NS_RELEASE(service);
return NS_ERROR_OUT_OF_MEMORY;
}
if (shutdownListener) {
rv = serviceEntry->AddListener(shutdownListener);
if (NS_FAILED(rv)) {
NS_RELEASE(service);
delete serviceEntry;
return rv;
}
}
entry->mServiceEntry = serviceEntry; // deleted in nsFactoryEntry's destructor
*result = service; // transfer ownership
return rv;
}
NS_IMETHODIMP
nsComponentManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service,
nsIShutdownListener* shutdownListener)
{
PRBool serviceFound = PR_FALSE;
nsresult rv = NS_OK;
#ifndef NS_DEBUG
// Do entry lookup only if there is a shutdownlistener to be removed.
//
// For Debug builds, Consistency check for entry always. Releasing service
// when the service is not with the servicemanager is mostly wrong.
if (shutdownListener)
#endif
{
nsAutoMonitor mon(mMon);
nsIDKey key(aClass);
nsFactoryEntry* entry = (nsFactoryEntry*)mFactories->Get(&key);
if (entry && entry->mServiceEntry) {
rv = entry->mServiceEntry->RemoveListener(shutdownListener);
serviceFound = PR_TRUE;
}
}
nsrefcnt cnt;
NS_RELEASE2(service, cnt);
// Consistency check: Service ref count cannot go to zero because of the
// extra addref the service manager does, unless the service has been
// unregistered (ie) not found in the service managers hash table.
//
NS_ASSERTION(cnt > 0 || !serviceFound,
"*** Service in hash table but is being deleted. Dangling pointer\n"
"*** in service manager hash table.");
return rv;
}
NS_IMETHODIMP
nsComponentManagerImpl::RegisterService(const nsCID& aClass, nsISupports* aService)
{
nsAutoMonitor mon(mMon);
// check to see if we have a factory entry for the service
nsIDKey key(aClass);
nsFactoryEntry *entry = GetFactoryEntry(aClass, key, 0);
if (!entry) { // XXXdougt - should we require that all services register factories?? probably not.
entry = new nsFactoryEntry(aClass, nsnull);
if (entry == NULL)
return NS_ERROR_OUT_OF_MEMORY;
entry->typeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY;
mFactories->Put(&key, entry);
}
else {
if (entry->mServiceEntry)
return NS_ERROR_FAILURE;
}
nsServiceEntry *serviceEntry = new nsServiceEntry(aService, entry); //owns a ref to aService
if (serviceEntry == NULL)
return NS_ERROR_OUT_OF_MEMORY;
entry->mServiceEntry = serviceEntry;
return NS_OK;
}
NS_IMETHODIMP
nsComponentManagerImpl::UnregisterService(const nsCID& aClass)
{
nsresult rv = NS_OK;
nsAutoMonitor mon(mMon);
nsIDKey key(aClass);
nsFactoryEntry* entry = (nsFactoryEntry*)mFactories->Get(&key);
if (entry == NULL || entry->mServiceEntry == NULL)
return NS_ERROR_SERVICE_NOT_FOUND;
delete entry->mServiceEntry;
entry->mServiceEntry = nsnull;
return rv;
}
NS_IMETHODIMP
nsComponentManagerImpl::RegisterService(const char* aContractID, nsISupports* aService)
{
nsAutoMonitor mon(mMon);
// check to see if we have a factory entry for the service
nsCStringKey key(aContractID);
nsFactoryEntry *entry = GetFactoryEntry(aContractID, 0);
if (entry == kNonExistentContractID)
entry = nsnull;
if (!entry) { // XXXdougt - should we require that all services register factories?? probably not.
entry = new nsFactoryEntry(kEmptyCID, nsnull);
if (entry == NULL)
return NS_ERROR_OUT_OF_MEMORY;
entry->typeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY;
mContractIDs->Put(&key, entry);
}
else {
if (entry->mServiceEntry)
return NS_ERROR_FAILURE;
}
nsServiceEntry *serviceEntry = new nsServiceEntry(aService, entry); //owns a ref to aService
if (serviceEntry == NULL)
return NS_ERROR_OUT_OF_MEMORY;
entry->mServiceEntry = serviceEntry;
return NS_OK;
}
NS_IMETHODIMP
nsComponentManagerImpl::UnregisterService(const char* aContractID)
{
nsresult rv = NS_OK;
nsAutoMonitor mon(mMon);
nsCStringKey key(aContractID);
nsFactoryEntry* entry = (nsFactoryEntry*)mFactories->Get(&key);
if (entry == NULL || entry == kNonExistentContractID || entry->mServiceEntry == NULL)
return NS_ERROR_SERVICE_NOT_FOUND;
delete entry->mServiceEntry;
entry->mServiceEntry = nsnull;
return rv;
}
NS_IMETHODIMP
nsComponentManagerImpl::GetService(const char* aContractID, const nsIID& aIID,
nsISupports* *result,
nsIShutdownListener* shutdownListener)
{
nsAutoMonitor mon(mMon);
// test this first, since there's no point in returning a service during
// shutdown -- whether it's available or not would depend on the order it
// occurs in the list
if (gShuttingDown) {
// When processing shutdown, dont process new GetService() requests
NS_WARNING("Creating new service on shutdown. Denied.");
return NS_ERROR_UNEXPECTED;
}
nsresult rv = NS_OK;
nsCStringKey key(aContractID);
nsFactoryEntry *entry = (nsFactoryEntry *) mContractIDs->Get(&key);
nsServiceEntry* serviceEntry;
if (entry && entry != kNonExistentContractID && entry->mServiceEntry) {
serviceEntry = entry->mServiceEntry;
if (!serviceEntry->mObject)
return NS_ERROR_NULL_POINTER;
nsISupports* service; // keep as raw point (avoid extra addref/release)
rv = serviceEntry->mObject->QueryInterface(aIID, (void**)&service);
if (NS_SUCCEEDED(rv)) {
// The refcount acquired in QI() above is "returned" to
// the caller.
if (shutdownListener) {
rv = serviceEntry->AddListener(shutdownListener);
if (NS_FAILED(rv)) {
NS_RELEASE(service);
return rv;
}
}
*result = service;
// If someone else requested the service to be shut down,
// and we just asked to get it again before it could be
// released, then cancel their shutdown request:
if (serviceEntry->mShuttingDown) {
serviceEntry->mShuttingDown = PR_FALSE;
NS_ADDREF(service); // Released in UnregisterService
}
}
return rv;
}
nsISupports* service;
// We need to not be holding the service manager's monitor while calling
// CreateInstance, because it invokes user code which could try to re-enter
// the service manager:
mon.Exit();
rv = CreateInstanceByContractID(aContractID, NULL, aIID, (void**)&service);
mon.Enter();
if (NS_FAILED(rv))
return rv;
if (!entry) { // second hash lookup for GetService
entry = (nsFactoryEntry*)mContractIDs->Get(&key);
NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
if (!entry) return NS_ERROR_FAILURE;
}
serviceEntry = new nsServiceEntry(service, entry);
if (serviceEntry == NULL) {
NS_RELEASE(service);
return NS_ERROR_OUT_OF_MEMORY;
}
if (shutdownListener) {
rv = serviceEntry->AddListener(shutdownListener);
if (NS_FAILED(rv)) {
NS_RELEASE(service);
delete serviceEntry;
return rv;
}
}
entry->mServiceEntry = serviceEntry; // deleted in nsFactoryEntry's destructor
*result = service; // transfer ownership
return rv;
}
NS_IMETHODIMP
nsComponentManagerImpl::ReleaseService(const char* aContractID, nsISupports* service,
nsIShutdownListener* shutdownListener)
{
PRBool serviceFound = PR_FALSE;
nsresult rv = NS_OK;
#ifndef NS_DEBUG
// Do entry lookup only if there is a shutdownlistener to be removed.
//
// For Debug builds, Consistency check for entry always. Releasing service
// when the service is not with the servicemanager is mostly wrong.
if (shutdownListener)
#endif
{
nsAutoMonitor mon(mMon);
nsCStringKey key(aContractID);
nsFactoryEntry* entry = (nsFactoryEntry*)mContractIDs->Get(&key);
if (entry && entry->mServiceEntry) {
rv = entry->mServiceEntry->RemoveListener(shutdownListener);
serviceFound = PR_TRUE;
}
}
nsrefcnt cnt;
NS_RELEASE2(service, cnt);
// Consistency check: Service ref count cannot go to zero because of the
// extra addref the service manager does, unless the service has been
// unregistered (ie) not found in the service managers hash table.
//
NS_ASSERTION(cnt > 0 || !serviceFound,
"*** Service in hash table but is being deleted. Dangling pointer\n"
"*** in service manager hash table.");
return rv;
}
/*
* I want an efficient way to allocate a buffer to the right size
* and stick the prefix and dllName in, then be able to hand that buffer
* off to the FactoryEntry. Is that so wrong?
*
* *regName is allocated on success.
*
* This should live in nsNativeComponentLoader.cpp, I think.
*/
static nsresult
MakeRegistryName(const char *aDllName, const char *prefix, char **regName)
{
char *registryName;
PRUint32 len = nsCRT::strlen(prefix);
PRUint32 registryNameLen = nsCRT::strlen(aDllName) + len;
registryName = (char *)nsMemory::Alloc(registryNameLen + 1);
// from here on it, we want len sans terminating NUL
if (!registryName)
return NS_ERROR_OUT_OF_MEMORY;
nsCRT::memcpy(registryName, prefix, len);
strcpy(registryName + len, aDllName); // no nsCRT::strcpy? for shame!
registryName[registryNameLen] = '\0';
*regName = registryName;
#ifdef DEBUG_shaver_off
fprintf(stderr, "MakeRegistryName(%s, %s, &[%s])\n",
aDllName, prefix, *regName);
#endif
return NS_OK;
}
nsresult
nsComponentManagerImpl::RegistryNameForLib(const char *aLibName,
char **aRegistryName)
{
return MakeRegistryName(aLibName, XPCOM_LIB_PREFIX, aRegistryName);
}
nsresult
2000-01-25 00:28:28 +03:00
nsComponentManagerImpl::RegistryLocationForSpec(nsIFile *aSpec,
char **aRegistryName)
{
nsresult rv;
2000-01-25 00:28:28 +03:00
if (!mComponentsDir)
return NS_ERROR_NOT_INITIALIZED;
if (!aSpec) {
*aRegistryName = nsCRT::strdup("");
return NS_OK;
}
2000-01-25 00:28:28 +03:00
PRBool containedIn;
2000-01-29 02:54:26 +03:00
mComponentsDir->Contains(aSpec, PR_TRUE, &containedIn);
2000-01-25 00:28:28 +03:00
char *persistentDescriptor;
if (containedIn){
rv = aSpec->GetPath(&persistentDescriptor);
2000-01-25 00:28:28 +03:00
if (NS_FAILED(rv))
return rv;
2000-02-01 10:54:46 +03:00
char* relativeLocation = persistentDescriptor + mComponentsOffset + 1;
rv = MakeRegistryName(relativeLocation, XPCOM_RELCOMPONENT_PREFIX,
aRegistryName);
} else {
/* absolute names include volume info on Mac, so persistent descriptor */
2000-01-25 00:28:28 +03:00
rv = aSpec->GetPath(&persistentDescriptor);
if (NS_FAILED(rv))
return rv;
rv = MakeRegistryName(persistentDescriptor, XPCOM_ABSCOMPONENT_PREFIX,
aRegistryName);
}
2000-01-25 00:28:28 +03:00
if (persistentDescriptor)
nsMemory::Free(persistentDescriptor);
return rv;
}
nsresult
nsComponentManagerImpl::SpecForRegistryLocation(const char *aLocation,
2000-01-25 00:28:28 +03:00
nsIFile **aSpec)
{
nsresult rv;
if (!aLocation || !aSpec)
return NS_ERROR_NULL_POINTER;
/* abs:/full/path/to/libcomponent.so */
if (!nsCRT::strncmp(aLocation, XPCOM_ABSCOMPONENT_PREFIX, 4)) {
2000-01-25 00:28:28 +03:00
nsLocalFile* file = new nsLocalFile;
if (!file) return NS_ERROR_FAILURE;
rv = file->InitWithPath(((char *)aLocation + 4));
file->QueryInterface(NS_GET_IID(nsILocalFile), (void**)aSpec);
return rv;
}
if (!nsCRT::strncmp(aLocation, XPCOM_RELCOMPONENT_PREFIX, 4)) {
2000-01-25 00:28:28 +03:00
if (!mComponentsDir)
return NS_ERROR_NOT_INITIALIZED;
nsILocalFile* file = nsnull;
rv = mComponentsDir->Clone((nsIFile**)&file);
if (NS_FAILED(rv)) return rv;
rv = file->AppendRelativePath(aLocation + 4);
2000-01-25 00:28:28 +03:00
*aSpec = file;
return rv;
}
*aSpec = nsnull;
return NS_ERROR_INVALID_ARG;
}
/**
* RegisterFactory()
*
* Register a factory to be responsible for creation of implementation of
* classID aClass. Plus creates as association of aClassName and aContractID
* to the classID. If replace is PR_TRUE, we replace any existing registrations
* with this one.
*
* Once registration is complete, we add the class to the factories cache
* that we maintain. The factories cache is the ONLY place where these
* registrations are ever kept.
*
* The other RegisterFunctions create a loader mapping and persistent
* location, but we just slam it into the cache here. And we don't call the
* loader's OnRegister function, either.
*/
nsresult
nsComponentManagerImpl::RegisterFactory(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
nsIFactory *aFactory,
PRBool aReplace)
{
nsFactoryEntry *entry = NULL;
nsIDKey key(aClass);
entry = GetFactoryEntry(aClass, key,
0 /* dont check registry */);
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
{
char *buf = aClass.ToString();
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("nsComponentManager: RegisterFactory(%s, %s)", buf,
(aContractID ? aContractID : "(null)")));
delete [] buf;
}
if (entry && !aReplace) {
// Already registered
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
("\t\tFactory already registered."));
return NS_ERROR_FACTORY_EXISTS;
}
if (entry) {
entry->ReInit(aClass, aFactory);
}
else {
entry = new nsFactoryEntry(aClass, aFactory);
if (entry == NULL)
return NS_ERROR_OUT_OF_MEMORY;
mFactories->Put(&key, entry);
}
// Update the ContractID->CLSID Map
if (aContractID) {
nsresult rv = HashContractID(aContractID, entry);
if(NS_FAILED(rv)) {
PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
("\t\tFactory register succeeded. "
"Hashing contractid (%s) FAILED.", aContractID));
return rv;
}
}
PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
("\t\tFactory register succeeded contractid=%s.",
aContractID ? aContractID : "<none>"));
return NS_OK;
}
nsresult
nsComponentManagerImpl::RegisterComponent(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
const char *aPersistentDescriptor,
PRBool aReplace,
PRBool aPersist)
{
return RegisterComponentCommon(aClass, aClassName, aContractID,
aPersistentDescriptor, aReplace, aPersist,
nativeComponentType);
1999-06-22 18:02:58 +04:00
}
nsresult
nsComponentManagerImpl::RegisterComponentWithType(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
2000-01-25 00:28:28 +03:00
nsIFile *aSpec,
const char *aLocation,
PRBool aReplace,
PRBool aPersist,
const char *aType)
{
return RegisterComponentCommon(aClass, aClassName, aContractID,
1999-11-19 05:14:23 +03:00
aLocation,
aReplace, aPersist,
aType);
}
1999-06-22 18:02:58 +04:00
/*
2000-01-25 00:28:28 +03:00
* Register a component, using whatever they stuck in the nsIFile.
*/
1999-06-22 18:02:58 +04:00
nsresult
nsComponentManagerImpl::RegisterComponentSpec(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
2000-01-25 00:28:28 +03:00
nsIFile *aLibrarySpec,
1999-06-22 18:02:58 +04:00
PRBool aReplace,
PRBool aPersist)
{
1999-11-19 05:14:23 +03:00
nsXPIDLCString registryName;
nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName));
if (NS_FAILED(rv))
return rv;
rv = RegisterComponentWithType(aClass, aClassName, aContractID, aLibrarySpec,
registryName,
aReplace, aPersist,
nativeComponentType);
return rv;
}
/*
* Register a ``library'', which is a DLL location named by a simple filename
* such as ``libnsappshell.so'', rather than a relative or absolute path.
*
* It implies application/x-moz-dll as the component type, and skips the
* FindLoaderForType phase.
*/
nsresult
nsComponentManagerImpl::RegisterComponentLib(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
const char *aDllName,
PRBool aReplace,
PRBool aPersist)
{
1999-11-19 05:14:23 +03:00
nsXPIDLCString registryName;
nsresult rv = RegistryNameForLib(aDllName, getter_Copies(registryName));
if (NS_FAILED(rv))
return rv;
return RegisterComponentCommon(aClass, aClassName, aContractID, registryName,
aReplace, aPersist, nativeComponentType);
}
/*
* Add a component to the known universe of components.
* Once we enter this function, we own aRegistryName, and must free it
* or hand it to nsFactoryEntry. Common exit point ``out'' helps keep us
* sane.
*/
nsresult
nsComponentManagerImpl::RegisterComponentCommon(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
1999-11-19 05:14:23 +03:00
const char *aRegistryName,
PRBool aReplace,
PRBool aPersist,
const char *aType)
{
nsresult rv = NS_OK;
nsIDKey key(aClass);
nsFactoryEntry *entry = GetFactoryEntry(aClass, !mPrePopulationDone);
// Normalize proid and classname
const char *contractID = (aContractID && *aContractID) ? aContractID : NULL;
const char *className = (aClassName && *aClassName) ? aClassName : NULL;
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
{
char *buf = aClass.ToString();
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
("nsComponentManager: RegisterComponentCommon(%s, %s, %s, %s)",
buf,
contractID ? contractID : "(null)",
aRegistryName, aType));
delete [] buf;
}
if (entry && !aReplace) {
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
("\t\tFactory already registered."));
return NS_ERROR_FACTORY_EXISTS;
}
#ifdef USE_REGISTRY
if (aPersist) {
/* Add to the registry */
rv = AddComponentToRegistry(aClass, className, contractID,
aRegistryName, aType);
if (NS_FAILED(rv)) {
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
("\t\tadding %s %s to registry FAILED", className, contractID));
return rv;
}
}
#endif
int typeIndex = GetLoaderType(aType);
nsCOMPtr<nsIComponentLoader> loader;
rv = GetLoaderForType(typeIndex, getter_AddRefs(loader));
if (NS_FAILED(rv)) {
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
("\t\tgetting loader for %s FAILED\n", aType));
return rv;
1999-06-22 18:02:58 +04:00
}
if (entry) {
entry->ReInit(aClass, aRegistryName, typeIndex);
}
else {
entry = new nsFactoryEntry(aClass, aRegistryName, typeIndex);
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
mFactories->Put(&key, entry);
}
// Update the ContractID->CLSID Map
if (contractID
1999-06-22 18:02:58 +04:00
#ifdef USE_REGISTRY
&& (mPrePopulationDone || !aPersist)
#endif
) {
rv = HashContractID(contractID, entry);
if (NS_FAILED(rv)) {
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
("\t\tHashContractID(%s) FAILED\n", contractID));
return rv;
}
}
// Let the loader do magic things now
rv = loader->OnRegister(aClass, aType, className, contractID, aRegistryName,
aReplace, aPersist);
if (NS_FAILED(rv)) {
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
("\t\tloader->OnRegister FAILED for %s \"%s\" %s %s", aType,
className, contractID, aRegistryName));
return rv;
}
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("\t\tRegisterComponentCommon() %s",
NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1999-06-22 18:02:58 +04:00
return rv;
}
nsresult
nsComponentManagerImpl::GetLoaderForType(int aType,
nsIComponentLoader **aLoader)
1999-06-22 18:02:58 +04:00
{
nsresult rv;
1999-06-22 18:02:58 +04:00
// Make sure we have a valid type
if (aType < 0 || aType >= mNLoaderData)
return NS_ERROR_INVALID_ARG;
*aLoader = mLoaderData[aType].loader;
if (*aLoader) {
NS_ADDREF(*aLoader);
return NS_OK;
1999-06-22 18:02:58 +04:00
}
nsCOMPtr<nsIComponentLoader> loader;
loader = do_GetServiceFromCategory("component-loader", mLoaderData[aType].type, &rv);
if (NS_FAILED(rv))
return rv;
rv = loader->Init(this, mRegistry);
if (NS_SUCCEEDED(rv)) {
mLoaderData[aType].loader = loader;
NS_ADDREF(mLoaderData[aType].loader);
*aLoader = loader;
NS_ADDREF(*aLoader);
1999-06-22 18:02:58 +04:00
}
return rv;
}
1999-06-22 18:02:58 +04:00
nsresult
nsComponentManagerImpl::AddComponentToRegistry(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
const char *aRegistryName,
const char *aType)
{
nsresult rv;
PRUint32 length = strlen(aRegistryName);
char* eRegistryName;
rv = mRegistry->EscapeKey((PRUint8*)aRegistryName, 1, &length, (PRUint8**)&eRegistryName);
if (rv != NS_OK)
{
return rv;
}
if (eRegistryName == nsnull) // No escaping required
eRegistryName = (char*)aRegistryName;
nsRegistryKey IDKey;
PRInt32 nComponents = 0;
/* so why do we use strings here rather than writing bytes, anyway? */
char *cidString = aClass.ToString();
if (!cidString)
return NS_ERROR_OUT_OF_MEMORY;
rv = mRegistry->AddSubtreeRaw(mCLSIDKey, cidString, &IDKey);
if (NS_FAILED(rv))
goto out;
if (aClassName) {
rv = mRegistry->SetStringUTF8(IDKey, classNameValueName, aClassName);
if (NS_FAILED(rv))
goto out;
}
rv = mRegistry->SetBytesUTF8(IDKey, inprocServerValueName,
strlen(aRegistryName) + 1,
(PRUint8*)aRegistryName);
if (NS_FAILED(rv))
goto out;
rv = mRegistry->SetStringUTF8(IDKey, componentTypeValueName, aType);
if (NS_FAILED(rv))
goto out;
if (aContractID) {
rv = mRegistry->SetStringUTF8(IDKey, contractIDValueName, aContractID);
if (NS_FAILED(rv))
goto out;
nsRegistryKey contractIDKey;
rv = mRegistry->AddSubtreeRaw(mClassesKey, aContractID, &contractIDKey);
if (NS_FAILED(rv))
goto out;
rv = mRegistry->SetStringUTF8(contractIDKey, classIDValueName, cidString);
if (NS_FAILED(rv))
goto out;
}
nsRegistryKey compKey;
rv = mRegistry->AddSubtreeRaw(mXPCOMKey, eRegistryName, &compKey);
// update component count
rv = mRegistry->GetInt(compKey, componentCountValueName, &nComponents);
nComponents++;
rv = mRegistry->SetInt(compKey, componentCountValueName, nComponents);
if (NS_FAILED(rv))
goto out;
out:
// XXX if failed, undo registry adds or set invalid bit? How?
nsCRT::free(cidString);
if (eRegistryName != aRegistryName)
nsMemory::Free(eRegistryName);
return rv;
}
nsresult
nsComponentManagerImpl::UnregisterFactory(const nsCID &aClass,
nsIFactory *aFactory)
{
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
{
char *buf = aClass.ToString();
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
("nsComponentManager: UnregisterFactory(%s)", buf));
delete [] buf;
}
nsIDKey key(aClass);
nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED;
nsFactoryEntry *old = GetFactoryEntry(aClass, key,
0 /* dont check registry */);
if (old != NULL)
{
if (old->factory.get() == aFactory)
{
PR_EnterMonitor(mMon);
old = (nsFactoryEntry *) mFactories->RemoveAndDelete(&key);
old = NULL;
PR_ExitMonitor(mMon);
res = NS_OK;
}
}
PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
("\t\tUnregisterFactory() %s",
NS_SUCCEEDED(res) ? "succeeded" : "FAILED"));
return res;
}
nsresult
nsComponentManagerImpl::UnregisterComponent(const nsCID &aClass,
const char *registryName)
{
nsresult rv = NS_OK;
NS_ENSURE_ARG_POINTER(registryName);
PR_EnterMonitor(mMon);
2000-04-18 09:25:05 +04:00
// Remove any stored factory entries
nsIDKey key(aClass);
nsFactoryEntry *entry = GetFactoryEntry(aClass, key,
0 /* dont check registry */);
if (entry && entry->location && !PL_strcasecmp(entry->location, registryName))
{
2000-04-18 09:25:05 +04:00
mFactories->RemoveAndDelete(&key);
entry = NULL;
}
#ifdef USE_REGISTRY
2000-04-18 09:25:05 +04:00
// Remove registry entries for this cid
char *cidString = aClass.ToString();
rv = PlatformUnregister(cidString, registryName);
delete [] cidString;
#endif
PR_ExitMonitor(mMon);
PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
("nsComponentManager: Factory unregister(%s) %s.", registryName,
2000-04-18 09:25:05 +04:00
NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
return rv;
}
nsresult
nsComponentManagerImpl::UnregisterComponentSpec(const nsCID &aClass,
nsIFile *aLibrarySpec)
{
nsXPIDLCString registryName;
nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName));
if (NS_FAILED(rv)) return rv;
return UnregisterComponent(aClass, registryName);
}
// XXX Need to pass in aWhen and servicemanager
nsresult
nsComponentManagerImpl::FreeLibraries(void)
{
nsIServiceManager* serviceMgr = NULL;
nsresult rv = nsServiceManager::GetGlobalServiceManager(&serviceMgr);
if (NS_FAILED(rv)) return rv;
rv = UnloadLibraries(serviceMgr, NS_Timer); // XXX when
return rv;
}
// Private implementation of unloading libraries
nsresult
nsComponentManagerImpl::UnloadLibraries(nsIServiceManager *serviceMgr, PRInt32 aWhen)
{
nsresult rv = NS_OK;
PR_EnterMonitor(mMon);
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
("nsComponentManager: Unloading Libraries."));
1999-09-23 04:14:00 +04:00
// UnloadAll the loaders
/* iterate over all known loaders and ask them to autoregister. */
// Skip mNativeComponentLoader
for (int i=NS_COMPONENT_TYPE_NATIVE + 1; i<mNLoaderData; i++) {
if (mLoaderData[i].loader) {
rv = mLoaderData[i].loader->UnloadAll(aWhen);
if (NS_FAILED(rv))
break;
}
}
// UnloadAll the native loader
rv = mNativeComponentLoader->UnloadAll(aWhen);
PR_ExitMonitor(mMon);
return rv;
}
////////////////////////////////////////////////////////////////////////////////
/**
1999-04-03 00:28:22 +04:00
* AutoRegister(RegistrationInstant, const char *directory)
*
1999-04-03 00:28:22 +04:00
* Given a directory in the following format, this will ensure proper registration
* of all components. No default director is looked at.
*
* Directory and fullname are what NSPR will accept. For eg.
* WIN y:/home/dp/mozilla/dist/bin
* UNIX /home/dp/mozilla/dist/bin
* MAC /Hard drive/mozilla/dist/apprunner
*
* This will take care not loading already registered dlls, finding and
* registering new dlls, re-registration of modified dlls
*
*/
nsresult
2000-01-25 00:28:28 +03:00
nsComponentManagerImpl::AutoRegister(PRInt32 when, nsIFile *inDirSpec)
{
nsresult rv;
mRegistry->SetBufferSize( 500*1024 );
rv = AutoRegisterImpl(when, inDirSpec);
mRegistry->Flush();
//mRegistry->SetBufferSize( 10*1024 );
return rv;
}
nsresult
nsComponentManagerImpl::AutoRegisterImpl(PRInt32 when, nsIFile *inDirSpec)
{
2000-01-25 00:28:28 +03:00
nsCOMPtr<nsIFile> dir;
1999-06-22 18:02:58 +04:00
nsresult rv;
#ifdef DEBUG
// testing release behaviour
if (getenv("XPCOM_NO_AUTOREG"))
return NS_OK;
#endif
if (inDirSpec)
{
// Use supplied components' directory
dir = inDirSpec;
// Set components' directory for AutoRegisterInterfces to query
nsCOMPtr<nsIProperties> directoryService =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
// Don't care if undefining fails
directoryService->Undefine(NS_XPCOM_COMPONENT_DIR);
rv = directoryService->Define(NS_XPCOM_COMPONENT_DIR, dir);
if (NS_FAILED(rv)) return rv;
}
else
{
// Do default components directory
nsCOMPtr<nsIProperties> directoryService =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
2000-01-25 00:28:28 +03:00
if (NS_FAILED(rv)) return rv;
rv = directoryService->Get(NS_XPCOM_COMPONENT_DIR, NS_GET_IID(nsIFile), getter_AddRefs(dir));
if (NS_FAILED(rv)) return rv; // XXX translate error code?
}
1999-06-22 18:02:58 +04:00
nsCOMPtr<nsIInterfaceInfoManager> iim =
dont_AddRef(XPTI_GetInterfaceInfoManager());
if (!iim)
return NS_ERROR_UNEXPECTED;
// Notify observers of xpcom autoregistration start
nsCOMPtr<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv))
{
nsIServiceManager *mgr; // NO COMPtr as we dont release the service manager
rv = nsServiceManager::GetGlobalServiceManager(&mgr);
if (NS_SUCCEEDED(rv))
{
(void) observerService->Notify(mgr,
NS_ConvertASCIItoUCS2(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID).get(),
NS_ConvertASCIItoUCS2("Starting component registration").get());
}
}
/* do the native loader first, so we can find other loaders */
rv = mNativeComponentLoader->AutoRegisterComponents((PRInt32)when, dir);
if (NS_FAILED(rv)) return rv;
#ifdef ENABLE_STATIC_COMPONENT_LOADER
rv = mStaticComponentLoader->AutoRegisterComponents((PRInt32)when, dir);
if (NS_FAILED(rv)) return rv;
#endif
/* do InterfaceInfoManager after native loader so it can use components. */
rv = iim->AutoRegisterInterfaces();
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsICategoryManager> catman =
do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISimpleEnumerator> loaderEnum;
rv = catman->EnumerateCategory("component-loader",
getter_AddRefs(loaderEnum));
if (NS_FAILED(rv)) return rv;
PRBool hasMore;
while (NS_SUCCEEDED(loaderEnum->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
if (NS_FAILED(loaderEnum->GetNext(getter_AddRefs(supports))))
continue;
nsCOMPtr<nsISupportsString> supStr = do_QueryInterface(supports);
if (!supStr)
continue;
nsXPIDLCString loaderType;
if (NS_FAILED(supStr->GetData(getter_Copies(loaderType))))
continue;
// We depend on the loader being created. Add the loader type and
// create the loader object too.
nsCOMPtr<nsIComponentLoader> loader;
GetLoaderForType(AddLoaderType(loaderType), getter_AddRefs(loader));
}
/* iterate over all known loaders and ask them to autoregister. */
/* XXX convert when to nsIComponentLoader::(when) properly */
nsIFile *spec = dir.get();
for (int i = NS_COMPONENT_TYPE_NATIVE + 1; i < mNLoaderData; i++) {
rv = mLoaderData[i].loader->AutoRegisterComponents(when, spec);
if (NS_FAILED(rv))
break;
}
if (NS_SUCCEEDED(rv))
{
PRBool registered;
do {
registered = PR_FALSE;
for (int i = NS_COMPONENT_TYPE_NATIVE; i < mNLoaderData; i++) {
PRBool b = PR_FALSE;
rv = mLoaderData[i].loader->RegisterDeferredComponents(when, &b);
if (NS_FAILED(rv))
break;
registered |= b;
}
} while (NS_SUCCEEDED(rv) && registered);
}
nsIServiceManager *mgr; // NO COMPtr as we dont release the service manager
rv = nsServiceManager::GetGlobalServiceManager(&mgr);
if (NS_SUCCEEDED(rv))
{
(void) observerService->Notify(mgr,
NS_ConvertASCIItoUCS2(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID).get(),
NS_ConvertASCIItoUCS2("Component registration finished").get());
}
return rv;
}
nsresult
1999-09-05 10:27:42 +04:00
nsComponentManagerImpl::AutoRegisterComponent(PRInt32 when,
2000-01-25 00:28:28 +03:00
nsIFile *component)
{
nsresult rv = NS_OK;
/*
* Do we have to give the native loader first crack at it?
* I vote ``no''.
*/
for (int i = 0; i < mNLoaderData; i++) {
PRBool didRegister;
rv = mLoaderData[i].loader->AutoRegisterComponent((int)when, component, &didRegister);
if (NS_SUCCEEDED(rv) && didRegister)
break;
}
return NS_FAILED(rv) ? NS_ERROR_FACTORY_NOT_REGISTERED : NS_OK;
1999-08-09 09:40:51 +04:00
}
2000-04-18 09:25:05 +04:00
nsresult
nsComponentManagerImpl::AutoUnregisterComponent(PRInt32 when,
nsIFile *component)
{
nsresult rv = NS_OK;
for (int i = 0; i < mNLoaderData; i++) {
PRBool didUnRegister;
rv = mLoaderData[i].loader->AutoUnregisterComponent(when, component, &didUnRegister);
if (NS_SUCCEEDED(rv) && didUnRegister)
break;
}
return NS_FAILED(rv) ? NS_ERROR_FACTORY_NOT_REGISTERED : NS_OK;
2000-04-18 09:25:05 +04:00
}
nsresult
nsComponentManagerImpl::IsRegistered(const nsCID &aClass,
PRBool *aRegistered)
{
if(!aRegistered)
{
NS_ASSERTION(0, "null ptr");
return NS_ERROR_NULL_POINTER;
}
*aRegistered = (nsnull != GetFactoryEntry(aClass));
return NS_OK;
}
static NS_IMETHODIMP
ConvertFactoryEntryToCID(nsHashKey *key, void *data, void *convert_data,
nsISupports **retval)
{
nsComponentManagerImpl *compMgr = (nsComponentManagerImpl*) convert_data;
nsresult rv;
nsISupportsID* cidHolder;
1999-09-05 10:27:42 +04:00
if(NS_SUCCEEDED(rv =
compMgr->CreateInstanceByContractID(NS_SUPPORTS_ID_CONTRACTID,
1999-09-05 10:27:42 +04:00
nsnull,
NS_GET_IID(nsISupportsID),
(void **)&cidHolder)))
{
nsFactoryEntry *fe = (nsFactoryEntry *) data;
cidHolder->SetData(&fe->cid);
*retval = cidHolder;
}
else
*retval = nsnull;
return rv;
}
static NS_IMETHODIMP
ConvertContractIDKeyToString(nsHashKey *key, void *data, void *convert_data,
nsISupports **retval)
{
nsComponentManagerImpl *compMgr = (nsComponentManagerImpl*) convert_data;
nsresult rv;
nsISupportsString* strHolder;
1999-09-05 10:27:42 +04:00
rv = compMgr->CreateInstanceByContractID(NS_SUPPORTS_STRING_CONTRACTID, nsnull,
1999-09-05 10:27:42 +04:00
NS_GET_IID(nsISupportsString),
(void **)&strHolder);
if(NS_SUCCEEDED(rv))
{
nsCStringKey *strKey = (nsCStringKey *) key;
strHolder->SetData(strKey->GetString());
*retval = strHolder;
}
else
*retval = nsnull;
return rv;
}
nsresult
nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator** aEmumerator)
{
if(!aEmumerator)
{
NS_ASSERTION(0, "null ptr");
return NS_ERROR_NULL_POINTER;
}
*aEmumerator = nsnull;
nsresult rv;
if(!mPrePopulationDone)
{
rv = PlatformPrePopulateRegistry();
if(NS_FAILED(rv))
return rv;
}
return NS_NewHashtableEnumerator(mFactories, ConvertFactoryEntryToCID,
this, aEmumerator);
}
nsresult
nsComponentManagerImpl::EnumerateContractIDs(nsIEnumerator** aEmumerator)
{
if(!aEmumerator)
{
NS_ASSERTION(0, "null ptr");
return NS_ERROR_NULL_POINTER;
}
*aEmumerator = nsnull;
nsresult rv;
if(!mPrePopulationDone)
{
rv = PlatformPrePopulateRegistry();
if(NS_FAILED(rv))
return rv;
}
return NS_NewHashtableEnumerator(mContractIDs, ConvertContractIDKeyToString,
this, aEmumerator);
}
nsresult
nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result)
{
nsresult rv = NS_OK;
if (uuid.Equals(NS_GET_IID(nsIServiceManager)))
{
// Return the global service manager
rv = nsServiceManager::GetGlobalServiceManager((nsIServiceManager **)result);
}
else
{
// fall through to QI as anything QIable is a superset of what canbe
// got via the GetInterface()
rv = QueryInterface(uuid, result);
}
return rv;
}
// Convert a loader type string into an index into the component data
// array. Empty loader types are converted to NATIVE. Returns -1 if
// loader type cannot be determined.
int
nsComponentManagerImpl::GetLoaderType(const char *typeStr)
{
if (!typeStr || !*typeStr) {
// Empty type strings are NATIVE
return NS_COMPONENT_TYPE_NATIVE;
}
for (int i=NS_COMPONENT_TYPE_NATIVE; i<mNLoaderData; i++) {
if (!strcmp(typeStr, mLoaderData[i].type))
return i;
}
// Not found
return NS_COMPONENT_TYPE_FACTORY_ONLY;
}
// Add a loader type if not already known. Return the typeIndex
// if the loader type is either added or already there.
int
nsComponentManagerImpl::AddLoaderType(const char *typeStr)
{
int typeIndex = GetLoaderType(typeStr);
if (typeIndex >= 0) {
return typeIndex;
}
// Add the loader type
if (mNLoaderData >= mMaxNLoaderData) {
NS_ASSERTION(mNLoaderData == mMaxNLoaderData,
"Memory corruption. nsComponentManagerImpl::mLoaderData array overrun.");
// Need to increase our loader array
nsLoaderdata *new_mLoaderData = (nsLoaderdata *) PR_Realloc(mLoaderData, (mMaxNLoaderData + NS_LOADER_DATA_ALLOC_STEP) * sizeof(nsLoaderdata));
if (!new_mLoaderData)
return NS_ERROR_OUT_OF_MEMORY;
mLoaderData = new_mLoaderData;
mMaxNLoaderData += NS_LOADER_DATA_ALLOC_STEP;
}
typeIndex = mNLoaderData;
mLoaderData[typeIndex].type = PL_strdup(typeStr);
if (!mLoaderData[typeIndex].type) {
// mmh! no memory. return failure.
return NS_ERROR_OUT_OF_MEMORY;
}
mLoaderData[typeIndex].loader = nsnull;
mNLoaderData++;
return typeIndex;
}
////////////////////////////////////////////////////////////////////////////////
NS_COM nsresult
NS_GetGlobalComponentManager(nsIComponentManager* *result)
{
nsresult rv = NS_OK;
if (nsComponentManagerImpl::gComponentManager == NULL)
{
// XPCOM needs initialization.
I know it's unorthodox to do a top level checkin like this, but I've got so many files in so many different directories, that I think it's the best way. I've pulled and clobber_all'd my tree and got r=dp on this checkin. Here are the touched files: M mozilla/embedding/browser/activex/src/control/MozillaBrowser.cpp M mozilla/embedding/browser/activex/src/control/MozillaBrowser.h M mozilla/js/src/xpconnect/shell/xpcshell.cpp M mozilla/netwerk/protocol/res/src/nsResProtocolHandler.cpp M mozilla/xpcom/build/nsXPComInit.cpp M mozilla/xpcom/components/nsComponentManager.cpp M mozilla/xpcom/components/nsIServiceManager.h M mozilla/xpcom/components/nsServiceManager.cpp M mozilla/xpcom/io/nsSpecialSystemDirectory.cpp M mozilla/xpcom/io/nsSpecialSystemDirectory.h M mozilla/xpcom/tests/TestBuffers.cpp M mozilla/xpcom/tests/TestPipes.cpp M mozilla/xpcom/tests/TestShutdown.cpp M mozilla/xpcom/tests/windows/TestHelloXPLoop.cpp M mozilla/xpcom/tools/registry/regExport.cpp M mozilla/xpcom/tools/registry/regxpcom.cpp M mozilla/xpinstall/stub/xpistub.cpp M mozilla/webshell/embed/ActiveX/MozillaBrowser.cpp M mozilla/webshell/embed/ActiveX/MozillaBrowser.h M mozilla/webshell/tests/viewer/nsMacMain.cpp M mozilla/webshell/tests/viewer/nsPhMain.cpp M mozilla/webshell/tests/viewer/nsWinMain.cpp M mozilla/webshell/tests/viewer/unix/gtk/nsGtkMain.cpp M mozilla/xpfe/appshell/src/nsFileLocations.cpp M mozilla/xpfe/bootstrap/nsAppRunner.cpp The heart of this checkin is a change in the signature and symantics of NS_InitXPCOM. The new signature is extern NS_COM nsresult NS_InitXPCOM(nsIServiceManager* *result, nsFileSpec* binDirectory); I filed a bug for this problem: b=23157 The original manifestation of this bug was in mozilla/netwerk/protocol/res/src/nsResProtocolHandler.cpp It used the current process directory to find resources, which is not correct when the current process is not mozilla.exe. I have added a new type to nsSpecialSystemDirectory, Moz_BinDirectory, and made nsResProtocolHandler use that value.
2000-01-06 04:05:13 +03:00
rv = NS_InitXPCOM(NULL, NULL);
}
if (NS_SUCCEEDED(rv))
{
// NO ADDREF since this is never intended to be released.
*result = nsComponentManagerImpl::gComponentManager;
}
return rv;
}
////////////////////////////////////////////////////////////////////////////////
// Global component manager interface
nsresult
nsComponentManager::Initialize(void)
{
return NS_OK;
}
nsresult
nsComponentManager::FindFactory(const nsCID &aClass,
nsIFactory **aFactory)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->FindFactory(aClass, aFactory);
}
nsresult
nsComponentManager::GetClassObject(const nsCID &aClass, const nsIID &aIID,
void **aResult)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->GetClassObject(aClass, aIID, aResult);
}
nsresult
nsComponentManager::ContractIDToClassID(const char *aContractID,
nsCID *aClass)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->ContractIDToClassID(aContractID, aClass);
}
nsresult
nsComponentManager::CLSIDToContractID(nsCID *aClass,
char* *aClassName,
char* *aContractID)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->CLSIDToContractID(*aClass, aClassName, aContractID);
}
nsresult
nsComponentManager::CreateInstance(const nsCID &aClass,
nsISupports *aDelegate,
const nsIID &aIID,
void **aResult)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->CreateInstance(aClass, aDelegate, aIID, aResult);
}
nsresult
nsComponentManager::CreateInstance(const char *aContractID,
nsISupports *aDelegate,
const nsIID &aIID,
void **aResult)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->CreateInstanceByContractID(aContractID, aDelegate, aIID, aResult);
}
nsresult
nsComponentManager::RegisterFactory(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
nsIFactory *aFactory,
PRBool aReplace)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->RegisterFactory(aClass, aClassName, aContractID,
aFactory, aReplace);
}
nsresult
nsComponentManager::RegisterComponent(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
const char *aLibraryPersistentDescriptor,
PRBool aReplace,
PRBool aPersist)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->RegisterComponent(aClass, aClassName, aContractID,
aLibraryPersistentDescriptor, aReplace, aPersist);
}
nsresult
nsComponentManager::RegisterComponentSpec(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
nsIFile *aLibrary,
PRBool aReplace,
PRBool aPersist)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->RegisterComponentSpec(aClass, aClassName, aContractID,
aLibrary, aReplace, aPersist);
}
nsresult
nsComponentManager::RegisterComponentLib(const nsCID &aClass,
const char *aClassName,
const char *aContractID,
const char *adllName,
PRBool aReplace,
PRBool aPersist)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->RegisterComponentLib(aClass, aClassName, aContractID,
adllName, aReplace, aPersist);
}
nsresult
nsComponentManager::UnregisterFactory(const nsCID &aClass,
nsIFactory *aFactory)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->UnregisterFactory(aClass, aFactory);
}
nsresult
nsComponentManager::UnregisterComponent(const nsCID &aClass,
const char *aLibrary)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->UnregisterComponent(aClass, aLibrary);
}
nsresult
nsComponentManager::UnregisterComponentSpec(const nsCID &aClass,
nsIFile *aLibrarySpec)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->UnregisterComponentSpec(aClass, aLibrarySpec);
}
nsresult
nsComponentManager::FreeLibraries(void)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->FreeLibraries();
}
nsresult
nsComponentManager::AutoRegister(PRInt32 when, nsIFile *directory)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->AutoRegister(when, directory);
}
nsresult
nsComponentManager::AutoRegisterComponent(PRInt32 when,
nsIFile *fullname)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->AutoRegisterComponent(when, fullname);
}
nsresult
nsComponentManager::AutoUnregisterComponent(PRInt32 when,
nsIFile *fullname)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->AutoUnregisterComponent(when, fullname);
}
nsresult
nsComponentManager::IsRegistered(const nsCID &aClass,
PRBool *aRegistered)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->IsRegistered(aClass, aRegistered);
}
nsresult
nsComponentManager::EnumerateCLSIDs(nsIEnumerator** aEmumerator)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->EnumerateCLSIDs(aEmumerator);
}
nsresult
nsComponentManager::EnumerateContractIDs(nsIEnumerator** aEmumerator)
{
nsIComponentManager* cm;
nsresult rv = NS_GetGlobalComponentManager(&cm);
if (NS_FAILED(rv)) return rv;
return cm->EnumerateContractIDs(aEmumerator);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Global service manager interface (see nsIServiceManager.h)
nsresult
nsServiceManager::GetGlobalServiceManager(nsIServiceManager* *result)
{
if (gShuttingDown)
return NS_ERROR_UNEXPECTED;
nsresult rv = NS_OK;
if (gServiceManager == NULL) {
// XPCOM not initialized yet. Let us do initialization of our module.
rv = NS_InitXPCOM(NULL, NULL);
}
// No ADDREF as we are advicing no release of this.
if (NS_SUCCEEDED(rv))
*result = gServiceManager;
return rv;
}
nsresult
nsServiceManager::ShutdownGlobalServiceManager(nsIServiceManager* *result)
{
if (gServiceManager != NULL) {
nsrefcnt cnt;
nsComponentManagerImpl* compImpl = NS_STATIC_CAST(nsComponentManagerImpl*, gServiceManager);
compImpl->FreeServices();
NS_RELEASE2(gServiceManager, cnt);
// the only reference at this point should be the component manager.
NS_ASSERTION(cnt == 1, "Service Manager being held past XPCOM shutdown.");
gServiceManager = NULL;
}
return NS_OK;
}
nsresult
nsServiceManager::GetService(const nsCID& aClass, const nsIID& aIID,
nsISupports* *result,
nsIShutdownListener* shutdownListener)
{
nsIServiceManager* mgr;
nsresult rv = GetGlobalServiceManager(&mgr);
if (NS_FAILED(rv)) return rv;
return mgr->GetService(aClass, aIID, result, shutdownListener);
}
nsresult
nsServiceManager::ReleaseService(const nsCID& aClass, nsISupports* service,
nsIShutdownListener* shutdownListener)
{
// Don't create the global service manager here because we might be shutting
// down, and releasing all the services in its destructor
if (gServiceManager)
return gServiceManager->ReleaseService(aClass, service, shutdownListener);
// If there wasn't a global service manager, just release the object:
NS_RELEASE(service);
return NS_OK;
}
nsresult
nsServiceManager::RegisterService(const nsCID& aClass, nsISupports* aService)
{
nsIServiceManager* mgr;
nsresult rv = GetGlobalServiceManager(&mgr);
if (NS_FAILED(rv)) return rv;
return mgr->RegisterService(aClass, aService);
}
nsresult
nsServiceManager::UnregisterService(const nsCID& aClass)
{
nsIServiceManager* mgr;
nsresult rv = GetGlobalServiceManager(&mgr);
if (NS_FAILED(rv)) return rv;
return mgr->UnregisterService(aClass);
}
////////////////////////////////////////////////////////////////////////////////
// let's do it again, this time with ContractIDs...
nsresult
nsServiceManager::GetService(const char* aContractID, const nsIID& aIID,
nsISupports* *result,
nsIShutdownListener* shutdownListener)
{
nsIServiceManager* mgr;
nsresult rv = GetGlobalServiceManager(&mgr);
if (NS_FAILED(rv)) return rv;
return mgr->GetService(aContractID, aIID, result, shutdownListener);
}
nsresult
nsServiceManager::ReleaseService(const char* aContractID, nsISupports* service,
nsIShutdownListener* shutdownListener)
{
// Don't create the global service manager here because we might
// be shutting down, and releasing all the services in its
// destructor
if (gServiceManager)
return gServiceManager->ReleaseService(aContractID, service, shutdownListener);
// If there wasn't a global service manager, just release the object:
NS_RELEASE(service);
return NS_OK;
}
nsresult
nsServiceManager::RegisterService(const char* aContractID, nsISupports* aService)
{
nsIServiceManager* mgr;
nsresult rv = GetGlobalServiceManager(&mgr);
if (NS_FAILED(rv)) return rv;
return mgr->RegisterService(aContractID, aService);
}
nsresult
nsServiceManager::UnregisterService(const char* aContractID)
{
// Don't create the global service manager here because we might
// be shutting down, and releasing all the services in its
// destructor
if (gServiceManager)
return gServiceManager->UnregisterService(aContractID);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////