VirtualBox

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

Last change on this file since 86506 was 83787, checked in by vboxsync, 4 years ago

Main/VirtualBoxBase.cpp: Don't need dbghelp.h. bugref:8489

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

© 2023 Oracle
ContactPrivacy policyTerms of Use