From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/Main/src-all/VirtualBoxBase.cpp | 884 +++++++++++++++++++++++++++++++ 1 file changed, 884 insertions(+) create mode 100644 src/VBox/Main/src-all/VirtualBoxBase.cpp (limited to 'src/VBox/Main/src-all/VirtualBoxBase.cpp') diff --git a/src/VBox/Main/src-all/VirtualBoxBase.cpp b/src/VBox/Main/src-all/VirtualBoxBase.cpp new file mode 100644 index 00000000..0fa8d8d3 --- /dev/null +++ b/src/VBox/Main/src-all/VirtualBoxBase.cpp @@ -0,0 +1,884 @@ +/* $Id: VirtualBoxBase.cpp $ */ +/** @file + * VirtualBox COM base classes implementation + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#define LOG_GROUP LOG_GROUP_MAIN +#include +#include +#include + +#include + +#if !defined(VBOX_WITH_XPCOM) +# include +#else /* !defined(VBOX_WITH_XPCOM) */ +/// @todo remove when VirtualBoxErrorInfo goes away from here +# include +# include +#endif /* !defined(VBOX_WITH_XPCOM) */ + +#include "VirtualBoxBase.h" +#include "AutoCaller.h" +#include "VirtualBoxErrorInfoImpl.h" +#include "VirtualBoxTranslator.h" +#include "Global.h" +#include "LoggingNew.h" + +#include "VBox/com/ErrorInfo.h" +#include "VBox/com/MultiResult.h" + +//////////////////////////////////////////////////////////////////////////////// +// +// VirtualBoxBase +// +//////////////////////////////////////////////////////////////////////////////// + +CLASSFACTORY_STAT g_aClassFactoryStats[CLASSFACTORYSTATS_MAX] = +{ + { "--- totals ---", 0 }, + { NULL, 0 } +}; + +RWLockHandle *g_pClassFactoryStatsLock = NULL; + + +VirtualBoxBase::VirtualBoxBase() : + mState(this), + iFactoryStat(~0U) +{ + mObjectLock = NULL; + + if (!g_pClassFactoryStatsLock) + { + RWLockHandle *lock = new RWLockHandle(LOCKCLASS_OBJECTSTATE); + if (!ASMAtomicCmpXchgPtr(&g_pClassFactoryStatsLock, lock, NULL)) + delete lock; + } + Assert(g_pClassFactoryStatsLock); +} + +VirtualBoxBase::~VirtualBoxBase() +{ + Assert(iFactoryStat == ~0U); + if (mObjectLock) + delete mObjectLock; +} + +HRESULT VirtualBoxBase::BaseFinalConstruct() +{ + Assert(iFactoryStat == ~0U); + if (g_pClassFactoryStatsLock) + { + AutoWriteLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS); + g_aClassFactoryStats[0].current++; + g_aClassFactoryStats[0].overall++; + const char *pszName = getComponentName(); + uint32_t i = 1; + while (i < CLASSFACTORYSTATS_MAX && g_aClassFactoryStats[i].psz) + { + if (g_aClassFactoryStats[i].psz == pszName) + break; + i++; + } + if (i < CLASSFACTORYSTATS_MAX) + { + if (!g_aClassFactoryStats[i].psz) + { + g_aClassFactoryStats[i].psz = pszName; + g_aClassFactoryStats[i].current = 0; + g_aClassFactoryStats[i].overall = 0; + } + iFactoryStat = i; + g_aClassFactoryStats[i].current++; + g_aClassFactoryStats[i].overall++; + } + else + AssertMsg(i < CLASSFACTORYSTATS_MAX, ("%u exhausts size of factory housekeeping array\n", i)); + } + else + Assert(g_pClassFactoryStatsLock); + +#ifdef RT_OS_WINDOWS + return CoCreateFreeThreadedMarshaler(this, //GetControllingUnknown(), + m_pUnkMarshaler.asOutParam()); +#else + return S_OK; +#endif +} + +void VirtualBoxBase::BaseFinalRelease() +{ + if (g_pClassFactoryStatsLock) + { + AutoWriteLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS); + g_aClassFactoryStats[0].current--; + const char *pszName = getComponentName(); + if (iFactoryStat < CLASSFACTORYSTATS_MAX) + { + if (g_aClassFactoryStats[iFactoryStat].psz == pszName) + { + g_aClassFactoryStats[iFactoryStat].current--; + iFactoryStat = ~0U; + } + else + AssertMsgFailed(("could not find factory housekeeping array entry for %s (index %u contains %s)\n", pszName, iFactoryStat, g_aClassFactoryStats[iFactoryStat].psz)); + } + else + AssertMsgFailed(("factory housekeeping array corruption, index %u is too large\n", iFactoryStat)); + } + else + Assert(g_pClassFactoryStatsLock); + +#ifdef RT_OS_WINDOWS + m_pUnkMarshaler.setNull(); +#endif +} + +void APIDumpComponentFactoryStats() +{ + if (g_pClassFactoryStatsLock) + { + AutoReadLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS); + for (uint32_t i = 0; i < CLASSFACTORYSTATS_MAX && g_aClassFactoryStats[i].psz; i++) + LogRel(("CFS: component %-30s current %-10u total %-10u\n", + g_aClassFactoryStats[i].psz, g_aClassFactoryStats[i].current, + g_aClassFactoryStats[i].overall)); + } + else + Assert(g_pClassFactoryStatsLock); +} + +/** + * This virtual method returns an RWLockHandle that can be used to + * protect instance data. This RWLockHandle is generally referred to + * as the "object lock"; its locking class (for lock order validation) + * must be returned by another virtual method, getLockingClass(), which + * by default returns LOCKCLASS_OTHEROBJECT but is overridden by several + * subclasses such as VirtualBox, Host, Machine and others. + * + * On the first call this method lazily creates the RWLockHandle. + * + * @return + */ +/* virtual */ +RWLockHandle *VirtualBoxBase::lockHandle() const +{ + /* lazy initialization */ + if (RT_LIKELY(mObjectLock)) + return mObjectLock; + + AssertCompile(sizeof(RWLockHandle *) == sizeof(void *)); + + // getLockingClass() is overridden by many subclasses to return + // one of the locking classes listed at the top of AutoLock.h + RWLockHandle *objLock = new RWLockHandle(getLockingClass()); + if (!ASMAtomicCmpXchgPtr(&mObjectLock, objLock, NULL)) + { + delete objLock; + objLock = ASMAtomicReadPtrT(&mObjectLock, RWLockHandle *); + } + return objLock; +} + +/** + * Handles unexpected exceptions by turning them into COM errors in release + * builds or by hitting a breakpoint in the release builds. + * + * Usage pattern: + * @code + try + { + // ... + } + catch (LaLalA) + { + // ... + } + catch (...) + { + hrc = VirtualBox::handleUnexpectedExceptions(this, RT_SRC_POS); + } + * @endcode + * + * @param aThis object where the exception happened + * @param SRC_POS "RT_SRC_POS" macro instantiation. + * */ +/* static */ +HRESULT VirtualBoxBase::handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL) +{ + try + { + /* re-throw the current exception */ + throw; + } + catch (const RTCError &err) // includes all XML exceptions + { + return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(), + false /* aWarning */, + true /* aLogIt */, + 0 /* aResultDetail */, + "%s.\n%s[%d] (%s)", + err.what(), pszFile, iLine, pszFunction); + } + catch (const std::exception &err) + { + return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(), + false /* aWarning */, + true /* aLogIt */, + 0 /* aResultDetail */, + tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"), + err.what(), typeid(err).name(), pszFile, iLine, pszFunction); + } + catch (...) + { + return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(), + false /* aWarning */, + true /* aLogIt */, + 0 /* aResultDetail */, + tr("Unknown exception\n%s[%d] (%s)"), + pszFile, iLine, pszFunction); + } + +#ifndef _MSC_VER /* (unreachable) */ + /* should not get here */ + AssertFailed(); + return E_FAIL; +#endif +} + + +/** + * Sets error info for the current thread. This is an internal function that + * gets eventually called by all public variants. If @a aWarning is + * @c true, then the highest (31) bit in the @a aResultCode value which + * indicates the error severity is reset to zero to make sure the receiver will + * recognize that the created error info object represents a warning rather + * than an error. + */ +/* static */ +HRESULT VirtualBoxBase::setErrorInternalF(HRESULT aResultCode, + const GUID &aIID, + const char *aComponent, + bool aWarning, + bool aLogIt, + LONG aResultDetail, + const char *aText, ...) +{ + va_list va; + va_start(va, aText); + HRESULT hres = setErrorInternalV(aResultCode, aIID, aComponent, aText, va, + aWarning, aLogIt, aResultDetail); + va_end(va); + return hres; +} + +/** + * Sets error info for the current thread. This is an internal function that + * gets eventually called by all public variants. If @a aWarning is + * @c true, then the highest (31) bit in the @a aResultCode value which + * indicates the error severity is reset to zero to make sure the receiver will + * recognize that the created error info object represents a warning rather + * than an error. + */ +/* static */ +HRESULT VirtualBoxBase::setErrorInternalV(HRESULT aResultCode, + const GUID &aIID, + const char *aComponent, + const char *aText, + va_list aArgs, + bool aWarning, + bool aLogIt, + LONG aResultDetail /* = 0*/) +{ + /* whether multi-error mode is turned on */ + bool preserve = MultiResult::isMultiEnabled(); + + com::Utf8Str strText; + if (aLogIt) + { +#ifdef VBOX_WITH_MAIN_NLS + strText = VirtualBoxTranslator::trSource(aText); +#else + strText = aText; +#endif + va_list va2; + va_copy(va2, aArgs); + LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%N}, preserve=%RTbool aResultDetail=%d\n", + aWarning ? "WARNING" : "ERROR", + aResultCode, + aResultCode, + &aIID, + aComponent, + strText.c_str(), + &va2, + preserve, + aResultDetail)); + va_end(va2); + } + + /* these are mandatory, others -- not */ + AssertReturn((!aWarning && FAILED(aResultCode)) || + (aWarning && aResultCode != S_OK), + E_FAIL); + + /* reset the error severity bit if it's a warning */ + if (aWarning) + aResultCode &= ~0x80000000; + + HRESULT hrc = S_OK; + + if (aText == NULL || aText[0] == '\0') + { + /* Some default info */ + switch (aResultCode) + { + case E_INVALIDARG: strText = tr("A parameter has an invalid value"); break; + case E_POINTER: strText = tr("A parameter is an invalid pointer"); break; + case E_UNEXPECTED: strText = tr("The result of the operation is unexpected"); break; + case E_ACCESSDENIED: strText = tr("The access to an object is not allowed"); break; + case E_OUTOFMEMORY: strText = tr("The allocation of new memory failed"); break; + case E_NOTIMPL: strText = tr("The requested operation is not implemented"); break; + case E_NOINTERFACE: strText = tr("The requested interface is not implemented"); break; + case E_FAIL: strText = tr("A general error occurred"); break; + case E_ABORT: strText = tr("The operation was canceled"); break; + case VBOX_E_OBJECT_NOT_FOUND: strText = tr("Object corresponding to the supplied arguments does not exist"); break; + case VBOX_E_INVALID_VM_STATE: strText = tr("Current virtual machine state prevents the operation"); break; + case VBOX_E_VM_ERROR: strText = tr("Virtual machine error occurred attempting the operation"); break; + case VBOX_E_FILE_ERROR: strText = tr("File not accessible or erroneous file contents"); break; + case VBOX_E_IPRT_ERROR: strText = tr("Runtime subsystem error"); break; + case VBOX_E_PDM_ERROR: strText = tr("Pluggable Device Manager error"); break; + case VBOX_E_INVALID_OBJECT_STATE: strText = tr("Current object state prohibits operation"); break; + case VBOX_E_HOST_ERROR: strText = tr("Host operating system related error"); break; + case VBOX_E_NOT_SUPPORTED: strText = tr("Requested operation is not supported"); break; + case VBOX_E_XML_ERROR: strText = tr("Invalid XML found"); break; + case VBOX_E_INVALID_SESSION_STATE: strText = tr("Current session state prohibits operation"); break; + case VBOX_E_OBJECT_IN_USE: strText = tr("Object being in use prohibits operation"); break; + case VBOX_E_PASSWORD_INCORRECT: strText = tr("Incorrect password provided"); break; + default: strText = tr("Unknown error"); break; + } + } + else + { + va_list va2; + va_copy(va2, aArgs); + strText = com::Utf8StrFmt("%N", aText, &va2); + va_end(va2); + } + + do + { + ComObjPtr info; + hrc = info.createObject(); + if (FAILED(hrc)) break; + +#if !defined(VBOX_WITH_XPCOM) + + ComPtr curInfo; + if (preserve) + { + /* get the current error info if any */ + ComPtr err; + hrc = ::GetErrorInfo(0, err.asOutParam()); + if (FAILED(hrc)) break; + hrc = err.queryInterfaceTo(curInfo.asOutParam()); + if (FAILED(hrc)) + { + /* create a IVirtualBoxErrorInfo wrapper for the native + * IErrorInfo object */ + ComObjPtr wrapper; + hrc = wrapper.createObject(); + if (SUCCEEDED(hrc)) + { + hrc = wrapper->init(err); + if (SUCCEEDED(hrc)) + curInfo = wrapper; + } + } + } + /* On failure, curInfo will stay null */ + Assert(SUCCEEDED(hrc) || curInfo.isNull()); + + /* set the current error info and preserve the previous one if any */ + hrc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, strText, curInfo); + if (FAILED(hrc)) break; + + ComPtr err; + hrc = info.queryInterfaceTo(err.asOutParam()); + if (SUCCEEDED(hrc)) + hrc = ::SetErrorInfo(0, err); + +#else // !defined(VBOX_WITH_XPCOM) + + nsCOMPtr es; + es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &hrc); + if (NS_SUCCEEDED(hrc)) + { + nsCOMPtr em; + hrc = es->GetCurrentExceptionManager(getter_AddRefs(em)); + if (FAILED(hrc)) break; + + ComPtr curInfo; + if (preserve) + { + /* get the current error info if any */ + ComPtr ex; + hrc = em->GetCurrentException(ex.asOutParam()); + if (FAILED(hrc)) break; + hrc = ex.queryInterfaceTo(curInfo.asOutParam()); + if (FAILED(hrc)) + { + /* create a IVirtualBoxErrorInfo wrapper for the native + * nsIException object */ + ComObjPtr wrapper; + hrc = wrapper.createObject(); + if (SUCCEEDED(hrc)) + { + hrc = wrapper->init(ex); + if (SUCCEEDED(hrc)) + curInfo = wrapper; + } + } + } + /* On failure, curInfo will stay null */ + Assert(SUCCEEDED(hrc) || curInfo.isNull()); + + /* set the current error info and preserve the previous one if any */ + hrc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, Bstr(strText), curInfo); + if (FAILED(hrc)) break; + + ComPtr ex; + hrc = info.queryInterfaceTo(ex.asOutParam()); + if (SUCCEEDED(hrc)) + hrc = em->SetCurrentException(ex); + } + else if (hrc == NS_ERROR_UNEXPECTED) + { + /* + * It is possible that setError() is being called by the object + * after the XPCOM shutdown sequence has been initiated + * (for example, when XPCOM releases all instances it internally + * references, which can cause object's FinalConstruct() and then + * uninit()). In this case, do_GetService() above will return + * NS_ERROR_UNEXPECTED and it doesn't actually make sense to + * set the exception (nobody will be able to read it). + */ + Log1WarningFunc(("Will not set an exception because nsIExceptionService is not available (NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n")); + hrc = NS_OK; + } + +#endif // !defined(VBOX_WITH_XPCOM) + } + while (0); + + AssertComRC(hrc); + + return SUCCEEDED(hrc) ? aResultCode : hrc; +} + +/** + * Shortcut instance method to calling the static setErrorInternal with the + * class interface ID and component name inserted correctly. This uses the + * virtual getClassIID() and getComponentName() methods which are automatically + * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro. + * @param aResultCode + * @return + */ +HRESULT VirtualBoxBase::setError(HRESULT aResultCode) +{ + return setErrorInternalF(aResultCode, + this->getClassIID(), + this->getComponentName(), + false /* aWarning */, + true /* aLogIt */, + 0 /* aResultDetail */, + NULL); +} + +/** + * Shortcut instance method to calling the static setErrorInternal with the + * class interface ID and component name inserted correctly. This uses the + * virtual getClassIID() and getComponentName() methods which are automatically + * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro. + * @param aResultCode + * @param pcsz + * @return + */ +HRESULT VirtualBoxBase::setError(HRESULT aResultCode, const char *pcsz, ...) +{ + va_list args; + va_start(args, pcsz); + HRESULT hrc = setErrorInternalV(aResultCode, + this->getClassIID(), + this->getComponentName(), + pcsz, args, + false /* aWarning */, + true /* aLogIt */); + va_end(args); + return hrc; +} + +/** + * Shortcut instance method to calling the static setErrorInternal with the + * class interface ID and component name inserted correctly. This uses the + * virtual getClassIID() and getComponentName() methods which are automatically + * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro. + * @param ei + * @return + */ +HRESULT VirtualBoxBase::setError(const com::ErrorInfo &ei) +{ + /* whether multi-error mode is turned on */ + bool preserve = MultiResult::isMultiEnabled(); + + HRESULT hrc = S_OK; + + do + { + ComObjPtr info; + hrc = info.createObject(); + if (FAILED(hrc)) break; + +#if !defined(VBOX_WITH_XPCOM) + + ComPtr curInfo; + if (preserve) + { + /* get the current error info if any */ + ComPtr err; + hrc = ::GetErrorInfo(0, err.asOutParam()); + if (FAILED(hrc)) break; + hrc = err.queryInterfaceTo(curInfo.asOutParam()); + if (FAILED(hrc)) + { + /* create a IVirtualBoxErrorInfo wrapper for the native + * IErrorInfo object */ + ComObjPtr wrapper; + hrc = wrapper.createObject(); + if (SUCCEEDED(hrc)) + { + hrc = wrapper->init(err); + if (SUCCEEDED(hrc)) + curInfo = wrapper; + } + } + } + /* On failure, curInfo will stay null */ + Assert(SUCCEEDED(hrc) || curInfo.isNull()); + + /* set the current error info and preserve the previous one if any */ + hrc = info->init(ei, curInfo); + if (FAILED(hrc)) break; + + ComPtr err; + hrc = info.queryInterfaceTo(err.asOutParam()); + if (SUCCEEDED(hrc)) + hrc = ::SetErrorInfo(0, err); + +#else // !defined(VBOX_WITH_XPCOM) + + nsCOMPtr es; + es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &hrc); + if (NS_SUCCEEDED(hrc)) + { + nsCOMPtr em; + hrc = es->GetCurrentExceptionManager(getter_AddRefs(em)); + if (FAILED(hrc)) break; + + ComPtr curInfo; + if (preserve) + { + /* get the current error info if any */ + ComPtr ex; + hrc = em->GetCurrentException(ex.asOutParam()); + if (FAILED(hrc)) break; + hrc = ex.queryInterfaceTo(curInfo.asOutParam()); + if (FAILED(hrc)) + { + /* create a IVirtualBoxErrorInfo wrapper for the native + * nsIException object */ + ComObjPtr wrapper; + hrc = wrapper.createObject(); + if (SUCCEEDED(hrc)) + { + hrc = wrapper->init(ex); + if (SUCCEEDED(hrc)) + curInfo = wrapper; + } + } + } + /* On failure, curInfo will stay null */ + Assert(SUCCEEDED(hrc) || curInfo.isNull()); + + /* set the current error info and preserve the previous one if any */ + hrc = info->init(ei, curInfo); + if (FAILED(hrc)) break; + + ComPtr ex; + hrc = info.queryInterfaceTo(ex.asOutParam()); + if (SUCCEEDED(hrc)) + hrc = em->SetCurrentException(ex); + } + else if (hrc == NS_ERROR_UNEXPECTED) + { + /* + * It is possible that setError() is being called by the object + * after the XPCOM shutdown sequence has been initiated + * (for example, when XPCOM releases all instances it internally + * references, which can cause object's FinalConstruct() and then + * uninit()). In this case, do_GetService() above will return + * NS_ERROR_UNEXPECTED and it doesn't actually make sense to + * set the exception (nobody will be able to read it). + */ + Log1WarningFunc(("Will not set an exception because nsIExceptionService is not available (NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n")); + hrc = NS_OK; + } + +#endif // !defined(VBOX_WITH_XPCOM) + } + while (0); + + AssertComRC(hrc); + + return SUCCEEDED(hrc) ? ei.getResultCode() : hrc; +} + +/** + * Converts the VBox status code a COM one and sets the error info. + * + * The VBox status code is made available to the API user via + * IVirtualBoxErrorInfo::resultDetail attribute. + * + * @param vrc The VBox status code. + * @return COM status code appropriate for @a vrc. + * + * @sa VirtualBoxBase::setError(HRESULT) + */ +HRESULT VirtualBoxBase::setErrorVrc(int vrc) +{ + return setErrorInternalF(Global::vboxStatusCodeToCOM(vrc), + this->getClassIID(), + this->getComponentName(), + false /* aWarning */, + true /* aLogIt */, + vrc /* aResultDetail */, + Utf8StrFmt("%Rrc", vrc).c_str()); +} + +/** + * Converts the VBox status code a COM one and sets the error info. + * + * @param vrc The VBox status code. + * @param pcszMsgFmt Error message format string. + * @param va_args Error message format string. + * @return COM status code appropriate for @a vrc. + * + * @sa VirtualBoxBase::setError(HRESULT, const char *, ...) + */ +HRESULT VirtualBoxBase::setErrorVrcV(int vrc, const char *pcszMsgFmt, va_list va_args) +{ + return setErrorInternalV(Global::vboxStatusCodeToCOM(vrc), + this->getClassIID(), + this->getComponentName(), + pcszMsgFmt, va_args, + false /* aWarning */, + true /* aLogIt */, + vrc /* aResultDetail */); +} + +/** + * Converts the VBox status code a COM one and sets the error info. + * + * @param vrc The VBox status code. + * @param pcszMsgFmt Error message format string. + * @param ... Argument specified in the @a pcszMsgFmt + * @return COM status code appropriate for @a vrc. + * + * @sa VirtualBoxBase::setError(HRESULT, const char *, ...) + */ +HRESULT VirtualBoxBase::setErrorVrc(int vrc, const char *pcszMsgFmt, ...) +{ + va_list va; + va_start(va, pcszMsgFmt); + HRESULT hrc = setErrorVrcV(vrc, pcszMsgFmt, va); + va_end(va); + return hrc; +} + +/** + * Sets error info with both a COM status and an VBox status code. + * + * The VBox status code is made available to the API user via + * IVirtualBoxErrorInfo::resultDetail attribute. + * + * @param hrc The COM status code to return. + * @param vrc The VBox status code. + * @return Most likely @a hrc, see setErrorInternal. + * + * @sa VirtualBoxBase::setError(HRESULT) + */ +HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc) +{ + return setErrorInternalF(hrc, + this->getClassIID(), + this->getComponentName(), + false /* aWarning */, + true /* aLogIt */, + vrc /* aResultDetail */, + Utf8StrFmt("%Rrc", vrc).c_str()); +} + +/** + * Sets error info with a message and both a COM status and an VBox status code. + * + * The VBox status code is made available to the API user via + * IVirtualBoxErrorInfo::resultDetail attribute. + * + * @param hrc The COM status code to return. + * @param vrc The VBox status code. + * @param pcszMsgFmt Error message format string. + * @param ... Argument specified in the @a pcszMsgFmt + * @return Most likely @a hrc, see setErrorInternal. + * + * @sa VirtualBoxBase::setError(HRESULT, const char *, ...) + */ +HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc, const char *pcszMsgFmt, ...) +{ + va_list va; + va_start(va, pcszMsgFmt); + hrc = setErrorInternalV(hrc, + this->getClassIID(), + this->getComponentName(), + pcszMsgFmt, va, + false /* aWarning */, + true /* aLogIt */, + vrc /* aResultDetail */); + va_end(va); + return hrc; +} + +/** + * Like setError(), but sets the "warning" bit in the call to setErrorInternal(). + * @param aResultCode + * @param pcsz + * @return + */ +HRESULT VirtualBoxBase::setWarning(HRESULT aResultCode, const char *pcsz, ...) +{ + va_list args; + va_start(args, pcsz); + HRESULT hrc = setErrorInternalV(aResultCode, + this->getClassIID(), + this->getComponentName(), + pcsz, args, + true /* aWarning */, + true /* aLogIt */); + va_end(args); + return hrc; +} + +/** + * Like setError(), but disables the "log" flag in the call to setErrorInternal(). + * @param aResultCode + * @param pcsz + * @return + */ +HRESULT VirtualBoxBase::setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...) +{ + va_list args; + va_start(args, pcsz); + HRESULT hrc = setErrorInternalV(aResultCode, + this->getClassIID(), + this->getComponentName(), + pcsz, args, + false /* aWarning */, + false /* aLogIt */); + va_end(args); + return hrc; +} + +/** + * Clear the current error information. + */ +/*static*/ +void VirtualBoxBase::clearError(void) +{ +#if !defined(VBOX_WITH_XPCOM) + ::SetErrorInfo(0, NULL); +#else + HRESULT hrc = S_OK; + nsCOMPtr es; + es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &hrc); + if (NS_SUCCEEDED(hrc)) + { + nsCOMPtr em; + hrc = es->GetCurrentExceptionManager(getter_AddRefs(em)); + if (SUCCEEDED(hrc)) + em->SetCurrentException(NULL); + } +#endif +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// MultiResult methods +// +//////////////////////////////////////////////////////////////////////////////// + +RTTLS MultiResult::sCounter = NIL_RTTLS; + +/*static*/ +void MultiResult::incCounter() +{ + if (sCounter == NIL_RTTLS) + { + sCounter = RTTlsAlloc(); + AssertReturnVoid(sCounter != NIL_RTTLS); + } + + uintptr_t counter = (uintptr_t)RTTlsGet(sCounter); + ++counter; + RTTlsSet(sCounter, (void*)counter); +} + +/*static*/ +void MultiResult::decCounter() +{ + uintptr_t counter = (uintptr_t)RTTlsGet(sCounter); + AssertReturnVoid(counter != 0); + --counter; + RTTlsSet(sCounter, (void*)counter); +} + +/*static*/ +bool MultiResult::isMultiEnabled() +{ + if (sCounter == NIL_RTTLS) + return false; + + return ((uintptr_t)RTTlsGet(MultiResult::sCounter)) > 0; +} + -- cgit v1.2.3