VirtualBox

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use