Index: /trunk/src/VBox/Main/include/VirtualBoxBase.h
===================================================================
--- /trunk/src/VBox/Main/include/VirtualBoxBase.h	(revision 38532)
+++ /trunk/src/VBox/Main/include/VirtualBoxBase.h	(revision 38533)
@@ -35,4 +35,9 @@
 {
 class File;
+}
+
+namespace com
+{
+class ErrorInfo;
 }
 
@@ -746,10 +751,12 @@
                                     const GUID &aIID,
                                     const char *aComponent,
-                                    const Utf8Str &aText,
+                                    Utf8Str aText,
                                     bool aWarning,
                                     bool aLogIt);
     static void clearError(void);
 
+    HRESULT setError(HRESULT aResultCode);
     HRESULT setError(HRESULT aResultCode, const char *pcsz, ...);
+    HRESULT setError(const ErrorInfo &ei);
     HRESULT setWarning(HRESULT aResultCode, const char *pcsz, ...);
     HRESULT setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...);
Index: /trunk/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h	(revision 38532)
+++ /trunk/src/VBox/Main/include/VirtualBoxErrorInfoImpl.h	(revision 38533)
@@ -94,4 +94,7 @@
                  IVirtualBoxErrorInfo *aNext = NULL);
 
+    HRESULT init(const com::ErrorInfo &ei,
+                 IVirtualBoxErrorInfo *aNext = NULL);
+
     // IVirtualBoxErrorInfo properties
     STDMETHOD(COMGETTER(ResultCode))(LONG *aResultCode);
Index: /trunk/src/VBox/Main/src-all/VirtualBoxBase.cpp
===================================================================
--- /trunk/src/VBox/Main/src-all/VirtualBoxBase.cpp	(revision 38532)
+++ /trunk/src/VBox/Main/src-all/VirtualBoxBase.cpp	(revision 38533)
@@ -306,5 +306,5 @@
                                          const GUID &aIID,
                                          const char *pcszComponent,
-                                         const Utf8Str &aText,
+                                         Utf8Str aText,
                                          bool aWarning,
                                          bool aLogIt)
@@ -328,5 +328,4 @@
                   (aWarning && aResultCode != S_OK),
                   E_FAIL);
-    AssertReturn(!aText.isEmpty(), E_FAIL);
 
     /* reset the error severity bit if it's a warning */
@@ -335,4 +334,34 @@
 
     HRESULT rc = S_OK;
+
+    if (aText.isEmpty())
+    {
+        /* Some default info */
+        switch (aResultCode)
+        {
+            case E_INVALIDARG:                 aText = "A parameter has an invalid value"; break;
+            case E_POINTER:                    aText = "A parameter is an invalid pointer"; break;
+            case E_UNEXPECTED:                 aText = "The result of the operation is unexpected"; break;
+            case E_ACCESSDENIED:               aText = "The access to an object is not allowed"; break;
+            case E_OUTOFMEMORY:                aText = "The allocation of new memory failed"; break;
+            case E_NOTIMPL:                    aText = "The requested operation is not implemented"; break;
+            case E_NOINTERFACE:                aText = "The requested interface is not implemented"; break;
+            case E_FAIL:                       aText = "A general error occurred"; break;
+            case E_ABORT:                      aText = "The operation was canceled"; break;
+            case VBOX_E_OBJECT_NOT_FOUND:      aText = "Object corresponding to the supplied arguments does not exist"; break;
+            case VBOX_E_INVALID_VM_STATE:      aText = "Current virtual machine state prevents the operation"; break;
+            case VBOX_E_VM_ERROR:              aText = "Virtual machine error occurred attempting the operation"; break;
+            case VBOX_E_FILE_ERROR:            aText = "File not accessible or erroneous file contents"; break;
+            case VBOX_E_IPRT_ERROR:            aText = "Runtime subsystem error"; break;
+            case VBOX_E_PDM_ERROR:             aText = "Pluggable Device Manager error"; break;
+            case VBOX_E_INVALID_OBJECT_STATE:  aText = "Current object state prohibits operation"; break;
+            case VBOX_E_HOST_ERROR:            aText = "Host operating system related error"; break;
+            case VBOX_E_NOT_SUPPORTED:         aText = "Requested operation is not supported"; break;
+            case VBOX_E_XML_ERROR:             aText = "Invalid XML found"; break;
+            case VBOX_E_INVALID_SESSION_STATE: aText = "Current session state prohibits operation"; break;
+            case VBOX_E_OBJECT_IN_USE:         aText = "Object being in use prohibits operation"; break;
+            default:                           aText = "Unknown error"; break;
+        }
+    }
 
     do
@@ -456,4 +485,22 @@
  * @return
  */
