VirtualBox

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

Last change on this file was 98288, checked in by vboxsync, 16 months ago

Main/src-server: rc -> hrc/vrc (partial). bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 8.7 KB
Line 
1/* $Id: MultiResult.h 98288 2023-01-24 15:32:43Z vboxsync $ */
2/** @file
3 * MS COM / XPCOM Abstraction Layer - MultiResult class declarations.
4 */
5
6/*
7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37#ifndef VBOX_INCLUDED_com_MultiResult_h
38#define VBOX_INCLUDED_com_MultiResult_h
39#ifndef RT_WITHOUT_PRAGMA_ONCE
40# pragma once
41#endif
42
43#include "VBox/com/defs.h"
44#include "VBox/com/string.h"
45
46#include <stdarg.h>
47
48/** @defgroup grp_com_mr MultiResult Classes
49 * @ingroup grp_com
50 * @{
51 */
52
53namespace com
54{
55
56/**
57 * "First worst" result type.
58 *
59 * Variables of this class are used instead of HRESULT variables when it is
60 * desirable to memorize the "first worst" result code instead of the last
61 * assigned one. In other words, an assignment operation to a variable of this
62 * class will succeed only if the result code to assign has worse severity. The
63 * following table demonstrate this (the first column lists the previous result
64 * code stored in the variable, the first row lists the new result code being
65 * assigned, 'A' means the assignment will take place, '> S_OK' means a warning
66 * result code):
67 *
68 * {{{
69 * FAILED > S_OK S_OK
70 * FAILED - - -
71 * > S_OK A - -
72 * S_OK A A -
73 *
74 * }}}
75 *
76 * In practice, you will need to use a FWResult variable when you call some COM
77 * method B after another COM method A fails and want to return the result code
78 * of A even if B also fails, but want to return the failed result code of B if
79 * A issues a warning or succeeds.
80 */
81class FWResult
82{
83
84public:
85
86 /**
87 * Constructs a new variable. Note that by default this constructor sets the
88 * result code to E_FAIL to make sure a failure is returned to the caller if
89 * the variable is never assigned another value (which is considered as the
90 * improper use of this class).
91 */
92 FWResult (HRESULT aRC = E_FAIL) : mRC (aRC) {}
93
94 FWResult &operator= (HRESULT aRC)
95 {
96 if ((FAILED (aRC) && !FAILED (mRC)) ||
97 (mRC == S_OK && aRC != S_OK))
98 mRC = aRC;
99
100 return *this;
101 }
102
103 operator HRESULT() const { return mRC; }
104
105 HRESULT *operator&() { return &mRC; }
106
107private:
108
109 HRESULT mRC;
110};
111
112/**
113 * The MultiResult class is a com::FWResult enhancement that also acts as a
114 * switch to turn on multi-error mode for VirtualBoxBase::setError() and
115 * VirtualBoxBase::setWarning() calls.
116 *
117 * When an instance of this class is created, multi-error mode is turned on
118 * for the current thread and the turn-on counter is increased by one. In
119 * multi-error mode, a call to setError() or setWarning() does not
120 * overwrite the current error or warning info object possibly set on the
121 * current thread by other method calls, but instead it stores this old
122 * object in the IVirtualBoxErrorInfo::next attribute of the new error
123 * object being set.
124 *
125 * This way, error/warning objects are stacked together and form a chain of
126 * errors where the most recent error is the first one retrieved by the
127 * calling party, the preceding error is what the
128 * IVirtualBoxErrorInfo::next attribute of the first error points to, and so
129 * on, up to the first error or warning occurred which is the last in the
130 * chain. See IVirtualBoxErrorInfo documentation for more info.
131 *
132 * When the instance of the MultiResult class goes out of scope and gets
133 * destroyed, it automatically decreases the turn-on counter by one. If
134 * the counter drops to zero, multi-error mode for the current thread is
135 * turned off and the thread switches back to single-error mode where every
136 * next error or warning object overwrites the previous one.
137 *
138 * Note that the caller of a COM method uses a non-S_OK result code to
139 * decide if the method has returned an error (negative codes) or a warning
140 * (positive non-zero codes) and will query extended error info only in
141 * these two cases. However, since multi-error mode implies that the method
142 * doesn't return control return to the caller immediately after the first
143 * error or warning but continues its execution, the functionality provided
144 * by the base com::FWResult class becomes very useful because it allows to
145 * preserve the error or the warning result code even if it is later assigned
146 * a S_OK value multiple times. See com::FWResult for details.
147 *
148 * Here is the typical usage pattern:
149 * @code
150 HRESULT Bar::method()
151 {
152 // assume multi-errors are turned off here...
153
154 if (something)
155 {
156 // Turn on multi-error mode and make sure severity is preserved
157 MultiResult rc = foo->method1();
158
159 // return on fatal error, but continue on warning or on success
160 CheckComRCReturnRC (rc);
161
162 rc = foo->method2();
163 // no matter what result, stack it and continue
164
165 // ...
166
167 // return the last worst result code (it will be preserved even if
168 // foo->method2() returns S_OK.
169 return rc;
170 }
171
172 // multi-errors are turned off here again...
173
174 return S_OK;
175 }
176 * @endcode
177 *
178 * @note This class is intended to be instantiated on the stack, therefore
179 * You cannot create them using new(). Although it is possible to copy
180 * instances of MultiResult or return them by value, please never do
181 * that as it is breaks the class semantics (and will assert);
182 */
183class MultiResult : public FWResult
184{
185public:
186
187 /**
188 * @copydoc FWResult::FWResult()
189 */
190 MultiResult(HRESULT aRC = E_FAIL) : FWResult (aRC) { incCounter(); }
191
192 MultiResult(const MultiResult &aThat) : FWResult (aThat)
193 {
194 /* We need this copy constructor only for GCC that wants to have
195 * it in case of expressions like |MultiResult rc = E_FAIL;|. But
196 * we assert since the optimizer should actually avoid the
197 * temporary and call the other constructor directly instead. */
198 AssertFailed();
199 }
200
201 ~MultiResult() { decCounter(); }
202
203 MultiResult &operator= (HRESULT aRC)
204 {
205 FWResult::operator= (aRC);
206 return *this;
207 }
208
209 MultiResult &operator= (const MultiResult & /* aThat */)
210 {
211 /* We need this copy constructor only for GCC that wants to have
212 * it in case of expressions like |MultiResult rc = E_FAIL;|. But
213 * we assert since the optimizer should actually avoid the
214 * temporary and call the other constructor directly instead. */
215 AssertFailed();
216 return *this;
217 }
218
219 /**
220 * Returns true if multi-mode is enabled for the current thread (i.e. at
221 * least one MultiResult instance exists on the stack somewhere).
222 * @return
223 */
224 static bool isMultiEnabled();
225
226private:
227
228 DECLARE_CLS_NEW_DELETE_NOOP(MultiResult);
229
230 static void incCounter();
231 static void decCounter();
232
233 static RTTLS sCounter;
234
235 friend class MultiResultRef;
236};
237
238/**
239 * The MultiResultRef class is equivalent to MultiResult except that it takes
240 * a reference to the existing HRESULT variable instead of maintaining its own
241 * one.
242 */
243class MultiResultRef
244{
245public:
246
247 MultiResultRef (HRESULT &aRC) : mRC (aRC) { MultiResult::incCounter(); }
248
249 ~MultiResultRef() { MultiResult::decCounter(); }
250
251 MultiResultRef &operator= (HRESULT aRC)
252 {
253 /* Copied from FWResult */
254 if ((FAILED (aRC) && !FAILED (mRC)) ||
255 (mRC == S_OK && aRC != S_OK))
256 mRC = aRC;
257
258 return *this;
259 }
260
261 operator HRESULT() const { return mRC; }
262
263 HRESULT *operator&() { return &mRC; }
264
265private:
266
267 DECLARE_CLS_NEW_DELETE_NOOP(MultiResultRef);
268
269 HRESULT &mRC;
270};
271
272
273} /* namespace com */
274
275/** @} */
276
277#endif /* !VBOX_INCLUDED_com_MultiResult_h */
278
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use