mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 05:35:31 +00:00
849d297364
a) create a new nsIComponentManager with only four functions on it: CreateInstance CreateInstanceByContractID GetClassInfo GetClassInfoByContractID. b) rename the old nsIComponentManager to nsIComponentManagerObsolete. c) fixes callers which use to access the nsIComponentManager for component registration functionality. These callers will temporary use the nsIComponentManagerObsolete interface. d) Create a new API NS_GetComponentManager() which mirrors the NS_GetServiceManager() e) Perserves the old NS_GetGlobalComponentManager(). Note the cast usage. r/sr = rpotts@netscape.com alecf@netscape.com brendan@mozilla.org
3344 lines
101 KiB
C++
3344 lines
101 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
|
|
*/
|
|
#include <stdlib.h>
|
|
#include "nscore.h"
|
|
#include "nsISupports.h"
|
|
#include "nsCRT.h"
|
|
#include "nspr.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"
|
|
|
|
#include "nsCOMPtr.h"
|
|
#include "nsComponentManager.h"
|
|
#include "nsComponentManagerObsolete.h"
|
|
#include "nsICategoryManager.h"
|
|
|
|
#include "nsIEnumerator.h"
|
|
#include "nsIModule.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsIComponentLoader.h"
|
|
#include "nsNativeComponentLoader.h"
|
|
#include "nsXPIDLString.h"
|
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#include "nsLocalFile.h"
|
|
#include "nsDirectoryService.h"
|
|
#include "nsDirectoryServiceDefs.h"
|
|
|
|
#include "NSReg.h"
|
|
|
|
#include "prcmon.h"
|
|
#include "prthread.h" /* XXX: only used for the NSPR initialization hack (rick) */
|
|
|
|
#ifdef XP_BEOS
|
|
#include <FindDirectory.h>
|
|
#include <Path.h>
|
|
#endif
|
|
|
|
#include "nsRegistry.h"
|
|
|
|
// Logging of debug output
|
|
#ifdef MOZ_LOGGING
|
|
#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
|
|
|
|
// Bloated registry buffer size to improve startup performance -- needs to
|
|
// be big enough to fit the entire file into memory or it'll thrash.
|
|
// 512K is big enough to allow for some future growth in the registry.
|
|
#define BIG_REGISTRY_BUFLEN (512*1024)
|
|
|
|
// Common Key Names
|
|
const char xpcomKeyName[]="software/mozilla/XPCOM";
|
|
const char classesKeyName[]="contractID";
|
|
const char classIDKeyName[]="classID";
|
|
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);
|
|
|
|
extern PRBool gXPCOMShuttingDown;
|
|
|
|
// 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_FAILED(status) )
|
|
*aInstancePtr = 0;
|
|
|
|
if ( mErrorPtr )
|
|
*mErrorPtr = status;
|
|
return status;
|
|
}
|
|
|
|
nsresult
|
|
nsCreateInstanceByContractID::operator()( const nsIID& aIID, void** aInstancePtr ) const
|
|
{
|
|
nsresult status;
|
|
if ( mContractID )
|
|
{
|
|
if ( NS_FAILED(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 = NS_ERROR_FAILURE;
|
|
if ( mServiceManager ) {
|
|
status = mServiceManager->GetService(mCID, aIID, (void**)aInstancePtr);
|
|
} else {
|
|
nsCOMPtr<nsIServiceManager> mgr;
|
|
NS_GetServiceManager(getter_AddRefs(mgr));
|
|
if (mgr)
|
|
status = mgr->GetService(mCID, aIID, (void**)aInstancePtr);
|
|
}
|
|
if ( NS_FAILED(status) )
|
|
*aInstancePtr = 0;
|
|
|
|
if ( mErrorPtr )
|
|
*mErrorPtr = status;
|
|
return status;
|
|
}
|
|
|
|
nsresult
|
|
nsGetServiceByContractID::operator()( const nsIID& aIID, void** aInstancePtr ) const
|
|
{
|
|
nsresult status = NS_ERROR_FAILURE;
|
|
if ( mServiceManager ) {
|
|
status = mServiceManager->GetServiceByContractID(mContractID, aIID, (void**)aInstancePtr);
|
|
} else {
|
|
nsCOMPtr<nsIServiceManager> mgr;
|
|
NS_GetServiceManager(getter_AddRefs(mgr));
|
|
if (mgr)
|
|
status = mgr->GetServiceByContractID(mContractID, aIID, (void**)aInstancePtr);
|
|
}
|
|
|
|
if ( NS_FAILED(status) )
|
|
*aInstancePtr = 0;
|
|
|
|
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;
|
|
}
|
|
|
|
if ( mServiceManager ) {
|
|
status = mServiceManager->GetServiceByContractID(value, aIID, (void**)aInstancePtr);
|
|
} else {
|
|
nsCOMPtr<nsIServiceManager> mgr;
|
|
NS_GetServiceManager(getter_AddRefs(mgr));
|
|
if (mgr)
|
|
status = mgr->GetServiceByContractID(value, aIID, (void**)aInstancePtr);
|
|
}
|
|
|
|
if (NS_FAILED(status)) {
|
|
error:
|
|
*aInstancePtr = 0;
|
|
}
|
|
|
|
*mErrorPtr = status;
|
|
return status;
|
|
}
|
|
|
|
/* prototypes for the Mac */
|
|
PRBool PR_CALLBACK
|
|
nsFactoryEntry_Destroy(nsHashKey *aKey, void *aData, void* closure);
|
|
|
|
PR_STATIC_CALLBACK(const void *)
|
|
factory_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
|
|
{
|
|
nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
|
|
|
|
return &entry->mFactoryEntry->cid;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(PLDHashNumber)
|
|
factory_HashKey(PLDHashTable *aTable, const void *aKey)
|
|
{
|
|
const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey);
|
|
|
|
return cidp->m0;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(PRBool)
|
|
factory_MatchEntry(PLDHashTable *aTable, const PLDHashEntryHdr *aHdr,
|
|
const void *aKey)
|
|
{
|
|
const nsFactoryTableEntry* entry =
|
|
NS_STATIC_CAST(const nsFactoryTableEntry*, aHdr);
|
|
const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey);
|
|
|
|
return (entry->mFactoryEntry->cid).Equals(*cidp);
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(void)
|
|
factory_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
|
|
{
|
|
nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
|
|
|
|
delete entry->mFactoryEntry;
|
|
PL_DHashClearEntryStub(aTable, aHdr);
|
|
}
|
|
|
|
static PLDHashTableOps factory_DHashTableOps = {
|
|
PL_DHashAllocTable,
|
|
PL_DHashFreeTable,
|
|
factory_GetKey,
|
|
factory_HashKey,
|
|
factory_MatchEntry,
|
|
PL_DHashMoveEntryStub,
|
|
factory_ClearEntry,
|
|
PL_DHashFinalizeStub,
|
|
};
|
|
|
|
PR_STATIC_CALLBACK(const void *)
|
|
contractID_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
|
|
{
|
|
nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
|
|
|
|
return entry->mContractID;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(PRBool)
|
|
contractID_MatchEntry(PLDHashTable *aTable, const PLDHashEntryHdr *aHdr,
|
|
const void *aKey)
|
|
{
|
|
const nsContractIDTableEntry* entry =
|
|
NS_STATIC_CAST(const nsContractIDTableEntry*, aHdr);
|
|
|
|
const char* contractID = NS_REINTERPRET_CAST(const char*, aKey);
|
|
|
|
return strcmp(entry->mContractID, contractID) == 0;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(void)
|
|
contractID_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
|
|
{
|
|
nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
|
|
|
|
if (entry->mFactoryEntry != kNonExistentContractID &&
|
|
entry->mFactoryEntry->typeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY &&
|
|
entry->mFactoryEntry->cid.Equals(kEmptyCID)) {
|
|
// this object is owned by the hash. Time to delete it.
|
|
delete entry->mFactoryEntry;
|
|
}
|
|
|
|
nsCRT::free(entry->mContractID);
|
|
|
|
PL_DHashClearEntryStub(aTable, aHdr);
|
|
}
|
|
|
|
static PLDHashTableOps contractID_DHashTableOps = {
|
|
PL_DHashAllocTable,
|
|
PL_DHashFreeTable,
|
|
contractID_GetKey,
|
|
PL_DHashStringKey,
|
|
contractID_MatchEntry,
|
|
PL_DHashMoveEntryStub,
|
|
contractID_ClearEntry,
|
|
PL_DHashFinalizeStub,
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// nsFactoryEntry
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
MOZ_DECL_CTOR_COUNTER(nsFactoryEntry)
|
|
|
|
nsFactoryEntry::nsFactoryEntry(const nsCID &aClass,
|
|
const char *aLocation,
|
|
int aType)
|
|
: cid(aClass), typeIndex(aType)
|
|
{
|
|
MOZ_COUNT_CTOR(nsFactoryEntry);
|
|
location = nsCRT::strdup(aLocation);
|
|
}
|
|
|
|
nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, nsIFactory *aFactory)
|
|
: cid(aClass), typeIndex(NS_COMPONENT_TYPE_FACTORY_ONLY)
|
|
{
|
|
MOZ_COUNT_CTOR(nsFactoryEntry);
|
|
factory = aFactory;
|
|
location = nsnull;
|
|
|
|
}
|
|
|
|
nsFactoryEntry::~nsFactoryEntry(void)
|
|
{
|
|
MOZ_COUNT_DTOR(nsFactoryEntry);
|
|
if (location)
|
|
nsCRT::free(location);
|
|
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 = nsCRT::strdup(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()
|
|
:
|
|
mMon(NULL),
|
|
mRegistry(NULL),
|
|
mPrePopulationDone(PR_FALSE),
|
|
mNativeComponentLoader(0),
|
|
mStaticComponentLoader(0),
|
|
mShuttingDown(NS_SHUTDOWN_NEVERHAPPENED),
|
|
mLoaderData(nsnull)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mFactories.ops = nsnull;
|
|
mContractIDs.ops = nsnull;
|
|
}
|
|
|
|
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.ops) {
|
|
if (!PL_DHashTableInit(&mFactories, &factory_DHashTableOps,
|
|
0, sizeof(nsFactoryTableEntry),
|
|
1024)) {
|
|
mFactories.ops = nsnull;
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
// Minimum alpha uses k=3 because nsFactoryTableEntry saves three
|
|
// words compared to what a chained hash table requires.
|
|
PL_DHashTableSetAlphaBounds(&mFactories,
|
|
0.875,
|
|
PL_DHASH_MIN_ALPHA(&mFactories, 3));
|
|
}
|
|
|
|
if (!mContractIDs.ops) {
|
|
if (!PL_DHashTableInit(&mContractIDs, &contractID_DHashTableOps,
|
|
0, sizeof(nsContractIDTableEntry),
|
|
1024)) {
|
|
mContractIDs.ops = nsnull;
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
// Minimum alpha uses k=2 because nsContractIDTableEntry saves two
|
|
// words compared to what a chained hash table requires.
|
|
PL_DHashTableSetAlphaBounds(&mContractIDs,
|
|
0.875,
|
|
PL_DHASH_MIN_ALPHA(&mContractIDs, 2));
|
|
}
|
|
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
|
|
NR_StartupRegistry();
|
|
{
|
|
nsresult ret;
|
|
ret = PlatformInit();
|
|
if( NS_FAILED( ret ) ) {
|
|
return ret;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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
|
|
if (mContractIDs.ops) {
|
|
PL_DHashTableFinish(&mContractIDs);
|
|
mContractIDs.ops = nsnull;
|
|
}
|
|
if (mFactories.ops) {
|
|
PL_DHashTableFinish(&mFactories);
|
|
mFactories.ops = nsnull;
|
|
}
|
|
// 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
|
|
|
|
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_THREADSAFE_ISUPPORTS6(nsComponentManagerImpl,
|
|
nsIComponentManager,
|
|
nsIServiceManager,
|
|
nsISupportsWeakReference,
|
|
nsIInterfaceRequestor,
|
|
nsIServiceManagerObsolete,
|
|
nsIComponentManagerObsolete)
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// nsComponentManagerImpl: Platform methods
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef USE_REGISTRY
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::PlatformInit(void)
|
|
{
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
// We need to create our registry. Since we are in the constructor
|
|
// we haven't gone as far as registering the registry factory.
|
|
// Hence, we hand create a registry.
|
|
if (mRegistry == NULL) {
|
|
nsIFactory *registryFactory = NULL;
|
|
rv = NS_RegistryGetFactory(®istryFactory);
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
rv = registryFactory->CreateInstance(NULL, NS_GET_IID(nsIRegistry),(void **)&mRegistry);
|
|
if (NS_FAILED(rv)) return rv;
|
|
NS_RELEASE(registryFactory);
|
|
}
|
|
}
|
|
|
|
// 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()
|
|
((nsRegistry *)mRegistry)->SetBufferSize( BIG_REGISTRY_BUFLEN );
|
|
|
|
// Check the version of registry. Nuke old versions.
|
|
nsRegistryKey xpcomRoot;
|
|
rv = PlatformVersionCheck(&xpcomRoot);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Open common registry keys here to speed access
|
|
// Do this after PlatformVersionCheck as it may re-create our keys
|
|
rv = mRegistry->AddSubtree(xpcomRoot, componentsKeyName, &mXPCOMKey);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = mRegistry->AddSubtree(xpcomRoot, classesKeyName, &mClassesKey);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = mRegistry->AddSubtree(xpcomRoot, classIDKeyName, &mCLSIDKey);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
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;
|
|
|
|
char* componentDescriptor;
|
|
mComponentsDir->GetPath(&componentDescriptor);
|
|
if (!componentDescriptor)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
mComponentsOffset = strlen(componentDescriptor);
|
|
|
|
if (componentDescriptor)
|
|
nsMemory::Free(componentDescriptor);
|
|
|
|
|
|
|
|
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
|
|
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
|
|
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));
|
|
|
|
// Delete the XPCOM hierarchy
|
|
rv = mRegistry->RemoveSubtree(nsIRegistry::Common, xpcomKeyName);
|
|
if(NS_FAILED(rv))
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("nsComponentManager: Failed To Nuke Subtree (%s)",xpcomKeyName));
|
|
return rv;
|
|
}
|
|
|
|
// 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);
|
|
|
|
// Recreate XPCOM key and version
|
|
rv = mRegistry->AddSubtree(nsIRegistry::Common,xpcomKeyName, &xpcomKey);
|
|
if(NS_FAILED(rv))
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("nsComponentManager: Failed To Add Subtree (%s)",xpcomKeyName));
|
|
return rv;
|
|
}
|
|
|
|
rv = mRegistry->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;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("nsComponentManager: platformVersionCheck() passed."));
|
|
}
|
|
|
|
|
|
// return the XPCOM key (null check deferred so cleanup always happens)
|
|
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
|
|
void
|
|
nsComponentManagerImpl::PlatformSetFileInfo(nsRegistryKey key, PRUint32 lastModifiedTime, PRUint32 fileSize)
|
|
{
|
|
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;
|
|
rv = mRegistry->AddSubtreeRaw(mXPCOMKey, dll->GetPersistentDescriptorString(), &dllPathKey);
|
|
if(NS_FAILED(rv))
|
|
{
|
|
return rv;
|
|
}
|
|
|
|
PlatformSetFileInfo(dllPathKey, dll->GetLastModifiedTime(), dll->GetSize());
|
|
rv = mRegistry->SetInt(dllPathKey, componentCountValueName, 0);
|
|
|
|
return rv;
|
|
}
|
|
|
|
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;
|
|
rv = mRegistry->AddSubtreeRaw(mXPCOMKey,dll->GetPersistentDescriptorString(), &dllPathKey);
|
|
|
|
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;
|
|
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)))
|
|
{
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
nsresult nsComponentManagerImpl::PlatformPrePopulateRegistry()
|
|
{
|
|
nsresult rv;
|
|
char buf[MAXREGPATHLEN];
|
|
PRUint32 bufLength = sizeof(buf);
|
|
|
|
if (mPrePopulationDone)
|
|
return NS_OK;
|
|
|
|
(void)((nsRegistry *)mRegistry)->SetBufferSize( BIG_REGISTRY_BUFLEN );
|
|
|
|
nsCOMPtr<nsIRegistryGetter> regGetter = do_QueryInterface(mRegistry);
|
|
if (!regGetter.get())
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// Read in all CID entries and populate the mFactories
|
|
nsCOMPtr<nsIEnumerator> cidEnum;
|
|
rv = mRegistry->EnumerateSubtrees( mCLSIDKey, getter_AddRefs(cidEnum));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIRegistryEnumerator> regEnum(do_QueryInterface(cidEnum, &rv));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
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;
|
|
|
|
// Figure out the component type
|
|
// Use the non allocating registry getter. Our buffer is big enough
|
|
// We wont get NS_ERROR_REG_BUFFER_TOO_SMALL
|
|
bufLength = sizeof(buf);
|
|
rv = regGetter->GetStringUTF8IntoBuffer(cidKey, componentTypeValueName, buf, &bufLength);
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
|
|
int loadertype = GetLoaderType(buf);
|
|
if (loadertype < 0) {
|
|
loadertype = AddLoaderType(buf);
|
|
}
|
|
|
|
// Create the CID entry
|
|
bufLength = sizeof(buf);
|
|
rv = regGetter->GetBytesUTF8IntoBuffer(cidKey, inprocServerValueName,
|
|
(PRUint8 *) buf, &bufLength);
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
nsCID aClass;
|
|
if (!(aClass.Parse(cidString)))
|
|
continue;
|
|
|
|
nsFactoryEntry *entry = new nsFactoryEntry(aClass, buf, loadertype);
|
|
if (!entry)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
nsFactoryTableEntry* factoryTableEntry =
|
|
NS_STATIC_CAST(nsFactoryTableEntry*,
|
|
PL_DHashTableOperate(&mFactories, &aClass,
|
|
PL_DHASH_ADD));
|
|
|
|
if (!factoryTableEntry)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
factoryTableEntry->mFactoryEntry = 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;
|
|
|
|
// Use the non allocating registry getter. Our buffer is big enough
|
|
// We wont get NS_ERROR_REG_BUFFER_TOO_SMALL
|
|
bufLength = sizeof(buf);
|
|
rv = regGetter->GetStringUTF8IntoBuffer(contractidKey, classIDValueName, buf, &bufLength);
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
nsCID aClass;
|
|
if (!aClass.Parse(buf))
|
|
continue;
|
|
|
|
// put the {contractid, Cid} mapping into our map
|
|
HashContractID(contractidString, aClass);
|
|
}
|
|
|
|
// Create the category manage to ensure prepopulation of categories
|
|
nsCOMPtr<nsICategoryManager> catman = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
|
|
|
|
// reset registry buffer to standard size
|
|
(void)((nsRegistry *)mRegistry)->SetBufferSize( -1 );
|
|
|
|
mPrePopulationDone = PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
|
|
#endif /* USE_REGISTRY */
|
|
|
|
//
|
|
// HashContractID
|
|
//
|
|
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)
|
|
{
|
|
if(!aContractID)
|
|
{
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
nsContractIDTableEntry* contractIDTableEntry =
|
|
NS_STATIC_CAST(nsContractIDTableEntry*,
|
|
PL_DHashTableOperate(&mContractIDs, aContractID,
|
|
PL_DHASH_ADD));
|
|
if (!contractIDTableEntry)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
if (!contractIDTableEntry->mContractID)
|
|
contractIDTableEntry->mContractID = nsCRT::strdup(aContractID);
|
|
|
|
contractIDTableEntry->mFactoryEntry = fe;
|
|
|
|
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)) {
|
|
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)
|
|
{
|
|
nsFactoryEntry *fe = nsnull;
|
|
{
|
|
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
nsContractIDTableEntry* contractIDTableEntry =
|
|
NS_STATIC_CAST(nsContractIDTableEntry*,
|
|
PL_DHashTableOperate(&mContractIDs, aContractID,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
|
|
fe = contractIDTableEntry->mFactoryEntry;
|
|
}
|
|
} //exit monitor
|
|
|
|
#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 = nsnull;
|
|
{
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
nsFactoryTableEntry* factoryTableEntry =
|
|
NS_STATIC_CAST(nsFactoryTableEntry*,
|
|
PL_DHashTableOperate(&mFactories, &aClass,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
|
|
entry = factoryTableEntry->mFactoryEntry;
|
|
}
|
|
} // exit monitor
|
|
|
|
|
|
#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))
|
|
{
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
nsFactoryTableEntry* factoryTableEntry =
|
|
NS_STATIC_CAST(nsFactoryTableEntry*,
|
|
PL_DHashTableOperate(&mFactories, &cidKey,
|
|
PL_DHASH_ADD));
|
|
|
|
if (!factoryTableEntry) {
|
|
return nsnull;
|
|
}
|
|
|
|
factoryTableEntry->mFactoryEntry = 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;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID,
|
|
const nsIID &aIID,
|
|
void **aResult)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIFactory> factory;
|
|
|
|
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
|
|
{
|
|
PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID);
|
|
}
|
|
|
|
PR_ASSERT(aResult != NULL);
|
|
|
|
rv = FindFactory(contractID, 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))
|
|
{
|
|
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 (gXPCOMShuttingDown) {
|
|
// 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,
|
|
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 (gXPCOMShuttingDown) {
|
|
// 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
|
|
|
|
PLDHashOperator PR_CALLBACK
|
|
FreeServiceFactoryEntryEnumerate(PLDHashTable *aTable,
|
|
PLDHashEntryHdr *aHdr,
|
|
PRUint32 aNumber,
|
|
void *aData)
|
|
{
|
|
nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
|
|
|
|
if (!entry->mFactoryEntry || entry->mFactoryEntry == kNonExistentContractID)
|
|
return PL_DHASH_NEXT;
|
|
|
|
nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
|
|
factoryEntry->mServiceObject = nsnull;
|
|
return PL_DHASH_NEXT;
|
|
}
|
|
|
|
PLDHashOperator PR_CALLBACK
|
|
FreeServiceContractIDEntryEnumerate(PLDHashTable *aTable,
|
|
PLDHashEntryHdr *aHdr,
|
|
PRUint32 aNumber,
|
|
void *aData)
|
|
{
|
|
nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
|
|
|
|
if (!entry->mFactoryEntry || entry->mFactoryEntry == kNonExistentContractID)
|
|
return PL_DHASH_NEXT;
|
|
|
|
nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
|
|
factoryEntry->mServiceObject = nsnull;
|
|
return PL_DHASH_NEXT;
|
|
}
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::FreeServices()
|
|
{
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
if (mFactories.ops) {
|
|
PL_DHashTableEnumerate(&mFactories, FreeServiceFactoryEntryEnumerate, nsnull);
|
|
}
|
|
|
|
if (mContractIDs.ops) {
|
|
PL_DHashTableEnumerate(&mContractIDs, FreeServiceContractIDEntryEnumerate, nsnull);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
NS_IMETHODIMP
|
|
nsComponentManagerImpl::GetService(const nsCID& aClass,
|
|
const nsIID& aIID,
|
|
void* *result)
|
|
{
|
|
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 (gXPCOMShuttingDown) {
|
|
// 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 = nsnull;
|
|
nsFactoryTableEntry* factoryTableEntry =
|
|
NS_STATIC_CAST(nsFactoryTableEntry*,
|
|
PL_DHashTableOperate(&mFactories, &aClass,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
|
|
entry = factoryTableEntry->mFactoryEntry;
|
|
}
|
|
|
|
if (entry && entry->mServiceObject) {
|
|
return entry->mServiceObject->QueryInterface(aIID, result);
|
|
}
|
|
|
|
nsCOMPtr<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, getter_AddRefs(service));
|
|
|
|
mon.Enter();
|
|
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (!entry) { // second hash lookup for GetService
|
|
nsFactoryTableEntry* factoryTableEntry =
|
|
NS_STATIC_CAST(nsFactoryTableEntry*,
|
|
PL_DHashTableOperate(&mFactories, &aClass,
|
|
PL_DHASH_LOOKUP));
|
|
if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
|
|
entry = factoryTableEntry->mFactoryEntry;
|
|
}
|
|
NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
|
|
if (!entry) return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
entry->mServiceObject = service;
|
|
*result = service.get();
|
|
NS_ADDREF(NS_STATIC_CAST(nsISupports*, (*result)));
|
|
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 == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
entry->typeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY;
|
|
nsFactoryTableEntry* factoryTableEntry =
|
|
NS_STATIC_CAST(nsFactoryTableEntry*,
|
|
PL_DHashTableOperate(&mFactories, &aClass,
|
|
PL_DHASH_ADD));
|
|
if (!factoryTableEntry)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
factoryTableEntry->mFactoryEntry = entry;
|
|
}
|
|
else {
|
|
if (entry->mServiceObject)
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
entry->mServiceObject = aService;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsComponentManagerImpl::UnregisterService(const nsCID& aClass)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
nsFactoryEntry* entry = nsnull;
|
|
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
nsFactoryTableEntry* factoryTableEntry =
|
|
NS_STATIC_CAST(nsFactoryTableEntry*,
|
|
PL_DHashTableOperate(&mFactories, &aClass,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
|
|
entry = factoryTableEntry->mFactoryEntry;
|
|
}
|
|
|
|
if (!entry || !entry->mServiceObject)
|
|
return NS_ERROR_SERVICE_NOT_FOUND;
|
|
|
|
entry->mServiceObject = 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
|
|
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 == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
entry->typeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY;
|
|
|
|
nsContractIDTableEntry* contractIDTableEntry =
|
|
NS_STATIC_CAST(nsContractIDTableEntry*,
|
|
PL_DHashTableOperate(&mContractIDs, aContractID,
|
|
PL_DHASH_ADD));
|
|
if (!contractIDTableEntry) {
|
|
delete entry;
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if (!contractIDTableEntry->mContractID)
|
|
contractIDTableEntry->mContractID = nsCRT::strdup(aContractID);
|
|
|
|
contractIDTableEntry->mFactoryEntry = entry;
|
|
}
|
|
else {
|
|
if (entry->mServiceObject)
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
entry->mServiceObject = aService;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass,
|
|
const nsIID& aIID,
|
|
PRBool *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 (gXPCOMShuttingDown) {
|
|
// 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;
|
|
nsFactoryEntry* entry = nsnull;
|
|
nsFactoryTableEntry* factoryTableEntry =
|
|
NS_STATIC_CAST(nsFactoryTableEntry*,
|
|
PL_DHashTableOperate(&mFactories, &aClass,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
|
|
entry = factoryTableEntry->mFactoryEntry;
|
|
}
|
|
|
|
if (entry && entry->mServiceObject) {
|
|
nsCOMPtr<nsISupports> service;
|
|
rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
|
|
*result =(service!=nsnull);
|
|
}
|
|
return rv;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID,
|
|
const nsIID& aIID,
|
|
PRBool *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 (gXPCOMShuttingDown) {
|
|
// When processing shutdown, dont process new GetService() requests
|
|
NS_WARNING("checking for new service on shutdown. Denied.");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
nsresult rv = NS_ERROR_SERVICE_NOT_FOUND;
|
|
nsFactoryEntry *entry = nsnull;
|
|
{
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
nsContractIDTableEntry* contractIDTableEntry =
|
|
NS_STATIC_CAST(nsContractIDTableEntry*,
|
|
PL_DHashTableOperate(&mContractIDs, aContractID,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
|
|
entry = contractIDTableEntry->mFactoryEntry;
|
|
}
|
|
} // exit monitor
|
|
|
|
if (entry && entry != kNonExistentContractID && entry->mServiceObject) {
|
|
nsCOMPtr<nsISupports> service;
|
|
rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
|
|
*result =(service!=nsnull);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsComponentManagerImpl::UnregisterService(const char* aContractID)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
nsFactoryEntry *entry = nsnull;
|
|
nsContractIDTableEntry* contractIDTableEntry =
|
|
NS_STATIC_CAST(nsContractIDTableEntry*,
|
|
PL_DHashTableOperate(&mContractIDs, aContractID,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
|
|
entry = contractIDTableEntry->mFactoryEntry;
|
|
}
|
|
|
|
if (entry == nsnull || entry == kNonExistentContractID || entry->mServiceObject == nsnull)
|
|
return NS_ERROR_SERVICE_NOT_FOUND;
|
|
|
|
entry->mServiceObject = nsnull;
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
|
|
const nsIID& aIID,
|
|
void* *result)
|
|
{
|
|
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 (gXPCOMShuttingDown) {
|
|
// When processing shutdown, dont process new GetService() requests
|
|
NS_WARNING("Creating new service on shutdown. Denied.");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
nsresult rv = NS_OK;
|
|
nsFactoryEntry *entry = nsnull;
|
|
nsContractIDTableEntry* contractIDTableEntry =
|
|
NS_STATIC_CAST(nsContractIDTableEntry*,
|
|
PL_DHashTableOperate(&mContractIDs, aContractID,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
|
|
entry = contractIDTableEntry->mFactoryEntry;
|
|
}
|
|
|
|
if (entry && entry != kNonExistentContractID && entry->mServiceObject) {
|
|
return entry->mServiceObject->QueryInterface(aIID, result);
|
|
}
|
|
|
|
nsCOMPtr<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, getter_AddRefs(service));
|
|
|
|
mon.Enter();
|
|
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (!entry) { // second hash lookup for GetService
|
|
nsContractIDTableEntry* contractIDTableEntry =
|
|
NS_STATIC_CAST(nsContractIDTableEntry*,
|
|
PL_DHashTableOperate(&mContractIDs, aContractID,
|
|
PL_DHASH_LOOKUP));
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
|
|
entry = contractIDTableEntry->mFactoryEntry;
|
|
}
|
|
NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
|
|
if (!entry) return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
entry->mServiceObject = service;
|
|
*result = service.get();
|
|
NS_ADDREF(NS_STATIC_CAST(nsISupports*, (*result)));
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
|
|
nsISupports* *result,
|
|
nsIShutdownListener* shutdownListener)
|
|
{
|
|
return GetService(aClass, aIID, (void**)result);
|
|
};
|
|
|
|
NS_IMETHODIMP
|
|
nsComponentManagerImpl::GetService(const char* aContractID, const nsIID& aIID,
|
|
nsISupports* *result,
|
|
nsIShutdownListener* shutdownListener )
|
|
{
|
|
return GetServiceByContractID(aContractID, aIID, (void**)result);
|
|
};
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsComponentManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service,
|
|
nsIShutdownListener* shutdownListener )
|
|
{
|
|
NS_IF_RELEASE(service);
|
|
return NS_OK;
|
|
};
|
|
|
|
NS_IMETHODIMP
|
|
nsComponentManagerImpl::ReleaseService(const char* aContractID, nsISupports* service,
|
|
nsIShutdownListener* shutdownListener )
|
|
{
|
|
NS_IF_RELEASE(service);
|
|
return NS_OK;
|
|
};
|
|
|
|
/*
|
|
* 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
|
|
nsComponentManagerImpl::RegistryLocationForSpec(nsIFile *aSpec,
|
|
char **aRegistryName)
|
|
{
|
|
nsresult rv;
|
|
|
|
if (!mComponentsDir)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
if (!aSpec) {
|
|
*aRegistryName = nsCRT::strdup("");
|
|
return NS_OK;
|
|
}
|
|
|
|
PRBool containedIn;
|
|
mComponentsDir->Contains(aSpec, PR_TRUE, &containedIn);
|
|
|
|
char *persistentDescriptor;
|
|
|
|
if (containedIn){
|
|
|
|
rv = aSpec->GetPath(&persistentDescriptor);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
char* relativeLocation = persistentDescriptor + mComponentsOffset + 1;
|
|
|
|
rv = MakeRegistryName(relativeLocation, XPCOM_RELCOMPONENT_PREFIX,
|
|
aRegistryName);
|
|
} else {
|
|
/* absolute names include volume info on Mac, so persistent descriptor */
|
|
rv = aSpec->GetPath(&persistentDescriptor);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
rv = MakeRegistryName(persistentDescriptor, XPCOM_ABSCOMPONENT_PREFIX,
|
|
aRegistryName);
|
|
}
|
|
|
|
if (persistentDescriptor)
|
|
nsMemory::Free(persistentDescriptor);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::SpecForRegistryLocation(const char *aLocation,
|
|
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)) {
|
|
|
|
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)) {
|
|
|
|
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);
|
|
*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 = nsnull;
|
|
nsIDKey key(aClass);
|
|
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
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 == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
nsFactoryTableEntry* factoryTableEntry =
|
|
NS_STATIC_CAST(nsFactoryTableEntry*,
|
|
PL_DHashTableOperate(&mFactories, &aClass,
|
|
PL_DHASH_ADD));
|
|
|
|
if (!factoryTableEntry)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
factoryTableEntry->mFactoryEntry = 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);
|
|
}
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::RegisterComponentWithType(const nsCID &aClass,
|
|
const char *aClassName,
|
|
const char *aContractID,
|
|
nsIFile *aSpec,
|
|
const char *aLocation,
|
|
PRBool aReplace,
|
|
PRBool aPersist,
|
|
const char *aType)
|
|
{
|
|
return RegisterComponentCommon(aClass, aClassName, aContractID,
|
|
aLocation,
|
|
aReplace, aPersist,
|
|
aType);
|
|
}
|
|
|
|
/*
|
|
* Register a component, using whatever they stuck in the nsIFile.
|
|
*/
|
|
nsresult
|
|
nsComponentManagerImpl::RegisterComponentSpec(const nsCID &aClass,
|
|
const char *aClassName,
|
|
const char *aContractID,
|
|
nsIFile *aLibrarySpec,
|
|
PRBool aReplace,
|
|
PRBool aPersist)
|
|
{
|
|
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)
|
|
{
|
|
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,
|
|
const char *aRegistryName,
|
|
PRBool aReplace,
|
|
PRBool aPersist,
|
|
const char *aType)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
nsIDKey key(aClass);
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
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;
|
|
}
|
|
|
|
if (entry) {
|
|
entry->ReInit(aClass, aRegistryName, typeIndex);
|
|
}
|
|
else {
|
|
entry = new nsFactoryEntry(aClass, aRegistryName, typeIndex);
|
|
if (!entry)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsFactoryTableEntry* factoryTableEntry =
|
|
NS_STATIC_CAST(nsFactoryTableEntry*,
|
|
PL_DHashTableOperate(&mFactories, &aClass,
|
|
PL_DHASH_ADD));
|
|
|
|
if (!factoryTableEntry)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
factoryTableEntry->mFactoryEntry = entry;
|
|
}
|
|
|
|
// Update the ContractID->CLSID Map
|
|
if (contractID
|
|
#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"));
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::GetLoaderForType(int aType,
|
|
nsIComponentLoader **aLoader)
|
|
{
|
|
nsresult rv;
|
|
|
|
// 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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
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)
|
|
{
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE);
|
|
old = NULL;
|
|
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);
|
|
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
// 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))
|
|
{
|
|
PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE);
|
|
entry = nsnull;
|
|
}
|
|
|
|
#ifdef USE_REGISTRY
|
|
// Remove registry entries for this cid
|
|
char *cidString = aClass.ToString();
|
|
rv = PlatformUnregister(cidString, registryName);
|
|
delete [] cidString;
|
|
#endif
|
|
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
|
|
("nsComponentManager: Factory unregister(%s) %s.", registryName,
|
|
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)
|
|
{
|
|
return UnloadLibraries(NS_STATIC_CAST(nsIServiceManager*, this), NS_Timer); // XXX when
|
|
}
|
|
|
|
// Private implementation of unloading libraries
|
|
nsresult
|
|
nsComponentManagerImpl::UnloadLibraries(nsIServiceManager *serviceMgr, PRInt32 aWhen)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("nsComponentManager: Unloading Libraries."));
|
|
|
|
// 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);
|
|
return rv;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* AutoRegister(RegistrationInstant, const char *directory)
|
|
*
|
|
* Given a directory in the following format, this will ensure proper registration
|
|
* of all components. No default director is looked at.
|
|
*
|
|
* Directory and fullname are what NSPR will accept. For eg.
|
|
* WIN y:/home/dp/mozilla/dist/bin
|
|
* UNIX /home/dp/mozilla/dist/bin
|
|
* MAC /Hard drive/mozilla/dist/apprunner
|
|
*
|
|
* This will take care not loading already registered dlls, finding and
|
|
* registering new dlls, re-registration of modified dlls
|
|
*
|
|
*/
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::AutoRegister(PRInt32 when, nsIFile *inDirSpec)
|
|
{
|
|
nsresult rv;
|
|
((nsRegistry *)mRegistry)->SetBufferSize( BIG_REGISTRY_BUFLEN );
|
|
rv = AutoRegisterImpl(when, inDirSpec);
|
|
mRegistry->Flush();
|
|
((nsRegistry *)mRegistry)->SetBufferSize( -1 );
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::AutoRegisterImpl(PRInt32 when, nsIFile *inDirSpec)
|
|
{
|
|
nsCOMPtr<nsIFile> dir;
|
|
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);
|
|
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?
|
|
}
|
|
|
|
nsCOMPtr<nsIInterfaceInfoManager> iim =
|
|
dont_AddRef(XPTI_GetInterfaceInfoManager());
|
|
|
|
if (!iim)
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
// Notify observers of xpcom autoregistration start
|
|
NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, nsnull,
|
|
"start");
|
|
|
|
/* 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++) {
|
|
if (!mLoaderData[i].loader) {
|
|
rv = GetLoaderForType(i, &mLoaderData[i].loader);
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
}
|
|
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;
|
|
if (mLoaderData[i].loader) {
|
|
rv = mLoaderData[i].loader->RegisterDeferredComponents(when, &b);
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
registered |= b;
|
|
}
|
|
}
|
|
} while (NS_SUCCEEDED(rv) && registered);
|
|
}
|
|
|
|
// Notify observers of xpcom autoregistration completion
|
|
NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, nsnull,
|
|
"end");
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::AutoRegisterComponent(PRInt32 when,
|
|
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;
|
|
if (!mLoaderData[i].loader) {
|
|
rv = GetLoaderForType(i, &mLoaderData[i].loader);
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
}
|
|
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;
|
|
|
|
}
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::AutoUnregisterComponent(PRInt32 when,
|
|
nsIFile *component)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
for (int i = 0; i < mNLoaderData; i++) {
|
|
PRBool didUnRegister;
|
|
if (!mLoaderData[i].loader) {
|
|
rv = GetLoaderForType(i, &mLoaderData[i].loader);
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
}
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
typedef NS_CALLBACK(EnumeratorConverter)(PLDHashTable *table,
|
|
const PLDHashEntryHdr *hdr,
|
|
void *data,
|
|
nsISupports **retval);
|
|
|
|
class PLDHashTableEnumeratorImpl : public nsIBidirectionalEnumerator
|
|
{
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIENUMERATOR
|
|
NS_DECL_NSIBIDIRECTIONALENUMERATOR
|
|
|
|
virtual ~PLDHashTableEnumeratorImpl();
|
|
PLDHashTableEnumeratorImpl(PLDHashTable *table,
|
|
EnumeratorConverter converter,
|
|
void *converterData);
|
|
PRInt32 Count() { return mCount; }
|
|
private:
|
|
PLDHashTableEnumeratorImpl(); /* no implementation */
|
|
NS_IMETHODIMP ReleaseElements();
|
|
|
|
nsVoidArray mElements;
|
|
PRInt32 mCount, mCurrent;
|
|
PRMonitor* mMonitor;
|
|
|
|
struct Closure {
|
|
PRBool succeeded;
|
|
EnumeratorConverter converter;
|
|
void *data;
|
|
PLDHashTableEnumeratorImpl *impl;
|
|
};
|
|
|
|
static PLDHashOperator PR_CALLBACK Enumerator(PLDHashTable *table,
|
|
PLDHashEntryHdr *hdr, PRUint32 number,
|
|
void *data);
|
|
};
|
|
|
|
// static
|
|
PLDHashOperator PR_CALLBACK
|
|
PLDHashTableEnumeratorImpl::Enumerator(PLDHashTable *table,
|
|
PLDHashEntryHdr *hdr, PRUint32 number,
|
|
void *data)
|
|
{
|
|
Closure *c = NS_REINTERPRET_CAST(Closure *, data);
|
|
nsISupports *converted;
|
|
if (NS_FAILED(c->converter(table, hdr, c->data, &converted)) ||
|
|
!c->impl->mElements.AppendElement(converted)) {
|
|
c->succeeded = PR_FALSE;
|
|
return PL_DHASH_STOP;
|
|
}
|
|
|
|
c->succeeded = PR_TRUE;
|
|
return PL_DHASH_NEXT;
|
|
}
|
|
|
|
PLDHashTableEnumeratorImpl::PLDHashTableEnumeratorImpl
|
|
(PLDHashTable *table, EnumeratorConverter converter,
|
|
void *converterData) :
|
|
mCurrent(0)
|
|
{
|
|
mMonitor = nsAutoMonitor::NewMonitor("PLDHashTableEnumeratorImpl");
|
|
|
|
nsAutoMonitor mon(mMonitor);
|
|
|
|
NS_INIT_REFCNT();
|
|
Closure c = { PR_FALSE, converter, converterData, this };
|
|
mCount = PL_DHashTableEnumerate(table, Enumerator, &c);
|
|
if (!c.succeeded) {
|
|
ReleaseElements();
|
|
mCount = 0;
|
|
}
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS2(PLDHashTableEnumeratorImpl, nsIBidirectionalEnumerator,
|
|
nsIEnumerator);
|
|
|
|
PLDHashTableEnumeratorImpl::~PLDHashTableEnumeratorImpl()
|
|
{
|
|
(void) ReleaseElements();
|
|
|
|
// Destroy the Lock
|
|
if (mMonitor)
|
|
PR_DestroyMonitor(mMonitor);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
PLDHashTableEnumeratorImpl::ReleaseElements()
|
|
{
|
|
for (PRInt32 i = 0; i < mCount; i++) {
|
|
nsISupports *supports = NS_REINTERPRET_CAST(nsISupports *,
|
|
mElements[i]);
|
|
NS_IF_RELEASE(supports);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
PL_NewDHashTableEnumerator(PLDHashTable *table,
|
|
EnumeratorConverter converter,
|
|
void *converterData, nsIEnumerator **retval)
|
|
{
|
|
PLDHashTableEnumeratorImpl *impl =
|
|
new PLDHashTableEnumeratorImpl(table, converter, converterData);
|
|
|
|
if (!impl)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
if (impl->Count() == -1) {
|
|
// conversion failed
|
|
delete impl;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
return impl->QueryInterface(NS_GET_IID(nsIEnumerator), (void **)retval);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
PLDHashTableEnumeratorImpl::First()
|
|
{
|
|
if (!mCount)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
mCurrent = 0;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
PLDHashTableEnumeratorImpl::Last()
|
|
{
|
|
if (!mCount)
|
|
return NS_ERROR_FAILURE;
|
|
mCurrent = mCount - 1;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
PLDHashTableEnumeratorImpl::Prev()
|
|
{
|
|
if (!mCurrent)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
mCurrent--;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
PLDHashTableEnumeratorImpl::Next()
|
|
{
|
|
// If empty or we're past the end, or we are at the end return error
|
|
if (!mCount || (mCurrent == mCount) || (++mCurrent == mCount))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
PLDHashTableEnumeratorImpl::CurrentItem(nsISupports **retval)
|
|
{
|
|
if (!mCount || mCurrent == mCount)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
*retval = NS_REINTERPRET_CAST(nsISupports *, mElements[mCurrent]);
|
|
if (*retval)
|
|
NS_ADDREF(*retval);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
PLDHashTableEnumeratorImpl::IsDone()
|
|
{
|
|
if (!mCount || (mCurrent == mCount)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
return NS_COMFALSE;
|
|
}
|
|
|
|
|
|
|
|
static NS_IMETHODIMP
|
|
ConvertFactoryEntryToCID(PLDHashTable *table,
|
|
const PLDHashEntryHdr *hdr,
|
|
void *data, nsISupports **retval)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsISupportsID> wrapper =
|
|
do_CreateInstance(NS_SUPPORTS_ID_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
const nsFactoryTableEntry *entry =
|
|
NS_REINTERPRET_CAST(const nsFactoryTableEntry *, hdr);
|
|
if(entry) {
|
|
nsFactoryEntry *fe = entry->mFactoryEntry;
|
|
|
|
wrapper->SetData(&fe->cid);
|
|
*retval = wrapper;
|
|
NS_ADDREF(*retval);
|
|
return NS_OK;
|
|
}
|
|
else
|
|
*retval = nsnull;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
static NS_IMETHODIMP
|
|
ConvertContractIDKeyToString(PLDHashTable *table,
|
|
const PLDHashEntryHdr *hdr,
|
|
void *data, nsISupports **retval)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsISupportsString> wrapper =
|
|
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
const nsContractIDTableEntry *entry =
|
|
NS_REINTERPRET_CAST(const nsContractIDTableEntry *, hdr);
|
|
const char *contractID = entry->mContractID;
|
|
nsCAutoString converted;
|
|
|
|
converted.Append(contractID);
|
|
|
|
wrapper->SetData(converted.get());
|
|
*retval = wrapper;
|
|
NS_ADDREF(*retval);
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator** aEnumerator)
|
|
{
|
|
NS_ASSERTION(aEnumerator != nsnull, "null ptr");
|
|
if(!aEnumerator)
|
|
{
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
*aEnumerator = nsnull;
|
|
|
|
nsresult rv;
|
|
if(!mPrePopulationDone)
|
|
{
|
|
rv = PlatformPrePopulateRegistry();
|
|
if(NS_FAILED(rv))
|
|
return rv;
|
|
}
|
|
|
|
return PL_NewDHashTableEnumerator(&mFactories,
|
|
ConvertFactoryEntryToCID,
|
|
nsnull, aEnumerator);
|
|
}
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::EnumerateContractIDs(nsIEnumerator** aEnumerator)
|
|
{
|
|
NS_ASSERTION(aEnumerator != nsnull, "null ptr");
|
|
if(!aEnumerator)
|
|
{
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
*aEnumerator = nsnull;
|
|
|
|
nsresult rv;
|
|
if(!mPrePopulationDone)
|
|
{
|
|
rv = PlatformPrePopulateRegistry();
|
|
if(NS_FAILED(rv))
|
|
return rv;
|
|
}
|
|
|
|
return PL_NewDHashTableEnumerator(&mContractIDs,
|
|
ConvertContractIDKeyToString,
|
|
nsnull, aEnumerator);
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result)
|
|
{
|
|
if (uuid.Equals(NS_GET_IID(nsIServiceManager)))
|
|
{
|
|
*result = NS_STATIC_CAST(nsIServiceManager*, this);
|
|
NS_ADDREF_THIS(); // dougt? extra addrefs???
|
|
return NS_OK;
|
|
}
|
|
|
|
// fall through to QI as anything QIable is a superset of what canbe
|
|
// got via the GetInterface()
|
|
return QueryInterface(uuid, result);
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
#ifdef DEBUG_dougt
|
|
// NS_WARNING("DEPRECATED FUNCTION: Use NS_GetComponentManager");
|
|
#endif
|
|
nsresult rv = NS_OK;
|
|
|
|
if (nsComponentManagerImpl::gComponentManager == NULL)
|
|
{
|
|
// XPCOM needs initialization.
|
|
rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
// NO ADDREF since this is never intended to be released.
|
|
// See nsComponentManagerObsolete.h for the reason for such
|
|
// casting uglyness
|
|
*result = (nsIComponentManager*)(void*)(nsIComponentManagerObsolete*) nsComponentManagerImpl::gComponentManager;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_COM nsresult
|
|
NS_GetComponentManager(nsIComponentManager* *result)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (nsComponentManagerImpl::gComponentManager == NULL)
|
|
{
|
|
// XPCOM needs initialization.
|
|
rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
|
|
}
|
|
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
|
|
*result = NS_STATIC_CAST(nsIComponentManager*,
|
|
nsComponentManagerImpl::gComponentManager);
|
|
NS_IF_ADDREF(*result);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_COM nsresult
|
|
NS_GetServiceManager(nsIServiceManager* *result)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (nsComponentManagerImpl::gComponentManager == NULL)
|
|
{
|
|
// XPCOM needs initialization.
|
|
rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
|
|
}
|
|
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
|
|
*result = NS_STATIC_CAST(nsIServiceManager*,
|
|
nsComponentManagerImpl::gComponentManager);
|
|
NS_IF_ADDREF(*result);
|
|
return NS_OK;
|
|
}
|
|
|
|
|