VirtualBox

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

Last change on this file since 87835 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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