VirtualBox

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

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

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.7 KB
Line 
1/* $Id: VirtualBoxBase.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtualBox COM base classes implementation
4 */
5
6/*
7 * Copyright (C) 2006-2022 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 "%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 = tr("A parameter has an invalid value"); break;
349 case E_POINTER: strText = tr("A parameter is an invalid pointer"); break;
350 case E_UNEXPECTED: strText = tr("The result of the operation is unexpected"); break;
351 case E_ACCESSDENIED: strText = tr("The access to an object is not allowed"); break;
352 case E_OUTOFMEMORY: strText = tr("The allocation of new memory failed"); break;
353 case E_NOTIMPL: strText = tr("The requested operation is not implemented"); break;
354 case E_NOINTERFACE: strText = tr("The requested interface is not implemented"); break;
355 case E_FAIL: strText = tr("A general error occurred"); break;
356 case E_ABORT: strText = tr("The operation was canceled"); break;
357 case VBOX_E_OBJECT_NOT_FOUND: strText = tr("Object corresponding to the supplied arguments does not exist"); break;
358 case VBOX_E_INVALID_VM_STATE: strText = tr("Current virtual machine state prevents the operation"); break;
359 case VBOX_E_VM_ERROR: strText = tr("Virtual machine error occurred attempting the operation"); break;
360 case VBOX_E_FILE_ERROR: strText = tr("File not accessible or erroneous file contents"); break;
361 case VBOX_E_IPRT_ERROR: strText = tr("Runtime subsystem error"); break;
362 case VBOX_E_PDM_ERROR: strText = tr("Pluggable Device Manager error"); break;
363 case VBOX_E_INVALID_OBJECT_STATE: strText = tr("Current object state prohibits operation"); break;
364 case VBOX_E_HOST_ERROR: strText = tr("Host operating system related error"); break;
365 case VBOX_E_NOT_SUPPORTED: strText = tr("Requested operation is not supported"); break;
366 case VBOX_E_XML_ERROR: strText = tr("Invalid XML found"); break;
367 case VBOX_E_INVALID_SESSION_STATE: strText = tr("Current session state prohibits operation"); break;
368 case VBOX_E_OBJECT_IN_USE: strText = tr("Object being in use prohibits operation"); break;
369 case VBOX_E_PASSWORD_INCORRECT: strText = tr("Incorrect password provided"); break;
370 default: strText = tr("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