VirtualBox

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

Last change on this file since 83176 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.1 KB
Line 
1/* $Id: VirtualBoxBase.cpp 82968 2020-02-04 10:35:17Z 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#include <dbghelp.h>
28#else /* !defined(VBOX_WITH_XPCOM) */
29/// @todo remove when VirtualBoxErrorInfo goes away from here
30#include <nsIServiceManager.h>
31#include <nsIExceptionService.h>
32#endif /* !defined(VBOX_WITH_XPCOM) */
33
34#include "VirtualBoxBase.h"
35#include "AutoCaller.h"
36#include "VirtualBoxErrorInfoImpl.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 setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
230 Utf8StrFmt(tr("%s.\n%s[%d] (%s)"),
231 err.what(),
232 pszFile, iLine, pszFunction).c_str(),
233 false /* aWarning */,
234 true /* aLogIt */);
235 }
236 catch (const std::exception &err)
237 {
238 return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
239 Utf8StrFmt(tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"),
240 err.what(), typeid(err).name(),
241 pszFile, iLine, pszFunction).c_str(),
242 false /* aWarning */,
243 true /* aLogIt */);
244 }
245 catch (...)
246 {
247 return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
248 Utf8StrFmt(tr("Unknown exception\n%s[%d] (%s)"),
249 pszFile, iLine, pszFunction).c_str(),
250 false /* aWarning */,
251 true /* aLogIt */);
252 }
253
254#ifndef _MSC_VER /* (unreachable) */
255 /* should not get here */
256 AssertFailed();
257 return E_FAIL;
258#endif
259}
260
261/**
262 * Sets error info for the current thread. This is an internal function that
263 * gets eventually called by all public variants. If @a aWarning is
264 * @c true, then the highest (31) bit in the @a aResultCode value which
265 * indicates the error severity is reset to zero to make sure the receiver will
266 * recognize that the created error info object represents a warning rather
267 * than an error.
268 *
269 * @param aResultCode
270 * @param aIID
271 * @param pcszComponent
272 * @param aText
273 * @param aWarning
274 * @param aLogIt
275 * @param aResultDetail
276 */
277/* static */
278HRESULT VirtualBoxBase::setErrorInternal(HRESULT aResultCode,
279 const GUID &aIID,
280 const char *pcszComponent,
281 Utf8Str aText,
282 bool aWarning,
283 bool aLogIt,
284 LONG aResultDetail /* = 0*/)
285{
286 /* whether multi-error mode is turned on */
287 bool preserve = MultiResult::isMultiEnabled();
288
289 if (aLogIt)
290 LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%s}, preserve=%RTbool aResultDetail=%d\n",
291 aWarning ? "WARNING" : "ERROR",
292 aResultCode,
293 aResultCode,
294 &aIID,
295 pcszComponent,
296 aText.c_str(),
297 preserve,
298 aResultDetail));
299
300 /* these are mandatory, others -- not */
301 AssertReturn((!aWarning && FAILED(aResultCode)) ||
302 (aWarning && aResultCode != S_OK),
303 E_FAIL);
304
305 /* reset the error severity bit if it's a warning */
306 if (aWarning)
307 aResultCode &= ~0x80000000;
308
309 HRESULT rc = S_OK;
310
311 if (aText.isEmpty())
312 {
313 /* Some default info */
314 switch (aResultCode)
315 {
316 case E_INVALIDARG: aText = "A parameter has an invalid value"; break;
317 case E_POINTER: aText = "A parameter is an invalid pointer"; break;
318 case E_UNEXPECTED: aText = "The result of the operation is unexpected"; break;
319 case E_ACCESSDENIED: aText = "The access to an object is not allowed"; break;
320 case E_OUTOFMEMORY: aText = "The allocation of new memory failed"; break;
321 case E_NOTIMPL: aText = "The requested operation is not implemented"; break;
322 case E_NOINTERFACE: aText = "The requested interface is not implemented"; break;
323 case E_FAIL: aText = "A general error occurred"; break;
324 case E_ABORT: aText = "The operation was canceled"; break;
325 case VBOX_E_OBJECT_NOT_FOUND: aText = "Object corresponding to the supplied arguments does not exist"; break;
326 case VBOX_E_INVALID_VM_STATE: aText = "Current virtual machine state prevents the operation"; break;
327 case VBOX_E_VM_ERROR: aText = "Virtual machine error occurred attempting the operation"; break;
328 case VBOX_E_FILE_ERROR: aText = "File not accessible or erroneous file contents"; break;
329 case VBOX_E_IPRT_ERROR: aText = "Runtime subsystem error"; break;
330 case VBOX_E_PDM_ERROR: aText = "Pluggable Device Manager error"; break;
331 case VBOX_E_INVALID_OBJECT_STATE: aText = "Current object state prohibits operation"; break;
332 case VBOX_E_HOST_ERROR: aText = "Host operating system related error"; break;
333 case VBOX_E_NOT_SUPPORTED: aText = "Requested operation is not supported"; break;
334 case VBOX_E_XML_ERROR: aText = "Invalid XML found"; break;
335 case VBOX_E_INVALID_SESSION_STATE: aText = "Current session state prohibits operation"; break;
336 case VBOX_E_OBJECT_IN_USE: aText = "Object being in use prohibits operation"; break;
337 case VBOX_E_PASSWORD_INCORRECT: aText = "Incorrect password provided"; break;
338 default: aText = "Unknown error"; break;
339 }
340 }
341
342 do
343 {
344 ComObjPtr<VirtualBoxErrorInfo> info;
345 rc = info.createObject();
346 if (FAILED(rc)) break;
347
348#if !defined(VBOX_WITH_XPCOM)
349
350 ComPtr<IVirtualBoxErrorInfo> curInfo;
351 if (preserve)
352 {
353 /* get the current error info if any */
354 ComPtr<IErrorInfo> err;
355 rc = ::GetErrorInfo(0, err.asOutParam());
356 if (FAILED(rc)) break;
357 rc = err.queryInterfaceTo(curInfo.asOutParam());
358 if (FAILED(rc))
359 {
360 /* create a IVirtualBoxErrorInfo wrapper for the native
361 * IErrorInfo object */
362 ComObjPtr<VirtualBoxErrorInfo> wrapper;
363 rc = wrapper.createObject();
364 if (SUCCEEDED(rc))
365 {
366 rc = wrapper->init(err);
367 if (SUCCEEDED(rc))
368 curInfo = wrapper;
369 }
370 }
371 }
372 /* On failure, curInfo will stay null */
373 Assert(SUCCEEDED(rc) || curInfo.isNull());
374
375 /* set the current error info and preserve the previous one if any */
376 rc = info->initEx(aResultCode, aResultDetail, aIID, pcszComponent, aText, curInfo);
377 if (FAILED(rc)) break;
378
379 ComPtr<IErrorInfo> err;
380 rc = info.queryInterfaceTo(err.asOutParam());
381 if (SUCCEEDED(rc))
382 rc = ::SetErrorInfo(0, err);
383
384#else // !defined(VBOX_WITH_XPCOM)
385
386 nsCOMPtr <nsIExceptionService> es;
387 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
388 if (NS_SUCCEEDED(rc))
389 {
390 nsCOMPtr <nsIExceptionManager> em;
391 rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
392 if (FAILED(rc)) break;
393
394 ComPtr<IVirtualBoxErrorInfo> curInfo;
395 if (preserve)
396 {
397 /* get the current error info if any */
398 ComPtr<nsIException> ex;
399 rc = em->GetCurrentException(ex.asOutParam());
400 if (FAILED(rc)) break;
401 rc = ex.queryInterfaceTo(curInfo.asOutParam());
402 if (FAILED(rc))
403 {
404 /* create a IVirtualBoxErrorInfo wrapper for the native
405 * nsIException object */
406 ComObjPtr<VirtualBoxErrorInfo> wrapper;
407 rc = wrapper.createObject();
408 if (SUCCEEDED(rc))
409 {
410 rc = wrapper->init(ex);
411 if (SUCCEEDED(rc))
412 curInfo = wrapper;
413 }
414 }
415 }
416 /* On failure, curInfo will stay null */
417 Assert(SUCCEEDED(rc) || curInfo.isNull());
418
419 /* set the current error info and preserve the previous one if any */
420 rc = info->initEx(aResultCode, aResultDetail, aIID, pcszComponent, Bstr(aText), curInfo);
421 if (FAILED(rc)) break;
422
423 ComPtr<nsIException> ex;
424 rc = info.queryInterfaceTo(ex.asOutParam());
425 if (SUCCEEDED(rc))
426 rc = em->SetCurrentException(ex);
427 }
428 else if (rc == NS_ERROR_UNEXPECTED)
429 {
430 /*
431 * It is possible that setError() is being called by the object
432 * after the XPCOM shutdown sequence has been initiated
433 * (for example, when XPCOM releases all instances it internally
434 * references, which can cause object's FinalConstruct() and then
435 * uninit()). In this case, do_GetService() above will return
436 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
437 * set the exception (nobody will be able to read it).
438 */
439 Log1WarningFunc(("Will not set an exception because nsIExceptionService is not available (NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n"));
440 rc = NS_OK;
441 }
442
443#endif // !defined(VBOX_WITH_XPCOM)
444 }
445 while (0);
446
447 AssertComRC(rc);
448
449 return SUCCEEDED(rc) ? aResultCode : rc;
450}
451
452/**
453 * Shortcut instance method to calling the static setErrorInternal with the
454 * class interface ID and component name inserted correctly. This uses the
455 * virtual getClassIID() and getComponentName() methods which are automatically
456 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
457 * @param aResultCode
458 * @return
459 */
460HRESULT VirtualBoxBase::setError(HRESULT aResultCode)
461{
462 return setErrorInternal(aResultCode,
463 this->getClassIID(),
464 this->getComponentName(),
465 "",
466 false /* aWarning */,
467 true /* aLogIt */);
468}
469
470/**
471 * Shortcut instance method to calling the static setErrorInternal with the
472 * class interface ID and component name inserted correctly. This uses the
473 * virtual getClassIID() and getComponentName() methods which are automatically
474 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
475 * @param aResultCode
476 * @param pcsz
477 * @return
478 */
479HRESULT VirtualBoxBase::setError(HRESULT aResultCode, const char *pcsz, ...)
480{
481 va_list args;
482 va_start(args, pcsz);
483 HRESULT rc = setErrorInternal(aResultCode,
484 this->getClassIID(),
485 this->getComponentName(),
486 Utf8Str(pcsz, args),
487 false /* aWarning */,
488 true /* aLogIt */);
489 va_end(args);
490 return rc;
491}
492
493/**
494 * Shortcut instance method to calling the static setErrorInternal with the
495 * class interface ID and component name inserted correctly. This uses the
496 * virtual getClassIID() and getComponentName() methods which are automatically
497 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
498 * @param ei
499 * @return
500 */
501HRESULT VirtualBoxBase::setError(const com::ErrorInfo &ei)
502{
503 /* whether multi-error mode is turned on */
504 bool preserve = MultiResult::isMultiEnabled();
505
506 HRESULT rc = S_OK;
507
508 do
509 {
510 ComObjPtr<VirtualBoxErrorInfo> info;
511 rc = info.createObject();
512 if (FAILED(rc)) break;
513
514#if !defined(VBOX_WITH_XPCOM)
515
516 ComPtr<IVirtualBoxErrorInfo> curInfo;
517 if (preserve)
518 {
519 /* get the current error info if any */
520 ComPtr<IErrorInfo> err;
521 rc = ::GetErrorInfo(0, err.asOutParam());
522 if (FAILED(rc)) break;
523 rc = err.queryInterfaceTo(curInfo.asOutParam());
524 if (FAILED(rc))
525 {
526 /* create a IVirtualBoxErrorInfo wrapper for the native
527 * IErrorInfo object */
528 ComObjPtr<VirtualBoxErrorInfo> wrapper;
529 rc = wrapper.createObject();
530 if (SUCCEEDED(rc))
531 {
532 rc = wrapper->init(err);
533 if (SUCCEEDED(rc))
534 curInfo = wrapper;
535 }
536 }
537 }
538 /* On failure, curInfo will stay null */
539 Assert(SUCCEEDED(rc) || curInfo.isNull());
540
541 /* set the current error info and preserve the previous one if any */
542 rc = info->init(ei, curInfo);
543 if (FAILED(rc)) break;
544
545 ComPtr<IErrorInfo> err;
546 rc = info.queryInterfaceTo(err.asOutParam());
547 if (SUCCEEDED(rc))
548 rc = ::SetErrorInfo(0, err);
549
550#else // !defined(VBOX_WITH_XPCOM)
551
552 nsCOMPtr <nsIExceptionService> es;
553 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
554 if (NS_SUCCEEDED(rc))
555 {
556 nsCOMPtr <nsIExceptionManager> em;
557 rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
558 if (FAILED(rc)) break;
559
560 ComPtr<IVirtualBoxErrorInfo> curInfo;
561 if (preserve)
562 {
563 /* get the current error info if any */
564 ComPtr<nsIException> ex;
565 rc = em->GetCurrentException(ex.asOutParam());
566 if (FAILED(rc)) break;
567 rc = ex.queryInterfaceTo(curInfo.asOutParam());
568 if (FAILED(rc))
569 {
570 /* create a IVirtualBoxErrorInfo wrapper for the native
571 * nsIException object */
572 ComObjPtr<VirtualBoxErrorInfo> wrapper;
573 rc = wrapper.createObject();
574 if (SUCCEEDED(rc))
575 {
576 rc = wrapper->init(ex);
577 if (SUCCEEDED(rc))
578 curInfo = wrapper;
579 }
580 }
581 }
582 /* On failure, curInfo will stay null */
583 Assert(SUCCEEDED(rc) || curInfo.isNull());
584
585 /* set the current error info and preserve the previous one if any */
586 rc = info->init(ei, curInfo);
587 if (FAILED(rc)) break;
588
589 ComPtr<nsIException> ex;
590 rc = info.queryInterfaceTo(ex.asOutParam());
591 if (SUCCEEDED(rc))
592 rc = em->SetCurrentException(ex);
593 }
594 else if (rc == NS_ERROR_UNEXPECTED)
595 {
596 /*
597 * It is possible that setError() is being called by the object
598 * after the XPCOM shutdown sequence has been initiated
599 * (for example, when XPCOM releases all instances it internally
600 * references, which can cause object's FinalConstruct() and then
601 * uninit()). In this case, do_GetService() above will return
602 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
603 * set the exception (nobody will be able to read it).
604 */
605 Log1WarningFunc(("Will not set an exception because nsIExceptionService is not available (NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n"));
606 rc = NS_OK;
607 }
608
609#endif // !defined(VBOX_WITH_XPCOM)
610 }
611 while (0);
612
613 AssertComRC(rc);
614
615 return SUCCEEDED(rc) ? ei.getResultCode() : rc;
616}
617
618/**
619 * Converts the VBox status code a COM one and sets the error info.
620 *
621 * The VBox status code is made available to the API user via
622 * IVirtualBoxErrorInfo::resultDetail attribute.
623 *
624 * @param vrc The VBox status code.
625 * @return COM status code appropriate for @a vrc.
626 *
627 * @sa VirtualBoxBase::setError(HRESULT)
628 */
629HRESULT VirtualBoxBase::setErrorVrc(int vrc)
630{
631 return setErrorInternal(Global::vboxStatusCodeToCOM(vrc),
632 this->getClassIID(),
633 this->getComponentName(),
634 Utf8StrFmt("%Rrc", vrc),
635 false /* aWarning */,
636 true /* aLogIt */,
637 vrc /* aResultDetail */);
638}
639
640/**
641 * Converts the VBox status code a COM one and sets the error info.
642 *
643 * @param vrc The VBox status code.
644 * @param pcszMsgFmt Error message format string.
645 * @param ... Argument specified in the @a pcszMsgFmt
646 * @return COM status code appropriate for @a vrc.
647 *
648 * @sa VirtualBoxBase::setError(HRESULT, const char *, ...)
649 */
650HRESULT VirtualBoxBase::setErrorVrc(int vrc, const char *pcszMsgFmt, ...)
651{
652 va_list va;
653 va_start(va, pcszMsgFmt);
654 HRESULT hrc = setErrorInternal(Global::vboxStatusCodeToCOM(vrc),
655 this->getClassIID(),
656 this->getComponentName(),
657 Utf8Str(pcszMsgFmt, va),
658 false /* aWarning */,
659 true /* aLogIt */,
660 vrc /* aResultDetail */);
661 va_end(va);
662 return hrc;
663}
664
665/**
666 * Sets error info with both a COM status and an VBox status code.
667 *
668 * The VBox status code is made available to the API user via
669 * IVirtualBoxErrorInfo::resultDetail attribute.
670 *
671 * @param hrc The COM status code to return.
672 * @param vrc The VBox status code.
673 * @return Most likely @a hrc, see setErrorInternal.
674 *
675 * @sa VirtualBoxBase::setError(HRESULT)
676 */
677HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc)
678{
679 return setErrorInternal(hrc,
680 this->getClassIID(),
681 this->getComponentName(),
682 Utf8StrFmt("%Rrc", vrc),
683 false /* aWarning */,
684 true /* aLogIt */,
685 vrc /* aResultDetail */);
686}
687
688/**
689 * Sets error info with a message and both a COM status and an VBox status code.
690 *
691 * The VBox status code is made available to the API user via
692 * IVirtualBoxErrorInfo::resultDetail attribute.
693 *
694 * @param hrc The COM status code to return.
695 * @param vrc The VBox status code.
696 * @param pcszMsgFmt Error message format string.
697 * @param ... Argument specified in the @a pcszMsgFmt
698 * @return Most likely @a hrc, see setErrorInternal.
699 *
700 * @sa VirtualBoxBase::setError(HRESULT, const char *, ...)
701 */
702HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc, const char *pcszMsgFmt, ...)
703{
704 va_list va;
705 va_start(va, pcszMsgFmt);
706 hrc = setErrorInternal(hrc,
707 this->getClassIID(),
708 this->getComponentName(),
709 Utf8Str(pcszMsgFmt, va),
710 false /* aWarning */,
711 true /* aLogIt */,
712 vrc /* aResultDetail */);
713 va_end(va);
714 return hrc;
715}
716
717/**
718 * Like setError(), but sets the "warning" bit in the call to setErrorInternal().
719 * @param aResultCode
720 * @param pcsz
721 * @return
722 */
723HRESULT VirtualBoxBase::setWarning(HRESULT aResultCode, const char *pcsz, ...)
724{
725 va_list args;
726 va_start(args, pcsz);
727 HRESULT rc = setErrorInternal(aResultCode,
728 this->getClassIID(),
729 this->getComponentName(),
730 Utf8Str(pcsz, args),
731 true /* aWarning */,
732 true /* aLogIt */);
733 va_end(args);
734 return rc;
735}
736
737/**
738 * Like setError(), but disables the "log" flag in the call to setErrorInternal().
739 * @param aResultCode
740 * @param pcsz
741 * @return
742 */
743HRESULT VirtualBoxBase::setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...)
744{
745 va_list args;
746 va_start(args, pcsz);
747 HRESULT rc = setErrorInternal(aResultCode,
748 this->getClassIID(),
749 this->getComponentName(),
750 Utf8Str(pcsz, args),
751 false /* aWarning */,
752 false /* aLogIt */);
753 va_end(args);
754 return rc;
755}
756
757/**
758 * Clear the current error information.
759 */
760/*static*/
761void VirtualBoxBase::clearError(void)
762{
763#if !defined(VBOX_WITH_XPCOM)
764 ::SetErrorInfo(0, NULL);
765#else
766 HRESULT rc = S_OK;
767 nsCOMPtr <nsIExceptionService> es;
768 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
769 if (NS_SUCCEEDED(rc))
770 {
771 nsCOMPtr <nsIExceptionManager> em;
772 rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
773 if (SUCCEEDED(rc))
774 em->SetCurrentException(NULL);
775 }
776#endif
777}
778
779
780////////////////////////////////////////////////////////////////////////////////
781//
782// MultiResult methods
783//
784////////////////////////////////////////////////////////////////////////////////
785
786RTTLS MultiResult::sCounter = NIL_RTTLS;
787
788/*static*/
789void MultiResult::incCounter()
790{
791 if (sCounter == NIL_RTTLS)
792 {
793 sCounter = RTTlsAlloc();
794 AssertReturnVoid(sCounter != NIL_RTTLS);
795 }
796
797 uintptr_t counter = (uintptr_t)RTTlsGet(sCounter);
798 ++counter;
799 RTTlsSet(sCounter, (void*)counter);
800}
801
802/*static*/
803void MultiResult::decCounter()
804{
805 uintptr_t counter = (uintptr_t)RTTlsGet(sCounter);
806 AssertReturnVoid(counter != 0);
807 --counter;
808 RTTlsSet(sCounter, (void*)counter);
809}
810
811/*static*/
812bool MultiResult::isMultiEnabled()
813{
814 if (sCounter == NIL_RTTLS)
815 return false;
816
817 return ((uintptr_t)RTTlsGet(MultiResult::sCounter)) > 0;
818}
819
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