VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use