diff options
Diffstat (limited to 'src/VBox/Main/glue/ErrorInfo.cpp')
-rw-r--r-- | src/VBox/Main/glue/ErrorInfo.cpp | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/src/VBox/Main/glue/ErrorInfo.cpp b/src/VBox/Main/glue/ErrorInfo.cpp new file mode 100644 index 00000000..aec225b7 --- /dev/null +++ b/src/VBox/Main/glue/ErrorInfo.cpp @@ -0,0 +1,374 @@ +/* $Id: ErrorInfo.cpp $ */ + +/** @file + * + * ErrorInfo class definition + */ + +/* + * Copyright (C) 2006-2022 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 <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#if defined(VBOX_WITH_XPCOM) +# include <nsIServiceManager.h> +# include <nsIExceptionService.h> +# include <nsCOMPtr.h> +#endif + +#include "VBox/com/VirtualBox.h" +#include "VBox/com/ErrorInfo.h" +#include "VBox/com/assert.h" +#include "VBox/com/com.h" +#include "VBox/com/MultiResult.h" + +#include <iprt/stream.h> +#include <iprt/string.h> + +#include <iprt/errcore.h> + +namespace com +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// ErrorInfo class +// +//////////////////////////////////////////////////////////////////////////////// + +HRESULT ErrorInfo::getVirtualBoxErrorInfo(ComPtr<IVirtualBoxErrorInfo> &pVirtualBoxErrorInfo) +{ + HRESULT rc = S_OK; + if (mErrorInfo) + rc = mErrorInfo.queryInterfaceTo(pVirtualBoxErrorInfo.asOutParam()); + else + pVirtualBoxErrorInfo.setNull(); + return rc; +} + +void ErrorInfo::copyFrom(const ErrorInfo &x) +{ + mIsBasicAvailable = x.mIsBasicAvailable; + mIsFullAvailable = x.mIsFullAvailable; + + mResultCode = x.mResultCode; + mResultDetail = x.mResultDetail; + mInterfaceID = x.mInterfaceID; + mComponent = x.mComponent; + mText = x.mText; + + if (x.m_pNext != NULL) + m_pNext = new ErrorInfo(*x.m_pNext); + else + m_pNext = NULL; + + mInterfaceName = x.mInterfaceName; + mCalleeIID = x.mCalleeIID; + mCalleeName = x.mCalleeName; + + mErrorInfo = x.mErrorInfo; +} + +void ErrorInfo::cleanup() +{ + mIsBasicAvailable = false; + mIsFullAvailable = false; + + if (m_pNext) + { + delete m_pNext; + m_pNext = NULL; + } + + mResultCode = S_OK; + mResultDetail = 0; + mInterfaceID.clear(); + mComponent.setNull(); + mText.setNull(); + mInterfaceName.setNull(); + mCalleeIID.clear(); + mCalleeName.setNull(); + mErrorInfo.setNull(); +} + +void ErrorInfo::init(bool aKeepObj /* = false */) +{ + HRESULT rc = E_FAIL; + +#if !defined(VBOX_WITH_XPCOM) + + ComPtr<IErrorInfo> err; + rc = ::GetErrorInfo(0, err.asOutParam()); + if (rc == S_OK && err) + { + if (aKeepObj) + mErrorInfo = err; + + ComPtr<IVirtualBoxErrorInfo> info; + rc = err.queryInterfaceTo(info.asOutParam()); + if (SUCCEEDED(rc) && info) + init(info); + + if (!mIsFullAvailable) + { + bool gotSomething = false; + + rc = err->GetGUID(mInterfaceID.asOutParam()); + gotSomething |= SUCCEEDED(rc); + if (SUCCEEDED(rc)) + GetInterfaceNameByIID(mInterfaceID.ref(), mInterfaceName.asOutParam()); + + rc = err->GetSource(mComponent.asOutParam()); + gotSomething |= SUCCEEDED(rc); + + rc = err->GetDescription(mText.asOutParam()); + gotSomething |= SUCCEEDED(rc); + + if (gotSomething) + mIsBasicAvailable = true; + + AssertMsg(gotSomething, ("Nothing to fetch!\n")); + } + } + +#else // defined(VBOX_WITH_XPCOM) + + nsCOMPtr<nsIExceptionService> es; + es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc); + if (NS_SUCCEEDED(rc)) + { + nsCOMPtr<nsIExceptionManager> em; + rc = es->GetCurrentExceptionManager(getter_AddRefs(em)); + if (NS_SUCCEEDED(rc)) + { + ComPtr<nsIException> ex; + rc = em->GetCurrentException(ex.asOutParam()); + if (NS_SUCCEEDED(rc) && ex) + { + if (aKeepObj) + mErrorInfo = ex; + + ComPtr<IVirtualBoxErrorInfo> info; + rc = ex.queryInterfaceTo(info.asOutParam()); + if (NS_SUCCEEDED(rc) && info) + init(info); + + if (!mIsFullAvailable) + { + bool gotSomething = false; + + rc = ex->GetResult(&mResultCode); + gotSomething |= NS_SUCCEEDED(rc); + + char *pszMsg; + rc = ex->GetMessage(&pszMsg); + gotSomething |= NS_SUCCEEDED(rc); + if (NS_SUCCEEDED(rc)) + { + mText = Bstr(pszMsg); + nsMemory::Free(pszMsg); + } + + if (gotSomething) + mIsBasicAvailable = true; + + AssertMsg(gotSomething, ("Nothing to fetch!\n")); + } + + // set the exception to NULL (to emulate Win32 behavior) + em->SetCurrentException(NULL); + + rc = NS_OK; + } + } + } + /* Ignore failure when called after nsComponentManagerImpl::Shutdown(). */ + else if (rc == NS_ERROR_UNEXPECTED) + rc = NS_OK; + + AssertComRC(rc); + +#endif // defined(VBOX_WITH_XPCOM) +} + +void ErrorInfo::init(IUnknown *aI, + const GUID &aIID, + bool aKeepObj /* = false */) +{ + AssertReturnVoid(aI); + +#if !defined(VBOX_WITH_XPCOM) + + ComPtr<IUnknown> iface = aI; + ComPtr<ISupportErrorInfo> serr; + HRESULT rc = iface.queryInterfaceTo(serr.asOutParam()); + if (SUCCEEDED(rc)) + { + rc = serr->InterfaceSupportsErrorInfo(aIID); + if (SUCCEEDED(rc)) + init(aKeepObj); + } + +#else + + init(aKeepObj); + +#endif + + if (mIsBasicAvailable) + { + mCalleeIID = aIID; + GetInterfaceNameByIID(aIID, mCalleeName.asOutParam()); + } +} + +void ErrorInfo::init(IVirtualBoxErrorInfo *info) +{ + AssertReturnVoid(info); + + HRESULT rc = E_FAIL; + bool gotSomething = false; + bool gotAll = true; + LONG lrc, lrd; + + rc = info->COMGETTER(ResultCode)(&lrc); mResultCode = lrc; + gotSomething |= SUCCEEDED(rc); + gotAll &= SUCCEEDED(rc); + + rc = info->COMGETTER(ResultDetail)(&lrd); mResultDetail = lrd; + gotSomething |= SUCCEEDED(rc); + gotAll &= SUCCEEDED(rc); + + Bstr iid; + rc = info->COMGETTER(InterfaceID)(iid.asOutParam()); + gotSomething |= SUCCEEDED(rc); + gotAll &= SUCCEEDED(rc); + if (SUCCEEDED(rc)) + { + mInterfaceID = iid; + GetInterfaceNameByIID(mInterfaceID.ref(), mInterfaceName.asOutParam()); + } + + rc = info->COMGETTER(Component)(mComponent.asOutParam()); + gotSomething |= SUCCEEDED(rc); + gotAll &= SUCCEEDED(rc); + + rc = info->COMGETTER(Text)(mText.asOutParam()); + gotSomething |= SUCCEEDED(rc); + gotAll &= SUCCEEDED(rc); + + m_pNext = NULL; + + ComPtr<IVirtualBoxErrorInfo> next; + rc = info->COMGETTER(Next)(next.asOutParam()); + if (SUCCEEDED(rc) && !next.isNull()) + { + m_pNext = new ErrorInfo(next); + Assert(m_pNext != NULL); + if (!m_pNext) + rc = E_OUTOFMEMORY; + } + + gotSomething |= SUCCEEDED(rc); + gotAll &= SUCCEEDED(rc); + + mIsBasicAvailable = gotSomething; + mIsFullAvailable = gotAll; + + mErrorInfo = info; + + AssertMsg(gotSomething, ("Nothing to fetch!\n")); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// ProgressErrorInfo class +// +//////////////////////////////////////////////////////////////////////////////// + +ProgressErrorInfo::ProgressErrorInfo(IProgress *progress) : + ErrorInfo(false /* aDummy */) +{ + Assert(progress); + if (!progress) + return; + + ComPtr<IVirtualBoxErrorInfo> info; + HRESULT rc = progress->COMGETTER(ErrorInfo)(info.asOutParam()); + if (SUCCEEDED(rc) && info) + init(info); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// ErrorInfoKeeper class +// +//////////////////////////////////////////////////////////////////////////////// + +HRESULT ErrorInfoKeeper::restore() +{ + if (mForgot) + return S_OK; + + HRESULT rc = S_OK; + +#if !defined(VBOX_WITH_XPCOM) + + ComPtr<IErrorInfo> err; + if (!mErrorInfo.isNull()) + { + rc = mErrorInfo.queryInterfaceTo(err.asOutParam()); + AssertComRC(rc); + } + rc = ::SetErrorInfo(0, err); + +#else // defined(VBOX_WITH_XPCOM) + + nsCOMPtr <nsIExceptionService> es; + es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc); + if (NS_SUCCEEDED(rc)) + { + nsCOMPtr <nsIExceptionManager> em; + rc = es->GetCurrentExceptionManager(getter_AddRefs(em)); + if (NS_SUCCEEDED(rc)) + { + ComPtr<nsIException> ex; + if (!mErrorInfo.isNull()) + { + rc = mErrorInfo.queryInterfaceTo(ex.asOutParam()); + AssertComRC(rc); + } + rc = em->SetCurrentException(ex); + } + } + +#endif // defined(VBOX_WITH_XPCOM) + + if (SUCCEEDED(rc)) + { + mErrorInfo.setNull(); + mForgot = true; + } + + return rc; +} + +} /* namespace com */ + |