root/trunk/include/VBox/com/ErrorInfo.h
| Revision 13856, 14.7 kB (checked in by vboxsync, 2 months ago) | |
|---|---|
| |
| Line | |
|---|---|
| 1 | /** @file |
| 2 | * MS COM / XPCOM Abstraction Layer: |
| 3 | * ErrorInfo class declaration |
| 4 | */ |
| 5 | |
| 6 | /* |
| 7 | * Copyright (C) 2006-2007 Sun Microsystems, Inc. |
| 8 | * |
| 9 | * This file is part of VirtualBox Open Source Edition (OSE), as |
| 10 | * available from http://www.virtualbox.org. This file is free software; |
| 11 | * you can redistribute it and/or modify it under the terms of the GNU |
| 12 | * General Public License (GPL) as published by the Free Software |
| 13 | * Foundation, in version 2 as it comes in the "COPYING" file of the |
| 14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the |
| 15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. |
| 16 | * |
| 17 | * The contents of this file may alternatively be used under the terms |
| 18 | * of the Common Development and Distribution License Version 1.0 |
| 19 | * (CDDL) only, as it comes in the "COPYING.CDDL" file of the |
| 20 | * VirtualBox OSE distribution, in which case the provisions of the |
| 21 | * CDDL are applicable instead of those of the GPL. |
| 22 | * |
| 23 | * You may elect to license modified versions of this file under the |
| 24 | * terms and conditions of either the GPL or the CDDL or both. |
| 25 | * |
| 26 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa |
| 27 | * Clara, CA 95054 USA or visit http://www.sun.com if you need |
| 28 | * additional information or have any questions. |
| 29 | */ |
| 30 | |
| 31 | #ifndef ___VBox_com_ErrorInfo_h |
| 32 | #define ___VBox_com_ErrorInfo_h |
| 33 | |
| 34 | #include "VBox/com/ptr.h" |
| 35 | #include "VBox/com/string.h" |
| 36 | #include "VBox/com/Guid.h" |
| 37 | #include "VBox/com/assert.h" |
| 38 | |
| 39 | #include <iprt/memory> // for auto_copy_ptr |
| 40 | |
| 41 | struct IProgress; |
| 42 | struct IVirtualBoxErrorInfo; |
| 43 | |
| 44 | namespace com |
| 45 | { |
| 46 | |
| 47 | /** |
| 48 | * The ErrorInfo class provides a convenient way to retrieve error |
| 49 | * information set by the most recent interface method, that was invoked on |
| 50 | * the current thread and returned an unsuccessful result code. |
| 51 | * |
| 52 | * Once the instance of this class is created, the error information for |
| 53 | * the current thread is cleared. |
| 54 | * |
| 55 | * There is no sense to use instances of this class after the last |
| 56 | * invoked interface method returns a success. |
| 57 | * |
| 58 | * The class usage pattern is as follows: |
| 59 | * <code> |
| 60 | * IFoo *foo; |
| 61 | * ... |
| 62 | * HRESULT rc = foo->SomeMethod(); |
| 63 | * if (FAILED (rc)) { |
| 64 | * ErrorInfo info (foo); |
| 65 | * if (info.isFullAvailable()) { |
| 66 | * printf ("error message = %ls\n", info.getText().raw()); |
| 67 | * } |
| 68 | * } |
| 69 | * </code> |
| 70 | * |
| 71 | * This class fetches error information using the IErrorInfo interface on |
| 72 | * Win32 (MS COM) or the nsIException interface on other platforms (XPCOM), |
| 73 | * or the extended IVirtualBoxErrorInfo interface when when it is available |
| 74 | * (i.e. a given IErrorInfo or nsIException instance implements it). |
| 75 | * Currently, IVirtualBoxErrorInfo is only available for VirtualBox components. |
| 76 | * |
| 77 | * ErrorInfo::isFullAvailable() and ErrorInfo::isBasicAvailable() determine |
| 78 | * what level of error information is available. If #isBasicAvailable() |
| 79 | * returns true, it means that only IErrorInfo or nsIException is available as |
| 80 | * the source of information (depending on the platform), but not |
| 81 | * IVirtualBoxErrorInfo. If #isFullAvailable() returns true, it means that all |
| 82 | * three interfaces are available. If both methods return false, no error info |
| 83 | * is available at all. |
| 84 | * |
| 85 | * Here is a table of correspondence between this class methods and |
| 86 | * and IErrorInfo/nsIException/IVirtualBoxErrorInfo attributes/methods: |
| 87 | * |
| 88 | * ErrorInfo IErrorInfo nsIException IVirtualBoxErrorInfo |
| 89 | * -------------------------------------------------------------------- |
| 90 | * getResultCode -- result resultCode |
| 91 | * getIID GetGUID -- interfaceID |
| 92 | * getComponent GetSource -- component |
| 93 | * getText GetDescription message text |
| 94 | * |
| 95 | * '--' means that this interface does not provide the corresponding portion |
| 96 | * of information, therefore it is useless to query it if only |
| 97 | * #isBasicAvailable() returns true. As it can be seen, the amount of |
| 98 | * information provided at the basic level, depends on the platform |
| 99 | * (MS COM or XPCOM). |
| 100 | */ |
| 101 | class ErrorInfo |
| 102 | { |
| 103 | public: |
| 104 | |
| 105 | /** |
| 106 | * Constructs a new, "interfaceless" ErrorInfo instance that takes |
| 107 | * the error information possibly set on the current thread by an |
| 108 | * interface method of some COM component or by the COM subsystem. |
| 109 | * |
| 110 | * This constructor is useful, for example, after an unsuccessful attempt |
| 111 | * to instantiate (create) a component, so there is no any valid interface |
| 112 | * pointer available. |
| 113 | */ |
| 114 | explicit ErrorInfo() |
| 115 | : mIsBasicAvailable (false), mIsFullAvailable (false) |
| 116 | , mResultCode (S_OK) |
| 117 | { init(); } |
| 118 | |
| 119 | /** |
| 120 | * Constructs a new, "interfaceless" ErrorInfo instance that takes |
| 121 | * the error information possibly set on the current thread by an |
| 122 | * interface method of the given interface pointer. |
| 123 | |
| 124 | * If the given interface does not support providing error information or, |
| 125 | * for some reason didn't set any error information, both |
| 126 | * #isFullAvailable() and #isBasicAvailable() will return |false|. |
| 127 | * |
| 128 | * @param aPtr pointer to the interface whose method returned an |
| 129 | * error |
| 130 | */ |
| 131 | template <class I> ErrorInfo (I *aPtr) |
| 132 | : mIsBasicAvailable (false), mIsFullAvailable (false) |
| 133 | , mResultCode (S_OK) |
| 134 | { init (aPtr, COM_IIDOF(I)); } |
| 135 | |
| 136 | /** |
| 137 | * Constructs a new ErrorInfo instance from the smart interface pointer. |
| 138 | * See template <class I> ErrorInfo (I *aPtr) for details |
| 139 | * |
| 140 | * @param aPtr smart pointer to the interface whose method returned |
| 141 | * an error |
| 142 | */ |
| 143 | template <class I> ErrorInfo (const ComPtr <I> &aPtr) |
| 144 | : mIsBasicAvailable (false), mIsFullAvailable (false) |
| 145 | , mResultCode (S_OK) |
| 146 | { init (static_cast <I*> (aPtr), COM_IIDOF(I)); } |
| 147 | |
| 148 | /** Specialization for the IVirtualBoxErrorInfo smart pointer */ |
| 149 | ErrorInfo (const ComPtr <IVirtualBoxErrorInfo> &aPtr) |
| 150 | : mIsBasicAvailable (false), mIsFullAvailable (false) |
| 151 | , mResultCode (S_OK) |
| 152 | { init (aPtr); } |
| 153 | |
| 154 | /** |
| 155 | * Constructs a new ErrorInfo instance from the IVirtualBoxErrorInfo |
| 156 | * interface pointer. If this pointer is not NULL, both #isFullAvailable() |
| 157 | * and #isBasicAvailable() will return |true|. |
| 158 | * |
| 159 | * @param aInfo pointer to the IVirtualBoxErrorInfo interface that |
| 160 | * holds error info to be fetched by this instance |
| 161 | */ |
| 162 | ErrorInfo (IVirtualBoxErrorInfo *aInfo) |
| 163 | : mIsBasicAvailable (false), mIsFullAvailable (false) |
| 164 | , mResultCode (S_OK) |
| 165 | { init (aInfo); } |
| 166 | |
| 167 | virtual ~ErrorInfo(); |
| 168 | |
| 169 | /** |
| 170 | * Returns whether basic error info is actually available for the current |
| 171 | * thread. If the instance was created from an interface pointer that |
| 172 | * supports basic error info and successfully provided it, or if it is an |
| 173 | * "interfaceless" instance and there is some error info for the current |
| 174 | * thread, the returned value will be true. |
| 175 | * |
| 176 | * See the class description for details about the basic error info level. |
| 177 | * |
| 178 | * The appropriate methods of this class provide meaningful info only when |
| 179 | * this method returns true (otherwise they simply return NULL-like values). |
| 180 | */ |
| 181 | bool isBasicAvailable() const { return mIsBasicAvailable; } |
| 182 | |
| 183 | /** |
| 184 | * Returns whether full error info is actually available for the current |
| 185 | * thread. If the instance was created from an interface pointer that |
| 186 | * supports full error info and successfully provided it, or if it is an |
| 187 | * "interfaceless" instance and there is some error info for the current |
| 188 | * thread, the returned value will be true. |
| 189 | * |
| 190 | * See the class description for details about the full error info level. |
| 191 | * |
| 192 | * The appropriate methods of this class provide meaningful info only when |
| 193 | * this method returns true (otherwise they simply return NULL-like values). |
| 194 | */ |
| 195 | bool isFullAvailable() const { return mIsFullAvailable; } |
| 196 | |
| 197 | /** |
| 198 | * Returns @c true if both isBasicAvailable() and isFullAvailable() are |
| 199 | * @c false. |
| 200 | */ |
| 201 | bool isNull() const { return !mIsBasicAvailable && !mIsFullAvailable; } |
| 202 | |
| 203 | /** |
| 204 | * Returns the COM result code of the failed operation. |
| 205 | */ |
| 206 | HRESULT getResultCode() const { return mResultCode; } |
| 207 | |
| 208 | /** |
| 209 | * Returns the IID of the interface that defined the error. |
| 210 | */ |
| 211 | const Guid &getInterfaceID() const { return mInterfaceID; } |
| 212 | |
| 213 | /** |
| 214 | * Returns the name of the component that generated the error. |
| 215 | */ |
| 216 | const Bstr &getComponent() const { return mComponent; } |
| 217 | |
| 218 | /** |
| 219 | * Returns the textual description of the error. |
| 220 | */ |
| 221 | const Bstr &getText() const { return mText; } |
| 222 | |
| 223 | /** |
| 224 | * Returns the next error information object or @c NULL if there is none. |
| 225 | */ |
| 226 | const ErrorInfo *getNext() const { return mNext.get(); } |
| 227 | |
| 228 | /** |
| 229 | * Returns the name of the interface that defined the error |
| 230 | */ |
| 231 | const Bstr &getInterfaceName() const { return mInterfaceName; } |
| 232 | |
| 233 | /** |
| 234 | * Returns the IID of the interface that returned the error. |
| 235 | * |
| 236 | * This method returns a non-null IID only if the instance was created |
| 237 | * using #template <class I> ErrorInfo (I *i) or |
| 238 | * template <class I> ErrorInfo (const ComPtr <I> &i) constructor. |
| 239 | */ |
| 240 | const Guid &getCalleeIID() const { return mCalleeIID; } |
| 241 | |
| 242 | /** |
| 243 | * Returns the name of the interface that returned the error |
| 244 | * |
| 245 | * This method returns a non-null name only if the instance was created |
| 246 | * using #template <class I> ErrorInfo (I *i) or |
| 247 | * template <class I> ErrorInfo (const ComPtr <I> &i) constructor. |
| 248 | */ |
| 249 | const Bstr &getCalleeName() const { return mCalleeName; } |
| 250 | |
| 251 | /** |
| 252 | * Resets all collected error information. #isNull() will |
| 253 | * return @c true after this method is called. |
| 254 | */ |
| 255 | void setNull() |
| 256 | { |
| 257 | mIsBasicAvailable = false; |
| 258 | mIsFullAvailable = false; |
| 259 | |
| 260 | mResultCode = S_OK; |
| 261 | mInterfaceID.clear(); |
| 262 | mComponent.setNull(); |
| 263 | mText.setNull(); |
| 264 | mNext.reset(); |
| 265 | mInterfaceName.setNull(); |
| 266 | mCalleeIID.clear(); |
| 267 | mCalleeName.setNull(); |
| 268 | mErrorInfo.setNull(); |
| 269 | } |
| 270 | |
| 271 | protected: |
| 272 | |
| 273 | ErrorInfo (bool aDummy) |
| 274 | : mIsBasicAvailable (false), mIsFullAvailable (false) |
| 275 | , mResultCode (S_OK) |
| 276 | {} |
| 277 | |
| 278 | void init (bool aKeepObj = false); |
| 279 | void init (IUnknown *aUnk, const GUID &aIID, bool aKeepObj = false); |
| 280 | void init (IVirtualBoxErrorInfo *aInfo); |
| 281 | |
| 282 | bool mIsBasicAvailable : 1; |
| 283 | bool mIsFullAvailable : 1; |
| 284 | |
| 285 | HRESULT mResultCode; |
| 286 | Guid mInterfaceID; |
| 287 | Bstr mComponent; |
| 288 | Bstr mText; |
| 289 | |
| 290 | cppx::auto_copy_ptr <ErrorInfo> mNext; |
| 291 | |
| 292 | Bstr mInterfaceName; |
| 293 | Guid mCalleeIID; |
| 294 | Bstr mCalleeName; |
| 295 | |
| 296 | ComPtr <IUnknown> mErrorInfo; |
| 297 | }; |
| 298 | |
| 299 | /** |
| 300 | * A convenience subclass of ErrorInfo that, given an IProgress interface |
| 301 | * pointer, reads its errorInfo attribute and uses the returned |
| 302 | * IVirtualBoxErrorInfo instance to construct itself. |
| 303 | */ |
| 304 | class ProgressErrorInfo : public ErrorInfo |
| 305 | { |
| 306 | public: |
| 307 | |
| 308 | /** |
| 309 | * Constructs a new instance by fetching error information from the |
| 310 | * IProgress interface pointer. If the progress object is not NULL, |
| 311 | * its completed attribute is true, resultCode represents a failure, |
| 312 | * and the errorInfo attribute returns a valid IVirtualBoxErrorInfo pointer, |
| 313 | * both #isFullAvailable() and #isBasicAvailable() will return true. |
| 314 | * |
| 315 | * @param progress the progress object representing a failed operation |
| 316 | */ |
| 317 | ProgressErrorInfo (IProgress *progress); |
| 318 | }; |
| 319 | |
| 320 | /** |
| 321 | * A convenience subclass of ErrorInfo that allows to preserve the current |
| 322 | * error info. Instances of this class fetch an error info object set on the |
| 323 | * current thread and keep a reference to it, which allows to restore it |
| 324 | * later using the #restore() method. This is useful to preserve error |
| 325 | * information returned by some method for the duration of making another COM |
| 326 | * call that may set its own error info and overwrite the existing |
| 327 | * one. Preserving and restoring error information makes sense when some |
| 328 | * method wants to return error information set by other call as its own |
| 329 | * error information while it still needs to make another call before return. |
| 330 | * |
| 331 | * Instead of calling #restore() explicitly you may let the object destructor |
| 332 | * do it for you, if you correctly limit the object's lifetime. |
| 333 | * |
| 334 | * The usage pattern is: |
| 335 | * <code> |
| 336 | * rc = foo->method(); |
| 337 | * if (FAILED (rc)) |
| 338 | * { |
| 339 | * ErrorInfoKeeper eik; |
| 340 | * ... |
| 341 | * // bar may return error info as well |
| 342 | * bar->method(); |
| 343 | * ... |
| 344 | * // no need to call #restore() explicitly here because the eik's |
| 345 | * // destructor will restore error info fetched after the failed |
| 346 | * // call to foo before returning to the caller |
| 347 | * return rc; |
| 348 | * } |
| 349 | * </code> |
| 350 | */ |
| 351 | class ErrorInfoKeeper : public ErrorInfo |
| 352 | { |
| 353 | public: |
| 354 | |
| 355 | /** |
| 356 | * Constructs a new instance that will fetch the current error info if |
| 357 | * @a aIsNull is @c false (by default) or remain uninitialized (null) |
| 358 | * otherwise. |
| 359 | * |
| 360 | * @param aIsNull @true to prevent fetching error info and leave |
| 361 | * the instance uninitialized. |
| 362 | */ |
| 363 | ErrorInfoKeeper (bool aIsNull = false) |
| 364 | : ErrorInfo (false), mForgot (aIsNull) |
| 365 | { |
| 366 | if (!aIsNull) |
| 367 | init (true /* aKeepObj */); |
| 368 | } |
| 369 | |
| 370 | /** |
| 371 | * Destroys this instance and automatically calls #restore() which will |
| 372 | * either restore error info fetched by the constructor or do nothing |
| 373 | * if #forget() was called before destruction. |
| 374 | */ |
| 375 | ~ErrorInfoKeeper() { if (!mForgot) restore(); } |
| 376 | |
| 377 | /** |
| 378 | * Tries to (re-)fetch error info set on the current thread. On success, |
| 379 | * the previous error information, if any, will be overwritten with the |
| 380 | * new error information. On failure, or if there is no error information |
| 381 | * available, this instance will be reset to null. |
| 382 | */ |
| 383 | void fetch() |
| 384 | { |
| 385 | setNull(); |
| 386 | mForgot = false; |
| 387 | init (true /* aKeepObj */); |
| 388 | } |
| 389 | |
| 390 | /** |
| 391 | * Restores error info fetched by the constructor and forgets it |
| 392 | * afterwards. Does nothing if the error info was forgotten by #forget(). |
| 393 | * |
| 394 | * @return COM result of the restore operation. |
| 395 | */ |
| 396 | HRESULT restore(); |
| 397 | |
| 398 | /** |
| 399 | * Forgets error info fetched by the constructor to prevent it from |
| 400 | * being restored by #restore() or by the destructor. |
| 401 | */ |
| 402 | void forget() { mForgot = true; } |
| 403 | |
| 404 | /** |
| 405 | * Forgets error info fetched by the constructor to prevent it from |
| 406 | * being restored by #restore() or by the destructor, and returns the |
| 407 | * stored error info object to the caller. |
| 408 | */ |
| 409 | ComPtr <IUnknown> takeError() { mForgot = true; return mErrorInfo; } |
| 410 | |
| 411 | private: |
| 412 | |
| 413 | bool mForgot : 1; |
| 414 | }; |
| 415 | |
| 416 | } /* namespace com */ |
| 417 | |
| 418 | #endif |
| 419 |
Note: See TracBrowser for help on using the browser.

