initterm.cpp revision 8bc83e5cee630bad71985c8ddf175f6eab0bfb7a
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * MS COM / XPCOM Abstraction Layer - Initialization and Termination.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * available from http://www.virtualbox.org. This file is free software;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * you can redistribute it and/or modify it under the terms of the GNU
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * General Public License (GPL) as published by the Free Software
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * additional information or have any questions.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#else /* !defined (VBOX_WITH_XPCOM) */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync/* XPCOM_GLUE is defined when the client uses the standalone glue
fef7670f1122a99df607422af1622eb495f5ba4fvboxsync * (i.e. dynamically picks up the existing XPCOM shared library installation).
fef7670f1122a99df607422af1622eb495f5ba4fvboxsync * This is not the case for VirtualBox XPCOM clients (they are always
1859e17ebfeca9bb36190ecf145a6d023eae00b4vboxsync * distrubuted with the self-built XPCOM library, and therefore have a binary
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * dependency on it) but left here for clarity.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#endif /* !defined (VBOX_WITH_XPCOM) */
2849c1c13746836fae51db4f2a934e0a2de6f120vboxsyncclass DirectoryServiceProvider : public nsIDirectoryServiceProvider
2849c1c13746836fae51db4f2a934e0a2de6f120vboxsync , mComponentDirLocation (NULL), mCurrProcDirLocation (NULL)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncNS_IMPL_ISUPPORTS1 (DirectoryServiceProvider, nsIDirectoryServiceProvider)
fef7670f1122a99df607422af1622eb495f5ba4fvboxsyncDirectoryServiceProvider::~DirectoryServiceProvider()
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @param aCompRegLocation Path to compreg.dat, in Utf8.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @param aXPTIDatLocation Path to xpti.data, in Utf8.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncDirectoryServiceProvider::init (const char *aCompRegLocation,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync AssertReturn(aCompRegLocation, NS_ERROR_INVALID_ARG);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync AssertReturn(aXPTIDatLocation, NS_ERROR_INVALID_ARG);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int vrc = RTStrUtf8ToCurrentCP (&mCompRegLocation, aCompRegLocation);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync vrc = RTStrUtf8ToCurrentCP (&mXPTIDatLocation, aXPTIDatLocation);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync vrc = RTStrUtf8ToCurrentCP (&mComponentDirLocation, aComponentDirLocation);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync vrc = RTStrUtf8ToCurrentCP (&mCurrProcDirLocation, aCurrProcDirLocation);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync return RT_SUCCESS(vrc) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncDirectoryServiceProvider::GetFile (const char *aProp,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (strcmp (aProp, NS_XPCOM_COMPONENT_REGISTRY_FILE) == 0)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else if (strcmp (aProp, NS_XPCOM_XPTI_REGISTRY_FILE) == 0)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else if (mComponentDirLocation && strcmp (aProp, NS_XPCOM_COMPONENT_DIR) == 0)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else if (mCurrProcDirLocation && strcmp (aProp, NS_XPCOM_CURRENT_PROCESS_DIR) == 0)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rv = NS_NewNativeLocalFile (nsEmbedCString (fileLocation),
fef7670f1122a99df607422af1622eb495f5ba4fvboxsync return localFile->QueryInterface (NS_GET_IID (nsIFile),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Global XPCOM initialization flag (we maintain it ourselves since XPCOM
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * doesn't provide such functionality)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic bool volatile gIsXPCOMInitialized = false;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Number of Initialize() calls on the main thread.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic unsigned int gXPCOMInitCount = 0;
fef7670f1122a99df607422af1622eb495f5ba4fvboxsync#else /* !defined (VBOX_WITH_XPCOM) */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * The COM main thread handle. (The first caller of com::Initialize().)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsyncstatic RTTHREAD volatile gCOMMainThread = NIL_RTTHREAD;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Number of Initialize() calls on the main thread.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#endif /* !defined (VBOX_WITH_XPCOM) */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Initializes the COM runtime.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * This method must be called on each thread of the client application that
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * wants to access COM facilities. The initialization must be performed before
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * calling any other COM method or attempting to instantiate COM objects.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * On platforms using XPCOM, this method uses the following scheme to search for
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * XPCOM runtime:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * 1. If the VBOX_APP_HOME environment variable is set, the path it specifies
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * is used to search XPCOM libraries and components. If this method fails to
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * initialize XPCOM runtime using this path, it will immediately return a
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * failure and will NOT check for other paths as described below.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * 2. If VBOX_APP_HOME is not set, this methods tries the following paths in the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * given order:
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * a) Compiled-in application data directory (as returned by
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * RTPathAppPrivateArch())
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * b) "/usr/lib/virtualbox" (Linux only)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * c) "/opt/VirtualBox" (Linux only)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * The first path for which the initialization succeeds will be used.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * On MS COM platforms, the COM runtime is provided by the system and does not
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * need to be searched for.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Once the COM subsystem is no longer necessary on a given thread, Shutdown()
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * must be called to free resources allocated for it. Note that a thread may
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * call Initialize() several times but for each of tese calls there must be a
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * corresponding Shutdown() call.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * @return S_OK on success and a COM result code in case of failure.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /// @todo the below rough method of changing the aparment type doesn't
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /// work on some systems for unknown reason (CoUninitialize() simply does
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /// nothing there, or at least all 10 000 of subsequent CoInitializeEx()
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /// continue to return RPC_E_CHANGED_MODE there). The problem on those
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /// systems is related to the "Extend support for advanced text services
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /// to all programs" checkbox in the advanced language settings dialog,
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /// i.e. the problem appears when this checkbox is checked and disappears
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /// if you clear it. For this reason, we disable the code below and
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /// instead initialize COM in MTA as early as possible, before 3rd party
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /// libraries we use have done so (i.e. Qt).
1859e17ebfeca9bb36190ecf145a6d023eae00b4vboxsync /* If we fail to set the necessary apartment model, it may mean that some
1859e17ebfeca9bb36190ecf145a6d023eae00b4vboxsync * DLL that was indirectly loaded by the process calling this function has
1859e17ebfeca9bb36190ecf145a6d023eae00b4vboxsync * already initialized COM on the given thread in an incompatible way
1859e17ebfeca9bb36190ecf145a6d023eae00b4vboxsync * which we can't leave with. Therefore, we try to fix this by using the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * brute force method: */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Before we use brute force, we need to check if we are in the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * neutral threaded apartment -- in this case there is no need to
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * worry at all. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
fef7670f1122a99df607422af1622eb495f5ba4fvboxsync /* This is a neutral apartment, reset the error */
fef7670f1122a99df607422af1622eb495f5ba4fvboxsync LogFlowFunc (("COM is already initialized in neutral threaded "
fef7670f1122a99df607422af1622eb495f5ba4fvboxsync "apartment mode,\nwill accept it.\n"));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* balance the test CoInitializeEx above */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync LogFlowFunc (("COM is already initialized in single threaded "
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync "apartment mode,\nwill reinitialize as "
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync "multi threaded.\n"));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* We've successfully reinitialized COM; restore the
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * initialization reference counter */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync LogFlowFunc (("Will call CoInitializeEx() %d times.\n",
42634b0ae449be8d087db91b81384bce7a5c21c3vboxsync /* the overall result must be either S_OK or S_FALSE (S_FALSE means
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * "already initialized using the same apartment model") */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync AssertMsg (rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* To be flow compatible with the XPCOM case, we return here if this isn't
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * the main thread or if it isn't its first initialization call.
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Note! CoInitializeEx and CoUninitialize does it's own reference
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * counting, so this exercise is entirely for the EventQueue init. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync RTTHREAD hSelf = RTThreadSelf (); Assert (hSelf != NIL_RTTHREAD);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ASMAtomicCmpXchgHandle (&gCOMMainThread, hSelf, NIL_RTTHREAD, fRc);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* this is the first main thread initialization */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#else /* !defined (VBOX_WITH_XPCOM) */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (ASMAtomicXchgBool (&gIsXPCOMInitialized, true) == true)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* XPCOM is already initialized on the main thread, no special
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * initialization is necessary on additional threads. Just increase
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * the init counter if it's a main thread again (to correctly support
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * nested calls to Initialize()/Shutdown() for compatibility with
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Win32). */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* this is the first initialization */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync bool const fInitEventQueues = true;
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* prepare paths for registry files */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync int vrc = GetVBoxUserHomeDirectory (userHomeDir, sizeof (userHomeDir));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /** @todo use RTPathAppend */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync LogFlowFunc (("component registry : \"%s\"\n", compReg));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync LogFlowFunc (("XPTI data file : \"%s\"\n", xptiDat));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync static const char *kAppPathsToProbe[] =
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Find out the directory where VirtualBox binaries are located */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync for (size_t i = 0; i < RT_ELEMENTS (kAppPathsToProbe); ++ i)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (i == 0)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Use VBOX_APP_HOME if present */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync strncpy (appHomeDir, RTEnvGet ("VBOX_APP_HOME"), RTPATH_MAX - 1); /** @todo r=bird: Use RTEnvGetEx. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync else if (i == 1)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Use RTPathAppPrivateArch() first */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync vrc = RTPathAppPrivateArch (appHomeDir, sizeof (appHomeDir));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Iterate over all other paths */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync strncpy (appHomeDir, kAppPathsToProbe [i], RTPATH_MAX - 1);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync LogFlowFunc (("component directory : \"%s\"\n", compDir));
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = dsProv->init (compReg, xptiDat, compDir, appHomeDir);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Setup the application path for NS_InitXPCOM2. Note that we properly
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * answer the NS_XPCOM_CURRENT_PROCESS_DIR query in our directory
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * service provider but it seems to be activated after the directory
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * service is used for the first time (see the source NS_InitXPCOM2). So
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * use the same value here to be on the safe side. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync vrc = RTStrUtf8ToCurrentCP (&appDirCP, appHomeDir);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = NS_NewNativeLocalFile (nsEmbedCString (appDirCP),
fef7670f1122a99df607422af1622eb495f5ba4fvboxsync /* Set VBOX_XPCOM_HOME to the same app path to make XPCOM sources that
fef7670f1122a99df607422af1622eb495f5ba4fvboxsync * still use it instead of the directory service happy */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* Finally, initialize XPCOM */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync rc = NS_InitXPCOM2 (getter_AddRefs (serviceManager),
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* We succeeded, stop probing paths */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* clean up before the new try */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (i == 0)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* We failed with VBOX_APP_HOME, don't probe other paths */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#endif /* !defined (VBOX_WITH_XPCOM) */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * Init the main event queue (ASSUMES it cannot fail).
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* EventQueue::uninit reference counting fun. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync ASMAtomicWriteHandle (&gCOMMainThread, NIL_RTTHREAD);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#else /* !defined (VBOX_WITH_XPCOM) */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync if (NS_SUCCEEDED(rc) || rc == NS_ERROR_NOT_AVAILABLE)
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* NS_ERROR_NOT_AVAILABLE seems to mean that
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * nsIEventQueue::StopAcceptingEvents() has been called (see
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * nsEventQueueService.cpp). We hope that this error code always means
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * just that in this case and assume that we're on the main thread
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * (it's a kind of unexpected behavior if a non-main thread ever calls
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * StopAcceptingEvents() on the main event queue). */
fef7670f1122a99df607422af1622eb495f5ba4fvboxsync eventQ = nsnull; /* early release before shutdown */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* only the main thread needs to uninitialize XPCOM and only if
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * init counter drops to zero */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync /* This is a thread initialized XPCOM and set gIsXPCOMInitialized to
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync * true. Reset it back to false. */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync bool wasInited = ASMAtomicXchgBool (&gIsXPCOMInitialized, false);
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync#endif /* !defined (VBOX_WITH_XPCOM) */
cf22150eaeeb72431bf1cf65c309a431454fb22bvboxsync} /* namespace com */