VirtualBox

source: vbox/trunk/src/VBox/Main/glue/initterm.cpp@ 8971

Last change on this file since 8971 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.2 KB
Line 
1/** @file
2 * MS COM / XPCOM Abstraction Layer - Initialization and Termination.
3 */
4
5/*
6 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
17 * Clara, CA 95054 USA or visit http://www.sun.com if you need
18 * additional information or have any questions.
19 */
20
21#if !defined (VBOX_WITH_XPCOM)
22
23#include <objbase.h>
24
25#else /* !defined (VBOX_WITH_XPCOM) */
26
27#include <stdlib.h>
28
29/* XPCOM_GLUE is defined when the client uses the standalone glue
30 * (i.e. dynamically picks up the existing XPCOM shared library installation).
31 * This is not the case for VirtualBox XPCOM clients (they are always
32 * distrubuted with the self-built XPCOM library, and therefore have a binary
33 * dependency on it) but left here for clarity.
34 */
35#if defined (XPCOM_GLUE)
36#include <nsXPCOMGlue.h>
37#endif
38
39#include <nsIComponentRegistrar.h>
40#include <nsIServiceManager.h>
41#include <nsCOMPtr.h>
42#include <nsEventQueueUtils.h>
43#include <nsEmbedString.h>
44
45#include <nsILocalFile.h>
46#include <nsIDirectoryService.h>
47#include <nsDirectoryServiceDefs.h>
48
49#endif /* !defined (VBOX_WITH_XPCOM) */
50
51#include <iprt/param.h>
52#include <iprt/path.h>
53#include <iprt/string.h>
54#include <iprt/env.h>
55#include <iprt/asm.h>
56
57#include <VBox/err.h>
58
59#include "VBox/com/com.h"
60#include "VBox/com/assert.h"
61
62#include "../include/Logging.h"
63
64namespace com
65{
66
67#if defined (VBOX_WITH_XPCOM)
68
69class DirectoryServiceProvider : public nsIDirectoryServiceProvider
70{
71public:
72
73 NS_DECL_ISUPPORTS
74
75 DirectoryServiceProvider()
76 : mCompRegLocation (NULL), mXPTIDatLocation (NULL)
77 , mComponentDirLocation (NULL), mCurrProcDirLocation (NULL)
78 {}
79
80 virtual ~DirectoryServiceProvider();
81
82 HRESULT init (const char *aCompRegLocation,
83 const char *aXPTIDatLocation,
84 const char *aComponentDirLocation,
85 const char *aCurrProcDirLocation);
86
87 NS_DECL_NSIDIRECTORYSERVICEPROVIDER
88
89private:
90
91 char *mCompRegLocation;
92 char *mXPTIDatLocation;
93 char *mComponentDirLocation;
94 char *mCurrProcDirLocation;
95};
96
97NS_IMPL_ISUPPORTS1 (DirectoryServiceProvider, nsIDirectoryServiceProvider)
98
99DirectoryServiceProvider::~DirectoryServiceProvider()
100{
101 if (mCompRegLocation)
102 {
103 RTStrFree (mCompRegLocation);
104 mCompRegLocation = NULL;
105 }
106 if (mXPTIDatLocation)
107 {
108 RTStrFree (mXPTIDatLocation);
109 mXPTIDatLocation = NULL;
110 }
111 if (mComponentDirLocation)
112 {
113 RTStrFree (mComponentDirLocation);
114 mComponentDirLocation = NULL;
115 }
116 if (mCurrProcDirLocation)
117 {
118 RTStrFree (mCurrProcDirLocation);
119 mCurrProcDirLocation = NULL;
120 }
121}
122
123/**
124 * @param aCompRegLocation Path to compreg.dat, in Utf8.
125 * @param aXPTIDatLocation Path to xpti.data, in Utf8.
126 */
127HRESULT
128DirectoryServiceProvider::init (const char *aCompRegLocation,
129 const char *aXPTIDatLocation,
130 const char *aComponentDirLocation,
131 const char *aCurrProcDirLocation)
132{
133 AssertReturn (aCompRegLocation, NS_ERROR_INVALID_ARG);
134 AssertReturn (aXPTIDatLocation, NS_ERROR_INVALID_ARG);
135
136 int vrc = RTStrUtf8ToCurrentCP (&mCompRegLocation, aCompRegLocation);
137 if (RT_SUCCESS (vrc))
138 vrc = RTStrUtf8ToCurrentCP (&mXPTIDatLocation, aXPTIDatLocation);
139 if (RT_SUCCESS (vrc) && aComponentDirLocation)
140 vrc = RTStrUtf8ToCurrentCP (&mComponentDirLocation, aComponentDirLocation);
141 if (RT_SUCCESS (vrc) && aCurrProcDirLocation)
142 vrc = RTStrUtf8ToCurrentCP (&mCurrProcDirLocation, aCurrProcDirLocation);
143
144 return RT_SUCCESS (vrc) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
145}
146
147NS_IMETHODIMP
148DirectoryServiceProvider::GetFile (const char *aProp,
149 PRBool *aPersistent,
150 nsIFile **aRetval)
151{
152 nsCOMPtr <nsILocalFile> localFile;
153 nsresult rv = NS_ERROR_FAILURE;
154
155 *aRetval = nsnull;
156 *aPersistent = PR_TRUE;
157
158 const char *fileLocation = NULL;
159
160 if (strcmp (aProp, NS_XPCOM_COMPONENT_REGISTRY_FILE) == 0)
161 fileLocation = mCompRegLocation;
162 else if (strcmp (aProp, NS_XPCOM_XPTI_REGISTRY_FILE) == 0)
163 fileLocation = mXPTIDatLocation;
164 else if (mComponentDirLocation && strcmp (aProp, NS_XPCOM_COMPONENT_DIR) == 0)
165 fileLocation = mComponentDirLocation;
166 else if (mCurrProcDirLocation && strcmp (aProp, NS_XPCOM_CURRENT_PROCESS_DIR) == 0)
167 fileLocation = mCurrProcDirLocation;
168 else
169 return NS_ERROR_FAILURE;
170
171 rv = NS_NewNativeLocalFile (nsEmbedCString (fileLocation),
172 PR_TRUE, getter_AddRefs (localFile));
173 if (NS_FAILED(rv))
174 return rv;
175
176 return localFile->QueryInterface (NS_GET_IID (nsIFile),
177 (void **) aRetval);
178}
179
180/**
181 * Global XPCOM initialization flag (we maintain it ourselves since XPCOM
182 * doesn't provide such functionality)
183 */
184static bool gIsXPCOMInitialized = false;
185
186/**
187 * Number of Initialize() calls on the main thread.
188 */
189static unsigned int gXPCOMInitCount = 0;
190
191#endif /* defined (VBOX_WITH_XPCOM) */
192
193
194HRESULT Initialize()
195{
196 HRESULT rc = E_FAIL;
197
198#if !defined (VBOX_WITH_XPCOM)
199
200 DWORD flags = COINIT_MULTITHREADED |
201 COINIT_DISABLE_OLE1DDE |
202 COINIT_SPEED_OVER_MEMORY;
203
204 rc = CoInitializeEx (NULL, flags);
205
206 /// @todo the below rough method of changing the aparment type doesn't
207 /// work on some systems for unknown reason (CoUninitialize() simply does
208 /// nothing there, or at least all 10 000 of subsequent CoInitializeEx()
209 /// continue to return RPC_E_CHANGED_MODE there). The problem on those
210 /// systems is related to the "Extend support for advanced text services
211 /// to all programs" checkbox in the advanced language settings dialog,
212 /// i.e. the problem appears when this checkbox is checked and disappears
213 /// if you clear it. For this reason, we disable the code below and
214 /// instead initialize COM in MTA as early as possible, before 3rd party
215 /// libraries we use have done so (i.e. Qt3).
216#if 0
217 /* If we fail to set the necessary apartment model, it may mean that some
218 * DLL that was indirectly loaded by the process calling this function has
219 * already initialized COM on the given thread in an incompatible way
220 * which we can't leave with. Therefore, we try to fix this by using the
221 * brute force method: */
222
223 if (rc == RPC_E_CHANGED_MODE)
224 {
225 /* Before we use brute force, we need to check if we are in the
226 * neutral threaded apartment -- in this case there is no need to
227 * worry at all. */
228
229 rc = CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
230 if (rc == RPC_E_CHANGED_MODE)
231 {
232 /* This is a neutral apartment, reset the error */
233 rc = S_OK;
234
235 LogFlowFunc (("COM is already initialized in neutral threaded "
236 "apartment mode,\nwill accept it.\n"));
237 }
238 else if (rc == S_FALSE)
239 {
240 /* balance the test CoInitializeEx above */
241 CoUninitialize();
242 rc = RPC_E_CHANGED_MODE;
243
244 LogFlowFunc (("COM is already initialized in single threaded "
245 "apartment mode,\nwill reinitialize as "
246 "multi threaded.\n"));
247
248 enum { MaxTries = 10000 };
249 int tries = MaxTries;
250 while (rc == RPC_E_CHANGED_MODE && tries --)
251 {
252 CoUninitialize();
253 rc = CoInitializeEx (NULL, flags);
254 if (rc == S_OK)
255 {
256 /* We've successfully reinitialized COM; restore the
257 * initialization reference counter */
258
259 LogFlowFunc (("Will call CoInitializeEx() %d times.\n",
260 MaxTries - tries));
261
262 while (tries ++ < MaxTries)
263 {
264 rc = CoInitializeEx (NULL, flags);
265 Assert (rc == S_FALSE);
266 }
267 }
268 }
269 }
270 else
271 AssertMsgFailed (("rc=%08X\n", rc));
272 }
273#endif
274
275 /* the overall result must be either S_OK or S_FALSE (S_FALSE means
276 * "already initialized using the same apartment model") */
277 AssertMsg (rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc));
278
279#else /* !defined (VBOX_WITH_XPCOM) */
280
281 if (ASMAtomicXchgBool (&gIsXPCOMInitialized, true) == true)
282 {
283 /* XPCOM is already initialized on the main thread, no special
284 * initialization is necessary on additional threads. Just increase
285 * the init counter if it's a main thread again (to correctly support
286 * nested calls to Initialize()/Shutdown() for compatibility with
287 * Win32). */
288
289 nsCOMPtr <nsIEventQueue> eventQ;
290 rc = NS_GetMainEventQ (getter_AddRefs (eventQ));
291
292 if (NS_SUCCEEDED (rc))
293 {
294 PRBool isOnMainThread = PR_FALSE;
295 rc = eventQ->IsOnCurrentThread (&isOnMainThread);
296 if (NS_SUCCEEDED (rc) && isOnMainThread)
297 ++ gXPCOMInitCount;
298 }
299
300 AssertComRC (rc);
301 return rc;
302 }
303
304 /* this is the first initialization */
305 gXPCOMInitCount = 1;
306
307 /* Set VBOX_XPCOM_HOME if not present */
308 if (!RTEnvExist ("VBOX_XPCOM_HOME"))
309 {
310 /* get the executable path */
311 char pathProgram [RTPATH_MAX];
312 int vrc = RTPathProgram (pathProgram, sizeof (pathProgram));
313 if (RT_SUCCESS (vrc))
314 {
315 char *pathProgramCP = NULL;
316 vrc = RTStrUtf8ToCurrentCP (&pathProgramCP, pathProgram);
317 if (RT_SUCCESS (vrc))
318 {
319 vrc = RTEnvSet ("VBOX_XPCOM_HOME", pathProgramCP);
320 RTStrFree (pathProgramCP);
321 }
322 }
323 AssertRC (vrc);
324 }
325
326#if defined (XPCOM_GLUE)
327 XPCOMGlueStartup (nsnull);
328#endif
329
330 nsCOMPtr <DirectoryServiceProvider> dsProv;
331
332 /* prepare paths for registry files */
333 char homeDir [RTPATH_MAX];
334 char privateArchDir [RTPATH_MAX];
335 int vrc = GetVBoxUserHomeDirectory (homeDir, sizeof (homeDir));
336 if (RT_SUCCESS (vrc))
337 vrc = RTPathAppPrivateArch (privateArchDir, sizeof (privateArchDir));
338 if (RT_SUCCESS (vrc))
339 {
340 char compReg [RTPATH_MAX];
341 char xptiDat [RTPATH_MAX];
342 char compDir [RTPATH_MAX];
343
344 RTStrPrintf (compReg, sizeof (compReg), "%s%c%s",
345 homeDir, RTPATH_DELIMITER, "compreg.dat");
346 RTStrPrintf (xptiDat, sizeof (xptiDat), "%s%c%s",
347 homeDir, RTPATH_DELIMITER, "xpti.dat");
348 RTStrPrintf (compDir, sizeof (compDir), "%s%c/components",
349 privateArchDir, RTPATH_DELIMITER);
350
351 LogFlowFunc (("component registry : \"%s\"\n", compReg));
352 LogFlowFunc (("XPTI data file : \"%s\"\n", xptiDat));
353 LogFlowFunc (("component directory : \"%s\"\n", compDir));
354
355 dsProv = new DirectoryServiceProvider();
356 if (dsProv)
357 rc = dsProv->init (compReg, xptiDat, compDir, privateArchDir);
358 else
359 rc = NS_ERROR_OUT_OF_MEMORY;
360 }
361 else
362 rc = NS_ERROR_FAILURE;
363
364 if (NS_SUCCEEDED (rc))
365 {
366 /* get the path to the executable */
367 nsCOMPtr <nsIFile> appDir;
368 {
369 char path [RTPATH_MAX];
370 char *appDirCP = NULL;
371#if defined (DEBUG)
372 const char *env = RTEnvGet ("VIRTUALBOX_APP_HOME");
373 if (env)
374 {
375 char *appDirUtf8 = NULL;
376 vrc = RTStrCurrentCPToUtf8 (&appDirUtf8, env);
377 if (RT_SUCCESS (vrc))
378 {
379 vrc = RTPathReal (appDirUtf8, path, RTPATH_MAX);
380 if (RT_SUCCESS (vrc))
381 vrc = RTStrUtf8ToCurrentCP (&appDirCP, appDirUtf8);
382 RTStrFree (appDirUtf8);
383 }
384 }
385 else
386#endif
387 {
388 vrc = RTPathProgram (path, RTPATH_MAX);
389 if (RT_SUCCESS (vrc))
390 vrc = RTStrUtf8ToCurrentCP (&appDirCP, path);
391 }
392
393 if (RT_SUCCESS (vrc))
394 {
395 nsCOMPtr <nsILocalFile> file;
396 rc = NS_NewNativeLocalFile (nsEmbedCString (appDirCP),
397 PR_FALSE, getter_AddRefs (file));
398 if (NS_SUCCEEDED (rc))
399 appDir = do_QueryInterface (file, &rc);
400
401 RTStrFree (appDirCP);
402 }
403 else
404 rc = NS_ERROR_FAILURE;
405 }
406
407 /* Finally, initialize XPCOM */
408 if (NS_SUCCEEDED (rc))
409 {
410 nsCOMPtr <nsIServiceManager> serviceManager;
411 rc = NS_InitXPCOM2 (getter_AddRefs (serviceManager),
412 appDir, dsProv);
413
414 if (NS_SUCCEEDED (rc))
415 {
416 nsCOMPtr <nsIComponentRegistrar> registrar =
417 do_QueryInterface (serviceManager, &rc);
418 if (NS_SUCCEEDED (rc))
419 registrar->AutoRegister (nsnull);
420 }
421 }
422 }
423
424#endif /* !defined (VBOX_WITH_XPCOM) */
425
426 AssertComRC (rc);
427
428 return rc;
429}
430
431HRESULT Shutdown()
432{
433 HRESULT rc = S_OK;
434
435#if !defined (VBOX_WITH_XPCOM)
436
437 CoUninitialize();
438
439#else /* !defined (VBOX_WITH_XPCOM) */
440
441 nsCOMPtr <nsIEventQueue> eventQ;
442 rc = NS_GetMainEventQ (getter_AddRefs (eventQ));
443
444 if (NS_SUCCEEDED (rc) || rc == NS_ERROR_NOT_AVAILABLE)
445 {
446 /* NS_ERROR_NOT_AVAILABLE seems to mean that
447 * nsIEventQueue::StopAcceptingEvents() has been called (see
448 * nsEventQueueService.cpp). We hope that this error code always means
449 * just that in this case and assume that we're on the main thread
450 * (it's a kind of unexpected behavior if a non-main thread ever calls
451 * StopAcceptingEvents() on the main event queue). */
452
453 PRBool isOnMainThread = PR_FALSE;
454 if (NS_SUCCEEDED (rc))
455 {
456 rc = eventQ->IsOnCurrentThread (&isOnMainThread);
457 eventQ = nsnull; /* early release before shutdown */
458 }
459 else
460 {
461 isOnMainThread = PR_TRUE;
462 rc = NS_OK;
463 }
464
465 if (NS_SUCCEEDED (rc) && isOnMainThread)
466 {
467 /* only the main thread needs to uninitialize XPCOM and only if
468 * init counter drops to zero */
469 if (-- gXPCOMInitCount == 0)
470 {
471 rc = NS_ShutdownXPCOM (nsnull);
472
473 /* This is a thread initialized XPCOM and set gIsXPCOMInitialized to
474 * true. Reset it back to false. */
475 bool wasInited = ASMAtomicXchgBool (&gIsXPCOMInitialized, false);
476 Assert (wasInited == true);
477 NOREF (wasInited);
478
479#if defined (XPCOM_GLUE)
480 XPCOMGlueShutdown();
481#endif
482 }
483 }
484 }
485
486#endif /* !defined (VBOX_WITH_XPCOM) */
487
488 AssertComRC (rc);
489
490 return rc;
491}
492
493} /* namespace com */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette