VirtualBox

source: vbox/trunk/include/VBox/com/ErrorInfo.h@ 41279

Last change on this file since 41279 was 38687, checked in by vboxsync, 13 years ago

Spelling.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.1 KB
Line 
1/** @file
2 * MS COM / XPCOM Abstraction Layer:
3 * ErrorInfo class declaration
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
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
27#ifndef ___VBox_com_ErrorInfo_h
28#define ___VBox_com_ErrorInfo_h
29
30#include "VBox/com/ptr.h"
31#include "VBox/com/string.h"
32#include "VBox/com/Guid.h"
33#include "VBox/com/assert.h"
34
35struct IProgress;
36struct IVirtualBoxErrorInfo;
37
38namespace com
39{
40
41/**
42 * General discussion:
43 *
44 * In COM all errors are stored on a per thread basis. In general this means
45 * only _one_ active error is possible per thread. A new error will overwrite
46 * the previous one. To prevent this use MultiResult or ErrorInfoKeeper (see
47 * below). The implementations in MSCOM/XPCOM differ slightly, but the details
48 * are handled by this glue code.
49 *
50 * We have different classes which are involved in the error management. I try
51 * to describe them separately to make clear what they are there for.
52 *
53 * ErrorInfo:
54 *
55 * This class is able to retrieve the per thread error and store it into its
56 * member variables. This class can also handle non-VirtualBox errors (like
57 * standard COM errors).
58 *
59 * ProgressErrorInfo:
60 *
61 * This is just a simple wrapper class to get the ErrorInfo stored within an
62 * IProgress object. That is the error which was stored when the progress
63 * object was in use and not an error produced by IProgress itself.
64 *
65 * IVirtualBoxErrorInfo:
66 *
67 * The VirtualBox interface class for accessing error information from Main
68 * clients. This class is also used for storing the error information in the
69 * thread context.
70 *
71 * ErrorInfoKeeper:
72 *
73 * A helper class which stores the current per thread info internally. After
74 * calling methods which may produce other errors it is possible to restore
75 * the previous error and therefore restore the situation before calling the
76 * other methods.
77 *
78 * MultiResult:
79 *
80 * Creating an instance of MultiResult turns error chain saving on. All errors
81 * which follow will be saved in a chain for later access.
82 *
83 * COMErrorInfo (Qt/Gui only):
84 *
85 * The Qt GUI does some additional work for saving errors. Because we create
86 * wrappers for _every_ COM call, it is possible to automatically save the
87 * error info after the execution. This allow some additional info like saving
88 * the callee. Please note that this error info is saved on the client side
89 * and therefore locally to the object instance. See COMBaseWithEI,
90 * COMErrorInfo and the generated COMWrappers.cpp in the GUI.
91 *
92 * Errors itself are set in VirtualBoxBase::setErrorInternal. First a
93 * IVirtualBoxErrorInfo object is created and the given error is saved within.
94 * If MultiResult is active the current per thread error is fetched and
95 * attached to the new created IVirtualBoxErrorInfo object. Next this object is
96 * set as the new per thread error.
97 *
98 * Some general hints:
99 *
100 * - Always use setError, especially when you are working in an asynchronous thread
101 * to indicate an error. Otherwise the error information itself will not make
102 * it into the client.
103 *
104 */
105
106/**
107 * The ErrorInfo class provides a convenient way to retrieve error
108 * information set by the most recent interface method, that was invoked on
109 * the current thread and returned an unsuccessful result code.
110 *
111 * Once the instance of this class is created, the error information for
112 * the current thread is cleared.
113 *
114 * There is no sense to use instances of this class after the last
115 * invoked interface method returns a success.
116 *
117 * The class usage pattern is as follows:
118 * <code>
119 * IFoo *foo;
120 * ...
121 * HRESULT rc = foo->SomeMethod();
122 * if (FAILED(rc)) {
123 * ErrorInfo info(foo);
124 * if (info.isFullAvailable()) {
125 * printf("error message = %ls\n", info.getText().raw());
126 * }
127 * }
128 * </code>
129 *
130 * This class fetches error information using the IErrorInfo interface on
131 * Win32 (MS COM) or the nsIException interface on other platforms (XPCOM),
132 * or the extended IVirtualBoxErrorInfo interface when when it is available
133 * (i.e. a given IErrorInfo or nsIException instance implements it).
134 * Currently, IVirtualBoxErrorInfo is only available for VirtualBox components.
135 *
136 * ErrorInfo::isFullAvailable() and ErrorInfo::isBasicAvailable() determine
137 * what level of error information is available. If #isBasicAvailable()
138 * returns true, it means that only IErrorInfo or nsIException is available as
139 * the source of information (depending on the platform), but not
140 * IVirtualBoxErrorInfo. If #isFullAvailable() returns true, it means that all
141 * three interfaces are available. If both methods return false, no error info
142 * is available at all.
143 *
144 * Here is a table of correspondence between this class methods and
145 * and IErrorInfo/nsIException/IVirtualBoxErrorInfo attributes/methods:
146 *
147 * ErrorInfo IErrorInfo nsIException IVirtualBoxErrorInfo
148 * --------------------------------------------------------------------
149 * getResultCode -- result resultCode
150 * getIID GetGUID -- interfaceID
151 * getComponent GetSource -- component
152 * getText GetDescription message text
153 *
154 * '--' means that this interface does not provide the corresponding portion
155 * of information, therefore it is useless to query it if only
156 * #isBasicAvailable() returns true. As it can be seen, the amount of
157 * information provided at the basic level, depends on the platform
158 * (MS COM or XPCOM).
159 */
160class ErrorInfo
161{
162public:
163
164 /**
165 * Constructs a new, "interfaceless" ErrorInfo instance that takes
166 * the error information possibly set on the current thread by an
167 * interface method of some COM component or by the COM subsystem.
168 *
169 * This constructor is useful, for example, after an unsuccessful attempt
170 * to instantiate (create) a component, so there is no any valid interface
171 * pointer available.
172 */
173 explicit ErrorInfo()
174 : mIsBasicAvailable(false),
175 mIsFullAvailable(false),
176 mResultCode(S_OK),
177 m_pNext(NULL)
178 {
179 init();
180 }
181
182 ErrorInfo(IUnknown *pObj, const GUID &aIID)
183 : mIsBasicAvailable(false),
184 mIsFullAvailable(false),
185 mResultCode(S_OK),
186 m_pNext(NULL)
187 {
188 init(pObj, aIID);
189 }
190
191 /** Specialization for the IVirtualBoxErrorInfo smart pointer */
192 ErrorInfo (const ComPtr <IVirtualBoxErrorInfo> &aPtr)
193 : mIsBasicAvailable (false), mIsFullAvailable (false)
194 , mResultCode (S_OK)
195 { init (aPtr); }
196
197 /**
198 * Constructs a new ErrorInfo instance from the IVirtualBoxErrorInfo
199 * interface pointer. If this pointer is not NULL, both #isFullAvailable()
200 * and #isBasicAvailable() will return |true|.
201 *
202 * @param aInfo pointer to the IVirtualBoxErrorInfo interface that
203 * holds error info to be fetched by this instance
204 */
205 ErrorInfo (IVirtualBoxErrorInfo *aInfo)
206 : mIsBasicAvailable (false), mIsFullAvailable (false)
207 , mResultCode (S_OK)
208 { init (aInfo); }
209
210 ErrorInfo(const ErrorInfo &x)
211 {
212 copyFrom(x);
213 }
214
215 virtual ~ErrorInfo()
216 {
217 cleanup();
218 }
219
220 ErrorInfo& operator=(const ErrorInfo& x)
221 {
222 cleanup();
223 copyFrom(x);
224 return *this;
225 }
226
227 /**
228 * Returns whether basic error info is actually available for the current
229 * thread. If the instance was created from an interface pointer that
230 * supports basic error info and successfully provided it, or if it is an
231 * "interfaceless" instance and there is some error info for the current
232 * thread, the returned value will be true.
233 *
234 * See the class description for details about the basic error info level.
235 *
236 * The appropriate methods of this class provide meaningful info only when
237 * this method returns true (otherwise they simply return NULL-like values).
238 */
239 bool isBasicAvailable() const
240 {
241 return mIsBasicAvailable;
242 }
243
244 /**
245 * Returns whether full error info is actually available for the current
246 * thread. If the instance was created from an interface pointer that
247 * supports full error info and successfully provided it, or if it is an
248 * "interfaceless" instance and there is some error info for the current
249 * thread, the returned value will be true.
250 *
251 * See the class description for details about the full error info level.
252 *
253 * The appropriate methods of this class provide meaningful info only when
254 * this method returns true (otherwise they simply return NULL-like values).
255 */
256 bool isFullAvailable() const
257 {
258 return mIsFullAvailable;
259 }
260
261 /**
262 * Returns the COM result code of the failed operation.
263 */
264 HRESULT getResultCode() const
265 {
266 return mResultCode;
267 }
268
269 /**
270 * Returns the IID of the interface that defined the error.
271 */
272 const Guid& getInterfaceID() const
273 {
274 return mInterfaceID;
275 }
276
277 /**
278 * Returns the name of the component that generated the error.
279 */
280 const Bstr& getComponent() const
281 {
282 return mComponent;
283 }
284
285 /**
286 * Returns the textual description of the error.
287 */
288 const Bstr& getText() const
289 {
290 return mText;
291 }
292
293 /**
294 * Returns the next error information object or @c NULL if there is none.
295 */
296 const ErrorInfo* getNext() const
297 {
298 return m_pNext;
299 }
300
301 /**
302 * Returns the name of the interface that defined the error
303 */
304 const Bstr& getInterfaceName() const
305 {
306 return mInterfaceName;
307 }
308
309 /**
310 * Returns the IID of the interface that returned the error.
311 *
312 * This method returns a non-null IID only if the instance was created
313 * using #template <class I> ErrorInfo(I *i) or
314 * template <class I> ErrorInfo(const ComPtr<I> &i) constructor.
315 */
316 const Guid& getCalleeIID() const
317 {
318 return mCalleeIID;
319 }
320
321 /**
322 * Returns the name of the interface that returned the error
323 *
324 * This method returns a non-null name only if the instance was created
325 * using #template <class I> ErrorInfo(I *i) or
326 * template <class I> ErrorInfo(const ComPtr<I> &i) constructor.
327 */
328 const Bstr& getCalleeName() const
329 {
330 return mCalleeName;
331 }
332
333 /**
334 * Resets all collected error information. #isBasicAvailable() and
335 * #isFullAvailable will return @c true after this method is called.
336 */
337 void setNull()
338 {
339 cleanup();
340 }
341
342protected:
343
344 ErrorInfo(bool /* aDummy */)
345 : mIsBasicAvailable(false),
346 mIsFullAvailable(false),
347 mResultCode(S_OK),
348 m_pNext(NULL)
349 { }
350
351 void copyFrom(const ErrorInfo &x);
352 void cleanup();
353
354 void init(bool aKeepObj = false);
355 void init(IUnknown *aUnk, const GUID &aIID, bool aKeepObj = false);
356 void init(IVirtualBoxErrorInfo *aInfo);
357
358 bool mIsBasicAvailable : 1;
359 bool mIsFullAvailable : 1;
360
361 HRESULT mResultCode;
362 Guid mInterfaceID;
363 Bstr mComponent;
364 Bstr mText;
365
366 ErrorInfo *m_pNext;
367
368 Bstr mInterfaceName;
369 Guid mCalleeIID;
370 Bstr mCalleeName;
371
372 ComPtr<IUnknown> mErrorInfo;
373};
374
375/**
376 * A convenience subclass of ErrorInfo that, given an IProgress interface
377 * pointer, reads its errorInfo attribute and uses the returned
378 * IVirtualBoxErrorInfo instance to construct itself.
379 */
380class ProgressErrorInfo : public ErrorInfo
381{
382public:
383
384 /**
385 * Constructs a new instance by fetching error information from the
386 * IProgress interface pointer. If the progress object is not NULL,
387 * its completed attribute is true, resultCode represents a failure,
388 * and the errorInfo attribute returns a valid IVirtualBoxErrorInfo pointer,
389 * both #isFullAvailable() and #isBasicAvailable() will return true.
390 *
391 * @param progress the progress object representing a failed operation
392 */
393 ProgressErrorInfo(IProgress *progress);
394};
395
396/**
397 * A convenience subclass of ErrorInfo that allows to preserve the current
398 * error info. Instances of this class fetch an error info object set on the
399 * current thread and keep a reference to it, which allows to restore it
400 * later using the #restore() method. This is useful to preserve error
401 * information returned by some method for the duration of making another COM
402 * call that may set its own error info and overwrite the existing
403 * one. Preserving and restoring error information makes sense when some
404 * method wants to return error information set by other call as its own
405 * error information while it still needs to make another call before return.
406 *
407 * Instead of calling #restore() explicitly you may let the object destructor
408 * do it for you, if you correctly limit the object's lifetime.
409 *
410 * The usage pattern is:
411 * <code>
412 * rc = foo->method();
413 * if (FAILED(rc))
414 * {
415 * ErrorInfoKeeper eik;
416 * ...
417 * // bar may return error info as well
418 * bar->method();
419 * ...
420 * // no need to call #restore() explicitly here because the eik's
421 * // destructor will restore error info fetched after the failed
422 * // call to foo before returning to the caller
423 * return rc;
424 * }
425 * </code>
426 */
427class ErrorInfoKeeper : public ErrorInfo
428{
429public:
430
431 /**
432 * Constructs a new instance that will fetch the current error info if
433 * @a aIsNull is @c false (by default) or remain uninitialized (null)
434 * otherwise.
435 *
436 * @param aIsNull @c true to prevent fetching error info and leave
437 * the instance uninitialized.
438 */
439 ErrorInfoKeeper(bool aIsNull = false)
440 : ErrorInfo(false), mForgot(aIsNull)
441 {
442 if (!aIsNull)
443 init(true /* aKeepObj */);
444 }
445
446 /**
447 * Destroys this instance and automatically calls #restore() which will
448 * either restore error info fetched by the constructor or do nothing
449 * if #forget() was called before destruction.
450 */
451 ~ErrorInfoKeeper() { if (!mForgot) restore(); }
452
453 /**
454 * Tries to (re-)fetch error info set on the current thread. On success,
455 * the previous error information, if any, will be overwritten with the
456 * new error information. On failure, or if there is no error information
457 * available, this instance will be reset to null.
458 */
459 void fetch()
460 {
461 setNull();
462 mForgot = false;
463 init(true /* aKeepObj */);
464 }
465
466 /**
467 * Restores error info fetched by the constructor and forgets it
468 * afterwards. Does nothing if the error info was forgotten by #forget().
469 *
470 * @return COM result of the restore operation.
471 */
472 HRESULT restore();
473
474 /**
475 * Forgets error info fetched by the constructor to prevent it from
476 * being restored by #restore() or by the destructor.
477 */
478 void forget() { mForgot = true; }
479
480 /**
481 * Forgets error info fetched by the constructor to prevent it from
482 * being restored by #restore() or by the destructor, and returns the
483 * stored error info object to the caller.
484 */
485 ComPtr<IUnknown> takeError() { mForgot = true; return mErrorInfo; }
486
487private:
488
489 bool mForgot : 1;
490};
491
492} /* namespace com */
493
494#endif
495
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette