VirtualBox

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

Last change on this file since 73768 was 69107, checked in by vboxsync, 7 years ago

include/VBox/: (C) year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use