VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/VirtualBoxBase.cpp@ 91312

Last change on this file since 91312 was 91312, checked in by vboxsync, 3 years ago

Main: bugref:1909: Prepared the API translation engine to using in ExtPacks and VBoxManage. Added using API translation engine in ExtPacks. Allowed VBox compilation with NLS enabled and GUI disabled. Allowed ExtPacks only compilation with NLS translation enabled.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.6 KB
Line 
1/* $Id: VirtualBoxBase.cpp 91312 2021-09-20 11:06:57Z vboxsync $ */
2/** @file
3 * VirtualBox COM base classes implementation
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_MAIN
19#include <iprt/semaphore.h>
20#include <iprt/asm.h>
21#include <iprt/cpp/exception.h>
22
23#include <typeinfo>
24
25#if !defined(VBOX_WITH_XPCOM)
26# include <iprt/win/windows.h>
27#else /* !defined(VBOX_WITH_XPCOM) */
28/// @todo remove when VirtualBoxErrorInfo goes away from here
29# include <nsIServiceManager.h>
30# include <nsIExceptionService.h>
31#endif /* !defined(VBOX_WITH_XPCOM) */
32
33#include "VirtualBoxBase.h"
34#include "AutoCaller.h"
35#include "VirtualBoxErrorInfoImpl.h"
36#include "VirtualBoxTranslator.h"
37#include "Global.h"
38#include "LoggingNew.h"
39
40#include "VBox/com/ErrorInfo.h"
41#include "VBox/com/MultiResult.h"
42
43////////////////////////////////////////////////////////////////////////////////
44//
45// VirtualBoxBase
46//
47////////////////////////////////////////////////////////////////////////////////
48
49CLASSFACTORY_STAT g_aClassFactoryStats[CLASSFACTORYSTATS_MAX] =
50{
51 { "--- totals ---", 0 },
52 { NULL, 0 }
53};
54
55RWLockHandle *g_pClassFactoryStatsLock = NULL;
56
57
58VirtualBoxBase::VirtualBoxBase() :
59 mState(this),
60 iFactoryStat(~0U)
61{
62 mObjectLock = NULL;
63
64 if (!g_pClassFactoryStatsLock)
65 {
66 RWLockHandle *lock = new RWLockHandle(LOCKCLASS_OBJECTSTATE);
67 if (!ASMAtomicCmpXchgPtr(&g_pClassFactoryStatsLock, lock, NULL))
68 delete lock;
69 }
70 Assert(g_pClassFactoryStatsLock);
71}
72
73VirtualBoxBase::~VirtualBoxBase()
74{
75 Assert(iFactoryStat == ~0U);
76 if (mObjectLock)
77 delete mObjectLock;
78}
79
80HRESULT VirtualBoxBase::BaseFinalConstruct()
81{
82 Assert(iFactoryStat == ~0U);
83 if (g_pClassFactoryStatsLock)
84 {
85 AutoWriteLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
86 g_aClassFactoryStats[0].current++;
87 g_aClassFactoryStats[0].overall++;
88 const char *pszName = getComponentName();
89 uint32_t i = 1;
90 while (i < CLASSFACTORYSTATS_MAX && g_aClassFactoryStats[i].psz)
91 {
92 if (g_aClassFactoryStats[i].psz == pszName)
93 break;
94 i++;
95 }
96 if (i < CLASSFACTORYSTATS_MAX)
97 {
98 if (!g_aClassFactoryStats[i].psz)
99 {
100 g_aClassFactoryStats[i].psz = pszName;
101 g_aClassFactoryStats[i].current = 0;
102 g_aClassFactoryStats[i].overall = 0;
103 }
104 iFactoryStat = i;
105 g_aClassFactoryStats[i].current++;
106 g_aClassFactoryStats[i].overall++;
107 }
108 else
109 AssertMsg(i < CLASSFACTORYSTATS_MAX, ("%u exhausts size of factory housekeeping array\n", i));
110 }
111 else
112 Assert(g_pClassFactoryStatsLock);
113
114#ifdef RT_OS_WINDOWS
115 return CoCreateFreeThreadedMarshaler(this, //GetControllingUnknown(),
116 m_pUnkMarshaler.asOutParam());
117#else
118 return S_OK;
119#endif
120}
121
122void VirtualBoxBase::BaseFinalRelease()
123{
124 if (g_pClassFactoryStatsLock)
125 {
126 AutoWriteLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
127 g_aClassFactoryStats[0].current--;
128 const char *pszName = getComponentName();
129 if (iFactoryStat < CLASSFACTORYSTATS_MAX)
130 {
131 if (g_aClassFactoryStats[iFactoryStat].psz == pszName)
132 {
133 g_aClassFactoryStats[iFactoryStat].current--;
134 iFactoryStat = ~0U;
135 }
136 else
137 AssertMsgFailed(("could not find factory housekeeping array entry for %s (index %u contains %s)\n", pszName, iFactoryStat, g_aClassFactoryStats[iFactoryStat].psz));
138 }
139 else
140 AssertMsgFailed(("factory housekeeping array corruption, index %u is too large\n", iFactoryStat));
141 }
142 else
143 Assert(g_pClassFactoryStatsLock);
144
145#ifdef RT_OS_WINDOWS
146 m_pUnkMarshaler.setNull();
147#endif
148}
149
150void APIDumpComponentFactoryStats()
151{
152 if (g_pClassFactoryStatsLock)
153 {
154 AutoReadLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
155 for (uint32_t i = 0; i < CLASSFACTORYSTATS_MAX && g_aClassFactoryStats[i].psz; i++)
156 LogRel(("CFS: component %-30s current %-10u total %-10u\n",
157 g_aClassFactoryStats[i].psz, g_aClassFactoryStats[i].current,
158 g_aClassFactoryStats[i].overall));
159 }
160 else
161 Assert(g_pClassFactoryStatsLock);
162}
163
164/**
165 * This virtual method returns an RWLockHandle that can be used to
166 * protect instance data. This RWLockHandle is generally referred to
167 * as the "object lock"; its locking class (for lock order validation)
168 * must be returned by another virtual method, getLockingClass(), which
169 * by default returns LOCKCLASS_OTHEROBJECT but is overridden by several
170 * subclasses such as VirtualBox, Host, Machine and others.
171 *
172 * On the first call this method lazily creates the RWLockHandle.
173 *
174 * @return
175 */
176/* virtual */
177RWLockHandle *VirtualBoxBase::lockHandle() const
178{
179 /* lazy initialization */
180 if (RT_LIKELY(mObjectLock))
181 return mObjectLock;
182
183 AssertCompile(sizeof(RWLockHandle *) == sizeof(void *));
184
185 // getLockingClass() is overridden by many subclasses to return
186 // one of the locking classes listed at the top of AutoLock.h
187 RWLockHandle *objLock = new RWLockHandle(getLockingClass());
188 if (!ASMAtomicCmpXchgPtr(&mObjectLock, objLock, NULL))
189 {
190 delete objLock;
191 objLock = ASMAtomicReadPtrT(&mObjectLock, RWLockHandle *);
192 }
193 return objLock;
194}
195
196/**
197 * Handles unexpected exceptions by turning them into COM errors in release
198 * builds or by hitting a breakpoint in the release builds.
199 *
200 * Usage pattern:
201 * @code
202 try
203 {
204 // ...
205 }
206 catch (LaLalA)
207 {
208 // ...
209 }
210 catch (...)
211 {
212 rc = VirtualBox::handleUnexpectedExceptions(this, RT_SRC_POS);
213 }
214 * @endcode
215 *
216 * @param aThis object where the exception happened
217 * @param SRC_POS "RT_SRC_POS" macro instantiation.
218 * */
219/* static */
220HRESULT VirtualBoxBase::handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL)
221{
222 try
223 {
224 /* re-throw the current exception */
225 throw;
226 }
227 catch (const RTCError &err) // includes all XML exceptions
228 {
229 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
230 false /* aWarning */,
231 true /* aLogIt */,
232 0 /* aResultDetail */,
233 tr("%s.\n%s[%d] (%s)"),
234 err.what(), pszFile, iLine, pszFunction);
235 }
236 catch (const std::exception &err)
237 {
238 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
239 false /* aWarning */,
240 true /* aLogIt */,
241 0 /* aResultDetail */,
242 tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"),
243 err.what(), typeid(err).name(), pszFile, iLine, pszFunction);
244 }
245 catch (...)
246 {
247 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
248 false /* aWarning */,
249 true /* aLogIt */,
250 0 /* aResultDetail */,
251 tr("Unknown exception\n%s[%d] (%s)"),
252 pszFile, iLine, pszFunction);
253 }
254
255#ifndef _MSC_VER /* (unreachable) */
256 /* should not get here */
257 AssertFailed();
258 return E_FAIL;
259#endif
260}
261
262
263/**
264 * Sets error info for the current thread. This is an internal function that
265 * gets eventually called by all public variants. If @a aWarning is
266 * @c true, then the highest (31) bit in the @a aResultCode value which
267 * indicates the error severity is reset to zero to make sure the receiver will
268 * recognize that the created error info object represents a warning rather
269 * than an error.
270 */
271/* static */
272HRESULT VirtualBoxBase::setErrorInternalF(HRESULT aResultCode,
273 const GUID &aIID,
274 const char *aComponent,
275 bool aWarning,
276 bool aLogIt,
277 LONG aResultDetail,
278 const char *aText, ...)
279{
280 va_list va;
281 va_start(va, aText);
282 HRESULT hres = setErrorInternalV(aResultCode, aIID, aComponent, aText, va,
283 aWarning, aLogIt, aResultDetail);
284 va_end(va);
285 return hres;
286}
287
288/**
289 * Sets error info for the current thread. This is an internal function that
290 * gets eventually called by all public variants. If @a aWarning is
291 * @c true, then the highest (31) bit in the @a aResultCode value which
292 * indicates the error severity is reset to zero to make sure the receiver will
293 * recognize that the created error info object represents a warning rather
294 * than an error.
295 */
296/* static */
297HRESULT VirtualBoxBase::setErrorInternalV(HRESULT aResultCode,
298 const GUID &aIID,
299 const char *aComponent,
300 const char *aText,
301 va_list aArgs,
302 bool aWarning,
303 bool aLogIt,
304 LONG aResultDetail /* = 0*/)
305{
306 /* whether multi-error mode is turned on */
307 bool preserve = MultiResult::isMultiEnabled();
308
309 com::Utf8Str strText;
310 if (aLogIt)
311 {
312#ifdef VBOX_WITH_MAIN_NLS
313 strText = VirtualBoxTranslator::trSource(aText);
314#else
315 strText = aText;
316#endif
317 va_list va2;
318 va_copy(va2, aArgs);
319 LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%N}, preserve=%RTbool aResultDetail=%d\n",
320 aWarning ? "WARNING" : "ERROR",
321 aResultCode,
322 aResultCode,
323 &aIID,
324 aComponent,
325 strText.c_str(),
326 &va2,
327 preserve,
328 aResultDetail));
329 va_end(va2);
330 }
331
332 /* these are mandatory, others -- not */
333 AssertReturn((!aWarning && FAILED(aResultCode)) ||
334 (aWarning && aResultCode != S_OK),
335 E_FAIL);
336
337 /* reset the error severity bit if it's a warning */
338 if (aWarning)
339 aResultCode &= ~0x80000000;
340
341 HRESULT rc = S_OK;
342
343 if (aText == NULL || aText[0] == '\0')
344 {
345 /* Some default info */
346 switch (aResultCode)
347 {
348 case E_INVALIDARG: strText = "A parameter has an invalid value"; break;
349 case E_POINTER: strText = "A parameter is an invalid pointer"; break;
350 case E_UNEXPECTED: strText = "The result of the operation is unexpected"; break;
351 case E_ACCESSDENIED: strText = "The access to an object is not allowed"; break;
352 case E_OUTOFMEMORY: strText = "The allocation of new memory failed"; break;
353 case E_NOTIMPL: strText = "The requested operation is not implemented"; break;
354 case E_NOINTERFACE: strText = "The requested interface is not implemented"; break;
355 case E_FAIL: strText = "A general error occurred"; break;
356 case E_ABORT: strText = "The operation was canceled"; break;
357 case VBOX_E_OBJECT_NOT_FOUND: strText = "Object corresponding to the supplied arguments does not exist"; break;
358 case VBOX_E_INVALID_VM_STATE: strText = "Current virtual machine state prevents the operation"; break;
359 case VBOX_E_VM_ERROR: strText = "Virtual machine error occurred attempting the operation"; break;
360 case VBOX_E_FILE_ERROR: strText = "File not accessible or erroneous file contents"; break;
361 case VBOX_E_IPRT_ERROR: strText = "Runtime subsystem error"; break;
362 case VBOX_E_PDM_ERROR: strText = "Pluggable Device Manager error"; break;
363 case VBOX_E_INVALID_OBJECT_STATE: strText = "Current object state prohibits operation"; break;
364 case VBOX_E_HOST_ERROR: strText = "Host operating system related error"; break;
365 case VBOX_E_NOT_SUPPORTED: strText = "Requested operation is not supported"; break;
366 case VBOX_E_XML_ERROR: strText = "Invalid XML found"; break;
367 case VBOX_E_INVALID_SESSION_STATE: strText = "Current session state prohibits operation"; break;
368 case VBOX_E_OBJECT_IN_USE: strText = "Object being in use prohibits operation"; break;
369 case VBOX_E_PASSWORD_INCORRECT: strText = "Incorrect password provided"; break;
370 default: strText = "Unknown error"; break;
371 }
372 }
373 else
374 {
375 va_list va2;
376 va_copy(va2, aArgs);
377 strText = com::Utf8StrFmt("%N", aText, &va2);
378 va_end(va2);
379 }
380
381 do
382 {
383 ComObjPtr<VirtualBoxErrorInfo> info;
384 rc = info.createObject();
385 if (FAILED(rc)) break;
386
387#if !defined(VBOX_WITH_XPCOM)
388
389 ComPtr<IVirtualBoxErrorInfo> curInfo;
390 if (preserve)
391 {
392 /* get the current error info if any */
393 ComPtr<IErrorInfo> err;
394 rc = ::GetErrorInfo(0, err.asOutParam());
395 if (FAILED(rc)) break;
396 rc = err.queryInterfaceTo(curInfo.asOutParam());
397 if (FAILED(rc))
398 {
399 /* create a IVirtualBoxErrorInfo wrapper for the native
400 * IErrorInfo object */
401 ComObjPtr<VirtualBoxErrorInfo> wrapper;
402 rc = wrapper.createObject();
403 if (SUCCEEDED(rc))
404 {
405 rc = wrapper->init(err);
406 if (SUCCEEDED(rc))
407 curInfo = wrapper;
408 }
409 }
410 }
411 /* On failure, curInfo will stay null */
412 Assert(SUCCEEDED(rc) || curInfo.isNull());
413
414 /* set the current error info and preserve the previous one if any */
415 rc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, strText, curInfo);
416 if (FAILED(rc)) break;
417
418 ComPtr<IErrorInfo> err;
419 rc = info.queryInterfaceTo(err.asOutParam());
420 if (SUCCEEDED(rc))
421 rc = ::SetErrorInfo(0, err);
422
423#else // !defined(VBOX_WITH_XPCOM)
424
425 nsCOMPtr <nsIExceptionService> es;
426 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
427 if (NS_SUCCEEDED(rc))
428 {
429 nsCOMPtr <nsIExceptionManager> em;
430 rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
431 if (FAILED(rc)) break;
432
433 ComPtr<IVirtualBoxErrorInfo> curInfo;
434 if (preserve)
435 {
436 /* get the current error info if any */
437 ComPtr<nsIException> ex;
438 rc = em->GetCurrentException(ex.asOutParam());
439 if (FAILED(rc)) break;
440 rc = ex.queryInterfaceTo(curInfo.asOutParam());
441 if (FAILED(rc))
442 {
443 /* create a IVirtualBoxErrorInfo wrapper for the native
444 * nsIException object */
445 ComObjPtr<VirtualBoxErrorInfo> wrapper;
446 rc = wrapper.createObject();
447 if (SUCCEEDED(rc))
448 {
449 rc = wrapper->init(ex);
450 if (SUCCEEDED(rc))
451 curInfo = wrapper;
452 }
453 }
454 }
455 /* On failure, curInfo will stay null */
456 Assert(SUCCEEDED(rc) || curInfo.isNull());
457
458 /* set the current error info and preserve the previous one if any */
459 rc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, Bstr(strText), curInfo);
460 if (FAILED(rc)) break;
461
462 ComPtr<nsIException> ex;
463 rc = info.queryInterfaceTo(ex.asOutParam());
464 if (SUCCEEDED(rc))
465 rc = em->SetCurrentException(ex);
466 }
467 else if (rc == NS_ERROR_UNEXPECTED)
468 {
469 /*
470 * It is possible that setError() is being called by the object
471 * after the XPCOM shutdown sequence has been initiated
472 * (for example, when XPCOM releases all instances it internally
473 * references, which can cause object's FinalConstruct() and then
474 * uninit()). In this case, do_GetService() above will return
475 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
476 * set the exception (nobody will be able to read it).
477 */
478 Log1WarningFunc(("Will not set an exception because nsIExceptionService is not available (NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n"));
479 rc = NS_OK;
480 }
481
482#endif // !defined(VBOX_WITH_XPCOM)
483 }
484 while (0);
485
486 AssertComRC(rc);
487
488 return SUCCEEDED(rc) ? aResultCode : rc;
489}
490
491/**
492 * Shortcut instance method to calling the static setErrorInternal with the
493 * class interface ID and component name inserted correctly. This uses the
494 * virtual getClassIID() and getComponentName() methods which are automatically
495 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
496 * @param aResultCode
497 * @return
498 */
499HRESULT VirtualBoxBase::setError(HRESULT aResultCode)
500{
501 return setErrorInternalF(aResultCode,
502 this->getClassIID(),
503 this->getComponentName(),
504 false /* aWarning */,
505 true /* aLogIt */,
506 0 /* aResultDetail */,
507 NULL);
508}
509
510/**
511 * Shortcut instance method to calling the static setErrorInternal with the
512 * class interface ID and component name inserted correctly. This uses the
513 * virtual getClassIID() and getComponentName() methods which are automatically
514 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
515 * @param aResultCode
516 * @param pcsz
517 * @return
518 */
519HRESULT VirtualBoxBase::setError(HRESULT aResultCode, const char *pcsz, ...)
520{
521 va_list args;
522 va_start(args, pcsz);
523 HRESULT rc = setErrorInternalV(aResultCode,
524 this->getClassIID(),
525 this->getComponentName(),
526 pcsz, args,
527 false /* aWarning */,
528 true /* aLogIt */);
529 va_end(args);
530 return rc;
531}
532
533/**
534 * Shortcut instance method to calling the static setErrorInternal with the
535 * class interface ID and component name inserted correctly. This uses the
536 * virtual getClassIID() and getComponentName() methods which are automatically
537 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
538 * @param ei
539 * @return
540 */
541HRESULT VirtualBoxBase::setError(const com::ErrorInfo &ei)
542{
543 /* whether multi-error mode is turned on */
544 bool preserve = MultiResult::isMultiEnabled();
545
546 HRESULT rc = S_OK;
547
548 do
549 {
550 ComObjPtr<VirtualBoxErrorInfo> info;
551 rc = info.createObject();
552 if (FAILED(rc)) break;
553
554#if !defined(VBOX_WITH_XPCOM)
555
556 ComPtr<IVirtualBoxErrorInfo> curInfo;
557 if (preserve)
558 {
559 /* get the current error info if any */
560 ComPtr<IErrorInfo> err;
561 rc = ::GetErrorInfo(0, err.asOutParam());
562 if (FAILED(rc)) break;
563 rc = err.queryInterfaceTo(curInfo.asOutParam());
564 if (FAILED(rc))
565 {
566 /* create a IVirtualBoxErrorInfo wrapper for the native
567 * IErrorInfo object */
568 ComObjPtr<VirtualBoxErrorInfo> wrapper;
569 rc = wrapper.createObject();
570 if (SUCCEEDED(rc))
571 {
572 rc = wrapper->init(err);
573 if (SUCCEEDED(rc))
574 curInfo = wrapper;
575 }
576 }
577 }
578 /* On failure, curInfo will stay null */
579 Assert(SUCCEEDED(rc) || curInfo.isNull());
580
581 /* set the current error info and preserve the previous one if any */
582 rc = info->init(ei, curInfo);
583 if (FAILED(rc)) break;
584
585 ComPtr<IErrorInfo> err;
586 rc = info.queryInterfaceTo(err.asOutParam());
587 if (SUCCEEDED(rc))
588 rc = ::SetErrorInfo(0, err);
589
590#else // !defined(VBOX_WITH_XPCOM)
591
592 nsCOMPtr <nsIExceptionService> es;
593 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
594 if (NS_SUCCEEDED(rc))
595 {
596 nsCOMPtr <nsIExceptionManager> em;
597 rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
598 if (FAILED(rc)) break;
599
600 ComPtr<IVirtualBoxErrorInfo> curInfo;
601 if (preserve)
602 {
603 /* get the current error info if any */
604 ComPtr<nsIException> ex;
605 rc = em->GetCurrentException(ex.asOutParam());
606 if (FAILED(rc)) break;
607 rc = ex.queryInterfaceTo(curInfo.asOutParam());
608 if (FAILED(rc))
609 {
610 /* create a IVirtualBoxErrorInfo wrapper for the native
611 * nsIException object */
612 ComObjPtr<VirtualBoxErrorInfo> wrapper;
613 rc = wrapper.createObject();
614 if (SUCCEEDED(rc))
615 {
616 rc = wrapper->init(ex);
617 if (SUCCEEDED(rc))
618 curInfo = wrapper;
619 }
620 }
621 }
622 /* On failure, curInfo will stay null */
623 Assert(SUCCEEDED(rc) || curInfo.isNull());
624
625 /* set the current error info and preserve the previous one if any */
626 rc = info->init(ei, curInfo);
627 if (FAILED(rc)) break;
628
629 ComPtr<nsIException> ex;
630 rc = info.queryInterfaceTo(ex.asOutParam());
631 if (SUCCEEDED(rc))
632 rc = em->SetCurrentException(ex);
633 }
634 else if (rc == NS_ERROR_UNEXPECTED)
635 {
636 /*
637 * It is possible that setError() is being called by the object
638 * after the XPCOM shutdown sequence has been initiated
639 * (for example, when XPCOM releases all instances it internally
640 * references, which can cause object's FinalConstruct() and then
641 * uninit()). In this case, do_GetService() above will return
642 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
643 * set the exception (nobody will be able to read it).
644 */
645 Log1WarningFunc(("Will not set an exception because nsIExceptionService is not available (NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n"));
646 rc = NS_OK;
647 }
648
649#endif // !defined(VBOX_WITH_XPCOM)
650 }
651 while (0);
652
653 AssertComRC(rc);
654
655 return SUCCEEDED(rc) ? ei.getResultCode() : rc;
656}
657
658/**
659 * Converts the VBox status code a COM one and sets the error info.
660 *
661 * The VBox status code is made available to the API user via
662 * IVirtualBoxErrorInfo::resultDetail attribute.
663 *
664 * @param vrc The VBox status code.
665 * @return COM status code appropriate for @a vrc.
666 *
667 * @sa VirtualBoxBase::setError(HRESULT)
668 */
669HRESULT VirtualBoxBase::setErrorVrc(int vrc)
670{
671 return setErrorInternalF(Global::vboxStatusCodeToCOM(vrc),
672 this->getClassIID(),
673 this->getComponentName(),
674 false /* aWarning */,
675 true /* aLogIt */,
676 vrc /* aResultDetail */,
677 Utf8StrFmt("%Rrc", vrc).c_str());
678}
679
680/**
681 * Converts the VBox status code a COM one and sets the error info.
682 *
683 * @param vrc The VBox status code.
684 * @param pcszMsgFmt Error message format string.
685 * @param ... Argument specified in the @a pcszMsgFmt
686 * @return COM status code appropriate for @a vrc.
687 *
688 * @sa VirtualBoxBase::setError(HRESULT, const char *, ...)
689 */
690HRESULT VirtualBoxBase::setErrorVrc(int vrc, const char *pcszMsgFmt, ...)
691{
692 va_list va;
693 va_start(va, pcszMsgFmt);
694 HRESULT hrc = setErrorInternalV(Global::vboxStatusCodeToCOM(vrc),
695 this->getClassIID(),
696 this->getComponentName(),
697 pcszMsgFmt, va,
698 false /* aWarning */,
699 true /* aLogIt */,
700 vrc /* aResultDetail */);
701 va_end(va);
702 return hrc;
703}
704
705/**
706 * Sets error info with both a COM status and an VBox status code.
707 *
708 * The VBox status code is made available to the API user via
709 * IVirtualBoxErrorInfo::resultDetail attribute.
710 *
711 * @param hrc The COM status code to return.
712 * @param vrc The VBox status code.
713 * @return Most likely @a hrc, see setErrorInternal.
714 *
715 * @sa VirtualBoxBase::setError(HRESULT)
716 */
717HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc)
718{
719 return setErrorInternalF(hrc,
720 this->getClassIID(),
721 this->getComponentName(),
722 false /* aWarning */,
723 true /* aLogIt */,
724 vrc /* aResultDetail */,
725 Utf8StrFmt("%Rrc", vrc).c_str());
726}
727
728/**
729 * Sets error info with a message and both a COM status and an VBox status code.
730 *
731 * The VBox status code is made available to the API user via
732 * IVirtualBoxErrorInfo::resultDetail attribute.
733 *
734 * @param hrc The COM status code to return.
735 * @param vrc The VBox status code.
736 * @param pcszMsgFmt Error message format string.
737 * @param ... Argument specified in the @a pcszMsgFmt
738 * @return Most likely @a hrc, see setErrorInternal.
739 *
740 * @sa VirtualBoxBase::setError(HRESULT, const char *, ...)
741 */
742HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc, const char *pcszMsgFmt, ...)
743{
744 va_list va;
745 va_start(va, pcszMsgFmt);
746 hrc = setErrorInternalV(hrc,
747 this->getClassIID(),
748 this->getComponentName(),
749 pcszMsgFmt, va,
750 false /* aWarning */,
751 true /* aLogIt */,
752 vrc /* aResultDetail */);
753 va_end(va);
754 return hrc;
755}
756
757/**
758 * Like setError(), but sets the "warning" bit in the call to setErrorInternal().
759 * @param aResultCode
760 * @param pcsz
761 * @return
762 */
763HRESULT VirtualBoxBase::setWarning(HRESULT aResultCode, const char *pcsz, ...)
764{
765 va_list args;
766 va_start(args, pcsz);
767 HRESULT rc = setErrorInternalV(aResultCode,
768 this->getClassIID(),
769 this->getComponentName(),
770 pcsz, args,
771 true /* aWarning */,
772 true /* aLogIt */);
773 va_end(args);
774 return rc;
775}
776
777/**
778 * Like setError(), but disables the "log" flag in the call to setErrorInternal().
779 * @param aResultCode
780 * @param pcsz
781 * @return
782 */
783HRESULT VirtualBoxBase::setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...)
784{
785 va_list args;
786 va_start(args, pcsz);
787 HRESULT rc = setErrorInternalV(aResultCode,
788 this->getClassIID(),
789 this->getComponentName(),
790 pcsz, args,
791 false /* aWarning */,
792 false /* aLogIt */);
793 va_end(args);
794 return rc;
795}
796
797/**
798 * Clear the current error information.
799 */
800/*static*/
801void VirtualBoxBase::clearError(void)
802{
803#if !defined(VBOX_WITH_XPCOM)
804 ::SetErrorInfo(0, NULL);
805#else
806 HRESULT rc = S_OK;
807 nsCOMPtr <nsIExceptionService> es;
808 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
809 if (NS_SUCCEEDED(rc))
810 {
811 nsCOMPtr <nsIExceptionManager> em;
812 rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
813 if (SUCCEEDED(rc))
814 em->SetCurrentException(NULL);
815 }
816#endif
817}
818
819
820////////////////////////////////////////////////////////////////////////////////
821//
822// MultiResult methods
823//
824////////////////////////////////////////////////////////////////////////////////
825
826RTTLS MultiResult::sCounter = NIL_RTTLS;
827
828/*static*/
829void MultiResult::incCounter()
830{
831 if (sCounter == NIL_RTTLS)
832 {
833 sCounter = RTTlsAlloc();
834 AssertReturnVoid(sCounter != NIL_RTTLS);
835 }
836
837 uintptr_t counter = (uintptr_t)RTTlsGet(sCounter);
838 ++counter;
839 RTTlsSet(sCounter, (void*)counter);
840}
841
842/*static*/
843void MultiResult::decCounter()
844{
845 uintptr_t counter = (uintptr_t)RTTlsGet(sCounter);
846 AssertReturnVoid(counter != 0);
847 --counter;
848 RTTlsSet(sCounter, (void*)counter);
849}
850
851/*static*/
852bool MultiResult::isMultiEnabled()
853{
854 if (sCounter == NIL_RTTLS)
855 return false;
856
857 return ((uintptr_t)RTTlsGet(MultiResult::sCounter)) > 0;
858}
859
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