VirtualBox

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

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

Main/GUI/Win32: Don't apply the brute force STA to MTA change hack since it doesn't work on all systems; instead initialize COM before Qt to enter MTA first.

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