ErrorInfo.cpp revision e07acfb7f2dbb8bb40804024c79fd3139bdb3f24
/* $Id$ */
/** @file
*
* ErrorInfo class definition
*/
/*
* Copyright (C) 2006-2007 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#if !defined (VBOX_WITH_XPCOM)
#else
#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 <iprt/stream.h>
#include <iprt/string.h>
#include <VBox/err.h>
namespace com
{
// ErrorInfo class
////////////////////////////////////////////////////////////////////////////////
void ErrorInfo::copyFrom(const ErrorInfo &x)
{
mIsBasicAvailable = x.mIsBasicAvailable;
mIsFullAvailable = x.mIsFullAvailable;
mResultCode = x.mResultCode;
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;
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, 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(mText);
}
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 */)
{
Assert(aI);
if (!aI)
return;
#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;
rc = info->COMGETTER(ResultCode) (&lrc); mResultCode = lrc;
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, 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;
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 */