+HRESULT VirtualBoxBase::setError(HRESULT aResultCode)
+{
+    return setErrorInternal(aResultCode,
+                            this->getClassIID(),
+                            this->getComponentName(),
+                            "",
+                            false /* aWarning */,
+                            true /* aLogIt */);
+}
+
+/**
+ * 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, const char *pcsz, ...)
 {
@@ -471,4 +518,130 @@
 
 /**
+ * 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 rc = S_OK;
+
+    do
+    {
+        ComObjPtr<VirtualBoxErrorInfo> info;
+        rc = info.createObject();
+        if (FAILED(rc)) break;
+
+#if !defined (VBOX_WITH_XPCOM)
+
+        ComPtr<IVirtualBoxErrorInfo> curInfo;
+        if (preserve)
+        {
+            /* get the current error info if any */
+            ComPtr<IErrorInfo> err;
+            rc = ::GetErrorInfo (0, err.asOutParam());
+            if (FAILED(rc)) break;
+            rc = err.queryInterfaceTo(curInfo.asOutParam());
+            if (FAILED(rc))
+            {
+                /* create a IVirtualBoxErrorInfo wrapper for the native
+                 * IErrorInfo object */
+                ComObjPtr<VirtualBoxErrorInfo> wrapper;
+                rc = wrapper.createObject();
+                if (SUCCEEDED(rc))
+                {
+                    rc = wrapper->init (err);
+                    if (SUCCEEDED(rc))
+                        curInfo = wrapper;
+                }
+            }
+        }
+        /* On failure, curInfo will stay null */
+        Assert(SUCCEEDED(rc) || curInfo.isNull());
+
+        /* set the current error info and preserve the previous one if any */
+        rc = info->init(ei, curInfo);
+        if (FAILED(rc)) break;
+
+        ComPtr<IErrorInfo> err;
+        rc = info.queryInterfaceTo(err.asOutParam());
+        if (SUCCEEDED(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 (FAILED(rc)) break;
+
+            ComPtr<IVirtualBoxErrorInfo> curInfo;
+            if (preserve)
+            {
+                /* get the current error info if any */
+                ComPtr<nsIException> ex;
+                rc = em->GetCurrentException (ex.asOutParam());
+                if (FAILED(rc)) break;
+                rc = ex.queryInterfaceTo(curInfo.asOutParam());
+                if (FAILED(rc))
+                {
+                    /* create a IVirtualBoxErrorInfo wrapper for the native
+                     * nsIException object */
+                    ComObjPtr<VirtualBoxErrorInfo> wrapper;
+                    rc = wrapper.createObject();
+                    if (SUCCEEDED(rc))
+                    {
+                        rc = wrapper->init (ex);
+                        if (SUCCEEDED(rc))
+                            curInfo = wrapper;
+                    }
+                }
+            }
+            /* On failure, curInfo will stay null */
+            Assert(SUCCEEDED(rc) || curInfo.isNull());
+
+            /* set the current error info and preserve the previous one if any */
+            rc = info->init(ei, curInfo);
+            if (FAILED(rc)) break;
+
+            ComPtr<nsIException> ex;
+            rc = info.queryInterfaceTo(ex.asOutParam());
+            if (SUCCEEDED(rc))
+                rc = em->SetCurrentException (ex);
+        }
+        else if (rc == 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).
+             */
+            LogWarningFunc(("Will not set an exception because nsIExceptionService is not available "
+                            "(NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n"));
+            rc = NS_OK;
+        }
+
+#endif // !defined (VBOX_WITH_XPCOM)
+    }
+    while (0);
+
+    AssertComRC (rc);
+
+    return SUCCEEDED(rc) ? ei.getResultCode() : rc;
+}
+
+/**
  * Like setError(), but sets the "warning" bit in the call to setErrorInternal().
  * @param aResultCode
Index: /trunk/src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp	(revision 38532)
+++ /trunk/src/VBox/Main/src-all/VirtualBoxErrorInfoImpl.cpp	(revision 38533)
@@ -19,4 +19,6 @@
 #include "Logging.h"
 
+#include <VBox/com/ErrorInfo.h>
+
 // public initializer/uninitializer for internal purposes only
 ////////////////////////////////////////////////////////////////////////////////
@@ -33,4 +35,28 @@
     m_strText = strText;
     mNext = aNext;
+
+    return S_OK;
+}
+
+HRESULT VirtualBoxErrorInfo::init(const com::ErrorInfo &info,
+                                  IVirtualBoxErrorInfo *aNext)
+{
+    m_resultCode = info.getResultCode();
+    m_IID = info.getInterfaceID();
+    m_strComponent = info.getComponent();
+    m_strText = info.getText();
+
+    /* Recursively create VirtualBoxErrorInfo instances for the next objects. */
+    const com::ErrorInfo *pInfo = info.getNext();
+    if (pInfo)
+    {
+        ComObjPtr<VirtualBoxErrorInfo> nextEI;
+        HRESULT rc = nextEI.createObject();
+        if (FAILED(rc)) return rc;
+        rc = nextEI->init(*pInfo, aNext);
+        if (FAILED(rc)) return rc;
+        mNext = nextEI;
+    }else
+        mNext = aNext;
 
     return S_OK;
