summaryrefslogtreecommitdiffstats
path: root/src/VBox/Main/glue/ErrorInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/glue/ErrorInfo.cpp')
-rw-r--r--src/VBox/Main/glue/ErrorInfo.cpp374
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 */
+