nsNativeComponentLoader.cpp revision fbe12eedabedca4b5434408da78201f4e5757d05
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla 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
*
* 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 the Initial Developer are Copyright (C) 1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK *****
* This Original Code has been modified by IBM Corporation.
* Modifications made by IBM described herein are
* Copyright (c) International Business Machines
* Corporation, 2000
*
* Modifications to Mozilla code or documentation
* identified per MPL Section 3.3
*
* Date Modified by Description of modification
* 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
*/
#include "prmem.h"
#include "prerror.h"
#include "prsystem.h" // PR_GetDirectorySeparator
#include "nsNativeComponentLoader.h"
#include "nsComponentManager.h"
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "nsIModule.h"
#include "xcDll.h"
#include "nsHashtable.h"
#include "nsXPIDLString.h"
#include "nsCRT.h"
#include "nsIObserverService.h"
#if defined(XP_MAC) // sdagley dougt fix
#include <Files.h>
#include <Errors.h>
#include "nsILocalFileMac.h"
#endif
#include "prlog.h"
extern PRLogModuleInfo *nsComponentManagerLog;
static PRBool PR_CALLBACK
{
delete entry;
return PR_TRUE;
}
{
}
const char *aLocation,
const char *aType,
{
if (!_retval)
return NS_ERROR_NULL_POINTER;
/* use a hashtable of WeakRefs to store the factory object? */
/* Should this all live in xcDll? */
return rv;
if (!dll)
return NS_ERROR_OUT_OF_MEMORY;
#ifdef PR_LOGGING
("nsNativeComponentLoader: loading \"%s\"",
displayPath.get()));
#endif
("nsNativeComponentLoader: load FAILED"));
if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
return NS_ERROR_FAILURE;
}
}
/* Get service manager for factory */
return rv; // XXX translate error code?
("nsNativeComponentLoader: Factory creation %s for %s",
aLocation));
// If the dll failed to get us a factory. But the dll registered that
// it would be able to create a factory for this CID. mmh!
// We cannot just delete the dll as the dll could be hosting
// other CID for which factory creation can pass.
// We will just let it be. The effect will be next time we try
// creating the object, we will query the dll again. Since the
// dll is loaded, this aint a big hit. So for optimized builds
// this is ok to limp along.
return rv;
}
{
if (!mCompMgr)
return NS_ERROR_INVALID_ARG;
return NS_OK;
}
{
#ifdef DEBUG
/* do we _really_ want to print this every time? */
#endif
#ifdef DEBUG
#endif
return rv;
}
{
#if 0
// Going to many of these checks is a performance hit on the mac.
// Since these routines are called relatively infrequently and
// we will fail anyway down the line if a directory aint there,
// we are commenting this check out.
// Make sure we are dealing with a directory
if (!isDir)
return NS_ERROR_INVALID_ARG;
#endif /* 0 */
// Create a directory iterator
// whip through the directory to register every file
{
if (NS_SUCCEEDED(rv))
{
if (NS_SUCCEEDED(rv))
{
{
// This is a directory. Grovel for components into the directory.
#ifdef RT_OS_DARWIN // But not if it's a debug bundle.
#endif
}
else
{
// This is a file. Try to register it.
}
}
}
}
return rv;
}
static nsresult PR_CALLBACK
{
{
return NS_ERROR_INVALID_ARG;
}
// Get if the dll was marked for unload in an earlier round
// Reset dll marking for unload just in case we return with
// an error.
// Get the module object
/* XXXshaver cheat and use the global component manager */
rv = dll->GetModule(NS_STATIC_CAST(nsIComponentManager*, nsComponentManagerImpl::gComponentManager),
if (NS_SUCCEEDED(rv))
{
}
// When shutting down, whether we can unload the dll or not,
// we will shutdown the dll to release any memory it has got
{
}
// Check error status on CanUnload() call
{
#ifdef PR_LOGGING
("nsNativeComponentLoader: nsIModule::CanUnload() returned error for %s.",
displayPath.get()));
#endif
return rv;
}
if (canUnload)
{
if (dllMarkedForUnload)
{
#ifdef PR_LOGGING
#endif
#ifdef DEBUG_dougt
// XXX dlls aren't counting their outstanding instances correctly
// XXX hence, dont unload until this gets enforced.
#endif /* 0 */
}
else
{
#ifdef PR_LOGGING
#endif
}
}
else
{
#ifdef PR_LOGGING
#endif
}
return rv;
}
struct freeLibrariesClosure
{
};
static PRBool PR_CALLBACK
{
return PR_TRUE;
}
/*
* SelfRegisterDll
*
* Given a dll abstraction, this will load, selfregister the dll and
* unload the dll.
*
*/
const char *registryLocation,
{
// Precondition: dll is not loaded already, unless we're deferred
{
// Cannot load. Probably not a dll.
if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
return NS_ERROR_FAILURE;
}
#ifdef PR_LOGGING
#endif
// Tell the module to self register
if (NS_SUCCEEDED(res))
{
/*************************************************************
* WARNING: Why are use introducing 'res2' here and then *
* later assigning it to 'res' rather than just using 'res'? *
* This is because this code turns up a code-generation bug *
* in VC6 on NT. Assigning to 'res' on the next line causes *
* the value of 'dll' to get nulled out! The two seem to be *
* getting aliased together during compilation. *
*************************************************************/
if (NS_SUCCEEDED(res2)) {
// in the case of re-registering a component, we want to remove
// any optional data that this file may have had.
}
else
{
#ifdef PR_LOGGING
("nsNativeComponentLoader: dll->GetDllSpec() on %s FAILED.",
displayPath.get()));
#endif
}
}
// Update the timestamp and size of the dll in registry
// Don't enter deferred modules in the registry, because it might only be
// able to register on some later autoreg, after another component has been
// installed.
if (res != NS_ERROR_FACTORY_REGISTER_AGAIN) {
if (!fs)
return res;
if (!manager)
return NS_ERROR_FAILURE;
}
return res;
}
//
// MOZ_DEMANGLE_SYMBOLS is only a linux + MOZ_DEBUG thing.
//
#if defined(MOZ_DEMANGLE_SYMBOLS)
#include "nsTraceRefcntImpl.h" // for nsTraceRefcntImpl::DemangleSymbol()
#endif
const char *aCallerName,
const char *aNsprErrorMsg)
{
return NS_OK;
#if defined(MOZ_DEMANGLE_SYMBOLS)
// Demangle undefined symbols
{
if (!demangledSymbol.IsEmpty())
{
tmp += " \n";
tmp += demangledSymbol;
}
}
#endif // MOZ_DEMANGLE_SYMBOLS
#ifdef DEBUG
"nsNativeComponentLoader: %s(%s) Load FAILED with error: %s\n",
displayPath.get(),
#endif
// Do NSPR log
#ifdef PR_LOGGING
("nsNativeComponentLoader: %s(%s) Load FAILED with error: %s",
displayPath.get(),
#endif
return NS_OK;
}
{
{
// Cannot load. Probably not a dll.
return(NS_ERROR_FAILURE);
}
// Tell the module to self register
if (NS_SUCCEEDED(res))
{
#ifdef PR_LOGGING
#endif
// Get registry location for spec
// what I want to do here is QI for a Component Registration Manager. Since this
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
if (obsoleteManager)
}
return res;
}
{
*unregistered = PR_FALSE;
// what I want to do here is QI for a Component Registration Manager. Since this
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
if (obsoleteManager)
// Notify observers, if any, of autoregistration work
if (NS_SUCCEEDED(rv))
{
if (NS_SUCCEEDED(rv))
{
}
}
#ifdef PR_LOGGING
("nsNativeComponentLoader: AutoUnregistration for %s %s.",
#endif
return rv;
// Remove any autoreg info about this dll
*unregistered = PR_TRUE;
return rv;
}
{
if (!registered)
return NS_ERROR_NULL_POINTER;
*registered = PR_FALSE;
/* this should be a pref or registry entry, or something */
static const char *ValidDllExtensions[] = {
".dll", /* Windows */
".so", /* Unix */
".shlb", /* Mac ? */
".dso", /* Unix ? */
".dylib", /* Unix: Mach */
".so.1.0", /* Unix: BSD */
".sl", /* Unix: HP-UX */
#if defined(VMS)
".exe", /* Open VMS */
#endif
".dlm", /* new for all platforms */
};
*registered = PR_FALSE;
#if 0
// This is a performance hit on mac. Since we have already checked
// this; plus is we dont, load will fail anyway later on, this
// is being commented out.
// Ensure we are dealing with a file as opposed to a dir
return rv;
#endif /* 0 */
// deal only with files that have a valid extension
#if defined(XP_MAC) // sdagley dougt fix
// rjc - on Mac, check the file's type code (skip checking the creator code)
if (localFileMac)
{
if (NS_SUCCEEDED(rv))
{
// on Mac, Mozilla shared libraries are of type 'shlb'
// Note: we don't check the creator (which for Mozilla is 'MOZZ')
// so that 3rd party shared libraries will be noticed!
}
}
#else
for (int i=0; ValidDllExtensions[i] != NULL; i++)
{
// Does fullname end with this extension
)
{
break;
}
}
#endif
if (validExtension == PR_FALSE)
// Skip invalid extensions
return NS_OK;
// what I want to do here is QI for a Component Registration Manager. Since this
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
if (obsoleteManager)
return rv;
// Get the registry representation of the dll, if any
return rv;
{
// We already have seen this dll. Check if this dll changed
if (!dll->HasChanged())
{
#ifdef PR_LOGGING
// Dll hasn't changed. Skip.
("nsNativeComponentLoader: + nsDll not changed \"%s\". Skipping...",
displayPath.get()));
#endif
*registered = PR_TRUE;
return NS_OK;
}
// Aagh! the dll has changed since the last time we saw it.
// re-register dll
// Notify observers, if any, of autoregistration work
if (NS_SUCCEEDED(rv))
{
if (NS_SUCCEEDED(rv))
{
// this string can't come from a string bundle, because we
// don't have string bundles yet.
// get the file name
{
}
// this string can't come from a string bundle, because we
// don't have string bundles yet.
(void) observerService->
}
}
{
// We loaded the old version of the dll and now we find that the
// on-disk copy if newer. Try to unload the dll.
{
// THIS IS THE WORST SITUATION TO BE IN.
// Dll doesn't want to be unloaded. Cannot re-register
// this dll.
#ifdef PR_LOGGING
("nsNativeComponentLoader: *** Dll already loaded. "
"Cannot unload either. Hence cannot re-register "
#endif
return rv;
}
else {
// dll doesn't have a CanUnload proc. Guess it is
// ok to unload it.
#ifdef PR_LOGGING
("nsNativeComponentLoader: + Unloading \"%s\". (no CanUnloadProc).",
displayPath.get()));
#endif
}
} // dll isloaded
// Sanity.
{
// We went through all the above to make sure the dll
// is unloaded. And here we are with the dll still
// loaded. Whoever taught dp programming...
#ifdef PR_LOGGING
("nsNativeComponentLoader: Dll still loaded. Cannot re-register "
#endif
return NS_ERROR_FAILURE;
}
} // dll != NULL
else
{
// Create and add the dll to the mDllStore
// It is ok to do this even if the creation of nsDll
// didnt succeed. That way we wont do this again
// when we encounter the same dll.
return NS_ERROR_OUT_OF_MEMORY;
} // dll == NULL
// Either we are seeing the dll for the first time or the dll has
// changed since we last saw it and it is unloaded successfully.
//
// Now we can try register the dll for sure.
{
if (res == NS_ERROR_FACTORY_REGISTER_AGAIN) {
/* defer for later loading */
*registered = PR_TRUE;
return NS_OK;
} else {
#ifdef PR_LOGGING
("nsNativeComponentLoader: Autoregistration FAILED for "
#endif
return NS_ERROR_FACTORY_NOT_REGISTERED;
}
}
else
{
#ifdef PR_LOGGING
("nsNativeComponentLoader: Autoregistration Passed for "
#endif
// Marking dll along with modified time and size in the
// registry happens at PlatformRegister(). No need to do it
// here again.
*registered = PR_TRUE;
}
return NS_OK;
}
{
#ifdef DEBUG
#endif
*aRegistered = PR_FALSE;
if (!mDeferredComponents.Count())
return NS_OK;
PR_TRUE);
if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) {
if (NS_SUCCEEDED(rv))
*aRegistered = PR_TRUE;
}
}
#ifdef DEBUG
if (*aRegistered)
else
#endif
/* are there any fatal errors? */
return NS_OK;
}
const char *aClassName,
const char *aContractID,
const char *aLocation,
{
return NS_OK;
}
{
struct freeLibrariesClosure callData;
// Cycle through the dlls checking to see if they want to be unloaded
return NS_OK;
}
//
// CreateDll
// The only way to create a dll or get it from the dll cache. This will
// be called in multiple situations:
//
// 1. Autoregister will create one for each dll it is trying to register. This
// call will be passing a spec in.
// {spec, NULL, 0, 0}
//
// 2. GetFactory() This will call CreateDll() with a null spec but will give
// the registry represented name of the dll. If modtime and size are zero,
// we will go the registry to find the right modtime and size.
// {NULL, rel:libpref.so, 0, 0}
//
// 3. Prepopulation of dllCache A dll object created off a registry entry.
// Specifically dll name is stored in rel: or abs: or lib: formats in the
// registry along with its lastModTime and fileSize.
// {NULL, rel:libpref.so, 8985659, 20987}
const char *aLocation,
{
if (dll)
{
return NS_OK;
}
if (!aSpec)
{
// what I want to do here is QI for a Component Registration Manager. Since this
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
if (obsoleteManager)
return rv;
}
else
{
}
if (!dll)
{
if (!dll)
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
{
return rv;
(void **)aFactory);
}
{
if (!manager)
{
NS_WARNING("Something is terribly wrong");
return NS_ERROR_FAILURE;
}
// the native component loader uses the optional data
// to store a space delimited list of dependent library
// names
if (!libName)
{
return NS_OK;
}
return NS_OK;
}