/** @file * MS COM / XPCOM Abstraction Layer: * ErrorInfo class declaration */ /* * 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. * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the * VirtualBox OSE distribution, in which case the provisions of the * CDDL are applicable instead of those of the GPL. * * You may elect to license modified versions of this file under the * terms and conditions of either the GPL or the CDDL or both. */ #ifndef ___VBox_com_ErrorInfo_h #define ___VBox_com_ErrorInfo_h #include "VBox/com/ptr.h" #include "VBox/com/string.h" #include "VBox/com/Guid.h" #include "VBox/com/assert.h" #include // for auto_copy_ptr struct IProgress; struct IVirtualBoxErrorInfo; namespace com { /** * The ErrorInfo class provides a convenient way to retrieve error * information set by the most recent interface method, that was invoked on * the current thread and returned an unsuccessful result code. * * Once the instance of this class is created, the error information for * the current thread is cleared. * * There is no sense to use instances of this class after the last * invoked interface method returns a success. * * The class usage pattern is as follows: * * IFoo *foo; * ... * HRESULT rc = foo->SomeMethod(); * if (FAILED (rc)) { * ErrorInfo info (foo); * if (info.isFullAvailable()) { * printf ("error message = %ls\n", info.getText().raw()); * } * } * * * This class fetches error information using the IErrorInfo interface on * Win32 (MS COM) or the nsIException interface on other platforms (XPCOM), * or the extended IVirtualBoxErrorInfo interface when when it is available * (i.e. a given IErrorInfo or nsIException instance implements it). * Currently, IVirtualBoxErrorInfo is only available for VirtualBox components. * * ErrorInfo::isFullAvailable() and ErrorInfo::isBasicAvailable() determine * what level of error information is available. If #isBasicAvailable() * returns true, it means that only IErrorInfo or nsIException is available as * the source of information (depending on the platform), but not * IVirtualBoxErrorInfo. If #isFullAvailable() returns true, it means that all * three interfaces are available. If both methods return false, no error info * is available at all. * * Here is a table of correspondence between this class methods and * and IErrorInfo/nsIException/IVirtualBoxErrorInfo attributes/methods: * * ErrorInfo IErrorInfo nsIException IVirtualBoxErrorInfo * -------------------------------------------------------------------- * getResultCode -- result resultCode * getIID GetGUID -- interfaceID * getComponent GetSource -- component * getText GetDescription message text * * '--' means that this interface does not provide the corresponding portion * of information, therefore it is useless to query it if only * #isBasicAvailable() returns true. As it can be seen, the amount of * information provided at the basic level, depends on the platform * (MS COM or XPCOM). */ class ErrorInfo { public: /** * Constructs a new, "interfaceless" ErrorInfo instance that takes * the error information possibly set on the current thread by an * interface method of some COM component or by the COM subsystem. * * This constructor is useful, for example, after an unsuccessful attempt * to instantiate (create) a component, so there is no any valid interface * pointer available. */ explicit ErrorInfo() : mIsBasicAvailable (false), mIsFullAvailable (false) , mResultCode (S_OK) { init(); } /** * Constructs a new, "interfaceless" ErrorInfo instance that takes * the error information possibly set on the current thread by an * interface method of the given interface pointer. * If the given interface does not support providing error information or, * for some reason didn't set any error information, both * #isFullAvailable() and #isBasicAvailable() will return |false|. * * @param aPtr pointer to the interface whose method returned an * error */ template ErrorInfo (I *aPtr) : mIsBasicAvailable (false), mIsFullAvailable (false) , mResultCode (S_OK) { init (aPtr, COM_IIDOF(I)); } /** * Constructs a new ErrorInfo instance from the smart interface pointer. * See template ErrorInfo (I *aPtr) for details * * @param aPtr smart pointer to the interface whose method returned * an error */ template ErrorInfo (const ComPtr &aPtr) : mIsBasicAvailable (false), mIsFullAvailable (false) , mResultCode (S_OK) { init (static_cast (aPtr), COM_IIDOF(I)); } /** Specialization for the IVirtualBoxErrorInfo smart pointer */ ErrorInfo (const ComPtr &aPtr) : mIsBasicAvailable (false), mIsFullAvailable (false) , mResultCode (S_OK) { init (aPtr); } /** * Constructs a new ErrorInfo instance from the IVirtualBoxErrorInfo * interface pointer. If this pointer is not NULL, both #isFullAvailable() * and #isBasicAvailable() will return |true|. * * @param aInfo pointer to the IVirtualBoxErrorInfo interface that * holds error info to be fetched by this instance */ ErrorInfo (IVirtualBoxErrorInfo *aInfo) : mIsBasicAvailable (false), mIsFullAvailable (false) , mResultCode (S_OK) { init (aInfo); } virtual ~ErrorInfo(); /** * Returns whether basic error info is actually available for the current * thread. If the instance was created from an interface pointer that * supports basic error info and successfully provided it, or if it is an * "interfaceless" instance and there is some error info for the current * thread, the returned value will be true. * * See the class description for details about the basic error info level. * * The appropriate methods of this class provide meaningful info only when * this method returns true (otherwise they simply return NULL-like values). */ bool isBasicAvailable() const { return mIsBasicAvailable; } /** * Returns whether full error info is actually available for the current * thread. If the instance was created from an interface pointer that * supports full error info and successfully provided it, or if it is an * "interfaceless" instance and there is some error info for the current * thread, the returned value will be true. * * See the class description for details about the full error info level. * * The appropriate methods of this class provide meaningful info only when * this method returns true (otherwise they simply return NULL-like values). */ bool isFullAvailable() const { return mIsFullAvailable; } /** * Returns @c true if both isBasicAvailable() and isFullAvailable() are * @c false. */ bool isNull() const { return !mIsBasicAvailable && !mIsFullAvailable; } /** * Returns the COM result code of the failed operation. */ HRESULT getResultCode() const { return mResultCode; } /** * Returns the IID of the interface that defined the error. */ const Guid &getInterfaceID() const { return mInterfaceID; } /** * Returns the name of the component that generated the error. */ const Bstr &getComponent() const { return mComponent; } /** * Returns the textual description of the error. */ const Bstr &getText() const { return mText; } /** * Returns the next error information object or @c NULL if there is none. */ const ErrorInfo *getNext() const { return mNext.get(); } /** * Returns the name of the interface that defined the error */ const Bstr &getInterfaceName() const { return mInterfaceName; } /** * Returns the IID of the interface that returned the error. * * This method returns a non-null IID only if the instance was created * using #template ErrorInfo (I *i) or * template ErrorInfo (const ComPtr &i) constructor. */ const Guid &getCalleeIID() const { return mCalleeIID; } /** * Returns the name of the interface that returned the error * * This method returns a non-null name only if the instance was created * using #template ErrorInfo (I *i) or * template ErrorInfo (const ComPtr &i) constructor. */ const Bstr &getCalleeName() const { return mCalleeName; } /** * Resets all collected error information. #isNull() will * return @c true after this method is called. */ void setNull() { mIsBasicAvailable = false; mIsFullAvailable = false; mResultCode = S_OK; mInterfaceID.clear(); mComponent.setNull(); mText.setNull(); mNext.reset(); mInterfaceName.setNull(); mCalleeIID.clear(); mCalleeName.setNull(); mErrorInfo.setNull(); } protected: ErrorInfo (bool /* aDummy */) : mIsBasicAvailable (false), mIsFullAvailable (false) , mResultCode (S_OK) {} void init (bool aKeepObj = false); void init (IUnknown *aUnk, const GUID &aIID, bool aKeepObj = false); void init (IVirtualBoxErrorInfo *aInfo); bool mIsBasicAvailable : 1; bool mIsFullAvailable : 1; HRESULT mResultCode; Guid mInterfaceID; Bstr mComponent; Bstr mText; cppx::auto_copy_ptr mNext; Bstr mInterfaceName; Guid mCalleeIID; Bstr mCalleeName; ComPtr mErrorInfo; }; /** * A convenience subclass of ErrorInfo that, given an IProgress interface * pointer, reads its errorInfo attribute and uses the returned * IVirtualBoxErrorInfo instance to construct itself. */ class ProgressErrorInfo : public ErrorInfo { public: /** * Constructs a new instance by fetching error information from the * IProgress interface pointer. If the progress object is not NULL, * its completed attribute is true, resultCode represents a failure, * and the errorInfo attribute returns a valid IVirtualBoxErrorInfo pointer, * both #isFullAvailable() and #isBasicAvailable() will return true. * * @param progress the progress object representing a failed operation */ ProgressErrorInfo (IProgress *progress); }; /** * A convenience subclass of ErrorInfo that allows to preserve the current * error info. Instances of this class fetch an error info object set on the * current thread and keep a reference to it, which allows to restore it * later using the #restore() method. This is useful to preserve error * information returned by some method for the duration of making another COM * call that may set its own error info and overwrite the existing * one. Preserving and restoring error information makes sense when some * method wants to return error information set by other call as its own * error information while it still needs to make another call before return. * * Instead of calling #restore() explicitly you may let the object destructor * do it for you, if you correctly limit the object's lifetime. * * The usage pattern is: * * rc = foo->method(); * if (FAILED (rc)) * { * ErrorInfoKeeper eik; * ... * // bar may return error info as well * bar->method(); * ... * // no need to call #restore() explicitly here because the eik's * // destructor will restore error info fetched after the failed * // call to foo before returning to the caller * return rc; * } * */ class ErrorInfoKeeper : public ErrorInfo { public: /** * Constructs a new instance that will fetch the current error info if * @a aIsNull is @c false (by default) or remain uninitialized (null) * otherwise. * * @param aIsNull @c true to prevent fetching error info and leave * the instance uninitialized. */ ErrorInfoKeeper (bool aIsNull = false) : ErrorInfo (false), mForgot (aIsNull) { if (!aIsNull) init (true /* aKeepObj */); } /** * Destroys this instance and automatically calls #restore() which will * either restore error info fetched by the constructor or do nothing * if #forget() was called before destruction. */ ~ErrorInfoKeeper() { if (!mForgot) restore(); } /** * Tries to (re-)fetch error info set on the current thread. On success, * the previous error information, if any, will be overwritten with the * new error information. On failure, or if there is no error information * available, this instance will be reset to null. */ void fetch() { setNull(); mForgot = false; init (true /* aKeepObj */); } /** * Restores error info fetched by the constructor and forgets it * afterwards. Does nothing if the error info was forgotten by #forget(). * * @return COM result of the restore operation. */ HRESULT restore(); /** * Forgets error info fetched by the constructor to prevent it from * being restored by #restore() or by the destructor. */ void forget() { mForgot = true; } /** * Forgets error info fetched by the constructor to prevent it from * being restored by #restore() or by the destructor, and returns the * stored error info object to the caller. */ ComPtr takeError() { mForgot = true; return mErrorInfo; } private: bool mForgot : 1; }; } /* namespace com */ #endif