VirtualBox

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

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

Main: bugref:1909: Added ability to use translation inside non-member functions

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