VirtualBox

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

Last change on this file since 107494 was 107494, checked in by vboxsync, 3 weeks ago

include/VBox/com/ErrorInfo.h: Fixed a warning found by Parfait. jiraref:VBP-1424

  • 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-2024 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 mResultDetail(0),
383 m_pNext(NULL)
384 { }
385
386 void copyFrom(const ErrorInfo &x);
387 void cleanup();
388
389 void init(bool aKeepObj = false);
390 void init(IUnknown *aUnk, const GUID &aIID, bool aKeepObj = false);
391 void init(IVirtualBoxErrorInfo *aInfo);
392
393 bool mIsBasicAvailable : 1;
394 bool mIsFullAvailable : 1;
395
396 HRESULT mResultCode;
397 LONG mResultDetail;
398 Guid mInterfaceID;
399 Bstr mComponent;
400 Bstr mText;
401
402 ErrorInfo *m_pNext;
403
404 Bstr mInterfaceName;
405 Guid mCalleeIID;
406 Bstr mCalleeName;
407
408 ComPtr<IUnknown> mErrorInfo;
409};
410
411/**
412 * A convenience subclass of ErrorInfo that, given an IProgress interface
413 * pointer, reads its errorInfo attribute and uses the returned
414 * IVirtualBoxErrorInfo instance to construct itself.
415 */
416class ProgressErrorInfo : public ErrorInfo
417{
418public:
419
420 /**
421 * Constructs a new instance by fetching error information from the
422 * IProgress interface pointer. If the progress object is not NULL,
423 * its completed attribute is true, resultCode represents a failure,
424 * and the errorInfo attribute returns a valid IVirtualBoxErrorInfo pointer,
425 * both #isFullAvailable() and #isBasicAvailable() will return true.
426 *
427 * @param progress the progress object representing a failed operation
428 */
429 ProgressErrorInfo(IProgress *progress);
430};
431
432/**
433 * A convenience subclass of ErrorInfo that allows to preserve the current
434 * error info. Instances of this class fetch an error info object set on the
435 * current thread and keep a reference to it, which allows to restore it
436 * later using the #restore() method. This is useful to preserve error
437 * information returned by some method for the duration of making another COM
438 * call that may set its own error info and overwrite the existing
439 * one. Preserving and restoring error information makes sense when some
440 * method wants to return error information set by other call as its own
441 * error information while it still needs to make another call before return.
442 *
443 * Instead of calling #restore() explicitly you may let the object destructor
444 * do it for you, if you correctly limit the object's lifetime.
445 *
446 * The usage pattern is:
447 * <code>
448 * rc = foo->method();
449 * if (FAILED(rc))
450 * {
451 * ErrorInfoKeeper eik;
452 * ...
453 * // bar may return error info as well
454 * bar->method();
455 * ...
456 * // no need to call #restore() explicitly here because the eik's
457 * // destructor will restore error info fetched after the failed
458 * // call to foo before returning to the caller
459 * return rc;
460 * }
461 * </code>
462 */
463class ErrorInfoKeeper : public ErrorInfo
464{
465public:
466
467 /**
468 * Constructs a new instance that will fetch the current error info if
469 * @a aIsNull is @c false (by default) or remain uninitialized (null)
470 * otherwise.
471 *
472 * @param aIsNull @c true to prevent fetching error info and leave
473 * the instance uninitialized.
474 */
475 ErrorInfoKeeper(bool aIsNull = false)
476 : ErrorInfo(false), mForgot(aIsNull)
477 {
478 if (!aIsNull)
479 init(true /* aKeepObj */);
480 }
481
482 /**
483 * Constructs a new instance from an ErrorInfo object, to inject a full
484 * error info created elsewhere.
485 *
486 * @param aInfo @c true to prevent fetching error info and leave
487 * the instance uninitialized.
488 */
489 ErrorInfoKeeper(const ErrorInfo &aInfo)
490 : ErrorInfo(false), mForgot(false)
491 {
492 copyFrom(aInfo);
493 }
494
495 /**
496 * Destroys this instance and automatically calls #restore() which will
497 * either restore error info fetched by the constructor or do nothing
498 * if #forget() was called before destruction.
499 */
500 ~ErrorInfoKeeper() { if (!mForgot) restore(); }
501
502 /**
503 * Tries to (re-)fetch error info set on the current thread. On success,
504 * the previous error information, if any, will be overwritten with the
505 * new error information. On failure, or if there is no error information
506 * available, this instance will be reset to null.
507 */
508 void fetch()
509 {
510 setNull();
511 mForgot = false;
512 init(true /* aKeepObj */);
513 }
514
515 /**
516 * Restores error info fetched by the constructor and forgets it
517 * afterwards. Does nothing if the error info was forgotten by #forget().
518 *
519 * @return COM result of the restore operation.
520 */
521 HRESULT restore();
522
523 /**
524 * Forgets error info fetched by the constructor to prevent it from
525 * being restored by #restore() or by the destructor.
526 */
527 void forget() { mForgot = true; }
528
529 /**
530 * Forgets error info fetched by the constructor to prevent it from
531 * being restored by #restore() or by the destructor, and returns the
532 * stored error info object to the caller.
533 */
534 ComPtr<IUnknown> takeError() { mForgot = true; return mErrorInfo; }
535
536private:
537
538 bool mForgot : 1;
539};
540
541} /* namespace com */
542
543/** @} */
544
545#endif /* !VBOX_INCLUDED_com_ErrorInfo_h */
546
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