VirtualBox

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

Last change on this file since 72293 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.9 KB
Line 
1/* $Id: VirtualBoxBase.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
2
3/** @file
4 *
5 * VirtualBox COM base classes implementation
6 */
7
8/*
9 * Copyright (C) 2006-2017 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include <iprt/semaphore.h>
21#include <iprt/asm.h>
22#include <iprt/cpp/exception.h>
23
24#include <typeinfo>
25
26#if !defined(VBOX_WITH_XPCOM)
27#include <iprt/win/windows.h>
28#include <dbghelp.h>
29#else /* !defined(VBOX_WITH_XPCOM) */
30/// @todo remove when VirtualBoxErrorInfo goes away from here
31#include <nsIServiceManager.h>
32#include <nsIExceptionService.h>
33#endif /* !defined(VBOX_WITH_XPCOM) */
34
35#include "VirtualBoxBase.h"
36#include "AutoCaller.h"
37#include "VirtualBoxErrorInfoImpl.h"
38#include "Logging.h"
39#include "Global.h"
40
41#include "VBox/com/ErrorInfo.h"
42#include "VBox/com/MultiResult.h"
43
44////////////////////////////////////////////////////////////////////////////////
45//
46// VirtualBoxBase
47//
48////////////////////////////////////////////////////////////////////////////////
49
50CLASSFACTORY_STAT g_aClassFactoryStats[CLASSFACTORYSTATS_MAX] =
51{
52 { "--- totals ---", 0 },
53 { NULL, 0 }
54};
55
56RWLockHandle *g_pClassFactoryStatsLock = NULL;
57
58
59VirtualBoxBase::VirtualBoxBase() :
60 mState(this),
61 iFactoryStat(~0U)
62{
63 mObjectLock = NULL;
64
65 if (!g_pClassFactoryStatsLock)
66 {
67 RWLockHandle *lock = new RWLockHandle(LOCKCLASS_OBJECTSTATE);
68 if (!ASMAtomicCmpXchgPtr(&g_pClassFactoryStatsLock, lock, NULL))
69 delete lock;
70 }
71 Assert(g_pClassFactoryStatsLock);
72}
73
74VirtualBoxBase::~VirtualBoxBase()
75{
76 Assert(iFactoryStat == ~0U);
77 if (mObjectLock)
78 delete mObjectLock;
79}
80
81HRESULT VirtualBoxBase::BaseFinalConstruct()
82{
83 Assert(iFactoryStat == ~0U);
84 if (g_pClassFactoryStatsLock)
85 {
86 AutoWriteLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
87 g_aClassFactoryStats[0].current++;
88 g_aClassFactoryStats[0].overall++;
89 const char *pszName = getComponentName();
90 uint32_t i = 1;
91 while (i < CLASSFACTORYSTATS_MAX && g_aClassFactoryStats[i].psz)
92 {
93 if (g_aClassFactoryStats[i].psz == pszName)
94 break;
95 i++;
96 }
97 if (i < CLASSFACTORYSTATS_MAX)
98 {
99 if (!g_aClassFactoryStats[i].psz)
100 {
101 g_aClassFactoryStats[i].psz = pszName;
102 g_aClassFactoryStats[i].current = 0;
103 g_aClassFactoryStats[i].overall = 0;
104 }
105 iFactoryStat = i;
106 g_aClassFactoryStats[i].current++;
107 g_aClassFactoryStats[i].overall++;
108 }
109 else
110 AssertMsg(i < CLASSFACTORYSTATS_MAX, ("%u exhausts size of factory housekeeping array\n", i));
111 }
112 else
113 Assert(g_pClassFactoryStatsLock);
114
115#ifdef RT_OS_WINDOWS
116 return CoCreateFreeThreadedMarshaler(this, //GetControllingUnknown(),
117 m_pUnkMarshaler.asOutParam());
118#else
119 return S_OK;
120#endif
121}
122
123void VirtualBoxBase::BaseFinalRelease()
124{
125 if (g_pClassFactoryStatsLock)
126 {
127 AutoWriteLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
128 g_aClassFactoryStats[0].current--;
129 const char *pszName = getComponentName();
130 if (iFactoryStat < CLASSFACTORYSTATS_MAX)
131 {
132 if (g_aClassFactoryStats[iFactoryStat].psz == pszName)
133 {
134 g_aClassFactoryStats[iFactoryStat].current--;
135 iFactoryStat = ~0U;
136 }
137 else
138 AssertMsgFailed(("could not find factory housekeeping array entry for %s (index %u contains %s)\n", pszName, iFactoryStat, g_aClassFactoryStats[iFactoryStat].psz));
139 }
140 else
141 AssertMsgFailed(("factory housekeeping array corruption, index %u is too large\n", iFactoryStat));
142 }
143 else
144 Assert(g_pClassFactoryStatsLock);
145
146#ifdef RT_OS_WINDOWS
147 m_pUnkMarshaler.setNull();
148#endif
149}
150
151void APIDumpComponentFactoryStats()
152{
153 if (g_pClassFactoryStatsLock)
154 {
155 AutoReadLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
156 for (uint32_t i = 0; i < CLASSFACTORYSTATS_MAX && g_aClassFactoryStats[i].psz; i++)
157 LogRel(("CFS: component %-30s current %-10u total %-10u\n",
158 g_aClassFactoryStats[i].psz, g_aClassFactoryStats[i].current,
159 g_aClassFactoryStats[i].overall));
160 }
161 else
162 Assert(g_pClassFactoryStatsLock);
163}
164
165/**
166 * This virtual method returns an RWLockHandle that can be used to
167 * protect instance data. This RWLockHandle is generally referred to
168 * as the "object lock"; its locking class (for lock order validation)
169 * must be returned by another virtual method, getLockingClass(), which
170 * by default returns LOCKCLASS_OTHEROBJECT but is overridden by several
171 * subclasses such as VirtualBox, Host, Machine and others.
172 *
173 * On the first call this method lazily creates the RWLockHandle.
174 *
175 * @return
176 */
177/* virtual */
178RWLockHandle *VirtualBoxBase::lockHandle() const
179{
180 /* lazy initialization */
181 if (RT_LIKELY(mObjectLock))
182 return mObjectLock;
183
184 AssertCompile(sizeof(RWLockHandle *) == sizeof(void *));
185
186 // getLockingClass() is overridden by many subclasses to return
187 // one of the locking classes listed at the top of AutoLock.h
188 RWLockHandle *objLock = new RWLockHandle(getLockingClass());
189 if (!ASMAtomicCmpXchgPtr(&mObjectLock, objLock, NULL))
190 {
191 delete objLock;
192 objLock = ASMAtomicReadPtrT(&mObjectLock, RWLockHandle *);
193 }
194 return objLock;
195}
196
197/**
198 * Handles unexpected exceptions by turning them into COM errors in release
199 * builds or by hitting a breakpoint in the release builds.
200 *
201 * Usage pattern:
202 * @code
203 try
204 {
205 // ...
206 }
207 catch (LaLalA)
208 {
209 // ...
210 }
211 catch (...)
212 {
213 rc = VirtualBox::handleUnexpectedExceptions(this, RT_SRC_POS);
214 }
215 * @endcode
216 *
217 * @param aThis object where the exception happened
218 * @param SRC_POS "RT_SRC_POS" macro instantiation.
219 * */
220/* static */
221HRESULT VirtualBoxBase::handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL)
222{
223 try
224 {
225 /* re-throw the current exception */
226 throw;
227 }
228 catch (const RTCError &err) // includes all XML exceptions
229 {
230 return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
231 Utf8StrFmt(tr("%s.\n%s[%d] (%s)"),
232 err.what(),
233 pszFile, iLine, pszFunction).c_str(),
234 false /* aWarning */,
235 true /* aLogIt */);
236 }
237 catch (const std::exception &err)
238 {
239 return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
240 Utf8StrFmt(tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"),
241 err.what(), typeid(err).name(),
242 pszFile, iLine, pszFunction).c_str(),
243 false /* aWarning */,
244 true /* aLogIt */);
245 }
246 catch (...)
247 {
248 return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
249 Utf8StrFmt(tr("Unknown exception\n%s[%d] (%s)"),
250 pszFile, iLine, pszFunction).c_str(),
251 false /* aWarning */,
252 true /* aLogIt */);
253 }
254
255#ifndef _MSC_VER /* (unreachable) */
256 /* should not get here */
257 AssertFailed();
258 return E_FAIL;
259#endif
260}
261
262/**
263 * Sets error info for the current thread. This is an internal function that
264 * gets eventually called by all public variants. If @a aWarning is
265 * @c true, then the highest (31) bit in the @a aResultCode value which
266 * indicates the error severity is reset to zero to make sure the receiver will
267 * recognize that the created error info object represents a warning rather
268 * than an error.
269 *
270 * @param aResultCode
271 * @param aIID
272 * @param pcszComponent
273 * @param aText
274 * @param aWarning
275 * @param aLogIt
276 * @param aResultDetail
277 */
278/* static */
279HRESULT VirtualBoxBase::setErrorInternal(HRESULT aResultCode,
280 const GUID &aIID,
281 const char *pcszComponent,
282 Utf8Str aText,
283 bool aWarning,
284 bool aLogIt,
285 LONG aResultDetail /* = 0*/)
286{
287 /* whether multi-error mode is turned on */
288 bool preserve = MultiResult::isMultiEnabled();
289
290 if (aLogIt)
291 LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%s}, preserve=%RTbool aResultDetail=%d\n",
292 aWarning ? "WARNING" : "ERROR",
293 aResultCode,
294 aResultCode,
295 &aIID,
296 pcszComponent,
297 aText.c_str(),
298 preserve,
299 aResultDetail));
300
301 /* these are mandatory, others -- not */
302 AssertReturn((!aWarning && FAILED(aResultCode)) ||
303 (aWarning && aResultCode != S_OK),
304 E_FAIL);
305
306 /* reset the error severity bit if it's a warning */
307 if (aWarning)
308 aResultCode &= ~0x80000000;
309
310 HRESULT rc = S_OK;
311
312 if (aText.isEmpty())
313 {
314 /* Some default info */
315 switch (aResultCode)
316 {
317 case E_INVALIDARG: aText = "A parameter has an invalid value"; break;
318 case E_POINTER: aText = "A parameter is an invalid pointer"; break;
319 case E_UNEXPECTED: aText = "The result of the operation is unexpected"; break;
320 case E_ACCESSDENIED: aText = "The access to an object is not allowed"; break;
321 case E_OUTOFMEMORY: aText = "The allocation of new memory failed"; break;
322 case E_NOTIMPL: aText = "The requested operation is not implemented"; break;
323 case E_NOINTERFACE: aText = "The requested interface is not implemented"; break;
324 case E_FAIL: aText = "A general error occurred"; break;
325 case E_ABORT: aText = "The operation was canceled"; break;
326 case VBOX_E_OBJECT_NOT_FOUND: aText = "Object corresponding to the supplied arguments does not exist"; break;
327 case VBOX_E_INVALID_VM_STATE: aText = "Current virtual machine state prevents the operation"; break;
328 case VBOX_E_VM_ERROR: aText = "Virtual machine error occurred attempting the operation"; break;
329 case VBOX_E_FILE_ERROR: aText = "File not accessible or erroneous file contents"; break;
330 case VBOX_E_IPRT_ERROR: aText = "Runtime subsystem error"; break;
331 case VBOX_E_PDM_ERROR: aText = "Pluggable Device Manager error"; break;
332 case VBOX_E_INVALID_OBJECT_STATE: aText = "Current object state prohibits operation"; break;
333 case VBOX_E_HOST_ERROR: aText = "Host operating system related error"; break;
334 case VBOX_E_NOT_SUPPORTED: aText = "Requested operation is not supported"; break;
335 case VBOX_E_XML_ERROR: aText = "Invalid XML found"; break;
336 case VBOX_E_INVALID_SESSION_STATE: aText = "Current session state prohibits operation"; break;
337 case VBOX_E_OBJECT_IN_USE: aText = "Object being in use prohibits operation"; 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