VirtualBox

source: vbox/trunk/include/VBox/com/errorprint.h@ 103224

Last change on this file since 103224 was 98611, checked in by vboxsync, 22 months ago

VBox/com/errorprint.h: docs update. bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.8 KB
Line 
1/** @file
2 * MS COM / XPCOM Abstraction Layer - Error Reporting.
3 *
4 * Error printing macros using shared functions defined in shared glue code.
5 * Use these CHECK_* macros for efficient error checking around calling COM
6 * methods.
7 */
8
9/*
10 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.virtualbox.org.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, in version 3 of the
18 * License.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses>.
27 *
28 * The contents of this file may alternatively be used under the terms
29 * of the Common Development and Distribution License Version 1.0
30 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
31 * in the VirtualBox distribution, in which case the provisions of the
32 * CDDL are applicable instead of those of the GPL.
33 *
34 * You may elect to license modified versions of this file under the
35 * terms and conditions of either the GPL or the CDDL or both.
36 *
37 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
38 */
39
40#ifndef VBOX_INCLUDED_com_errorprint_h
41#define VBOX_INCLUDED_com_errorprint_h
42#ifndef RT_WITHOUT_PRAGMA_ONCE
43# pragma once
44#endif
45
46#include <VBox/com/ErrorInfo.h>
47
48
49/** @defgroup grp_com_error_reporting Error Reporting
50 * @ingroup grp_com
51 * @{
52 */
53
54namespace com
55{
56
57// shared prototypes; these are defined in shared glue code and are
58// compiled only once for all front-ends
59void GluePrintErrorInfo(const com::ErrorInfo &info);
60void GluePrintErrorContext(const char *pcszContext, const char *pcszSourceFile, uint32_t uLine, bool fWarning = false);
61void GluePrintRCMessage(HRESULT hrc);
62void GlueHandleComError(ComPtr<IUnknown> iface, const char *pcszContext, HRESULT hrc, const char *pcszSourceFile, uint32_t uLine);
63void GlueHandleComErrorNoCtx(ComPtr<IUnknown> iface, HRESULT hrc);
64void GlueHandleComErrorProgress(ComPtr<IProgress> progress, const char *pcszContext, HRESULT hrc,
65 const char *pcszSourceFile, uint32_t uLine);
66
67/**
68 * Extended macro that implements all the other CHECK_ERROR2XXX macros.
69 *
70 * Calls the method of the given interface and checks the return status code.
71 * If the status indicates failure, as much information as possible is reported
72 * about the error, including current source file and line.
73 *
74 * After reporting an error, the statement |stmtError| is executed.
75 *
76 * This macro family is intended for command line tools like VBoxManage, but
77 * could also be handy for debugging.
78 *
79 * @param type For defining @a hrc locally inside the the macro
80 * expansion, pass |HRESULT| otherwise |RT_NOTHING|.
81 * @param hrc Name of the HRESULT variable to assign the result of the
82 * method call to.
83 * @param iface The interface pointer (can be a smart pointer object).
84 * @param method The method to invoke together with the parameters.
85 * @param stmtError Statement to be executed after reporting failures. This
86 * can be a |break| or |return| statement, if so desired.
87 *
88 * @remarks Unlike CHECK_ERROR, CHECK_ERROR_RET and family, this macro family
89 * does not presuppose a |rc| variable but instead either let the user
90 * specify the variable to use or employs a local variable |hrcCheck|
91 * within its own scope.
92 *
93 * @sa CHECK_ERROR2, CHECK_ERROR2I, CHECK_ERROR2_STMT, CHECK_ERROR2I_STMT,
94 * CHECK_ERROR2_BREAK, CHECK_ERROR2I_BREAK, CHECK_ERROR2_RET,
95 * CHECK_ERROR2I_RET
96 */
97#define CHECK_ERROR2_EX(type, hrc, iface, method, stmtError) \
98 if (1) { \
99 type hrc = iface->method; \
100 if (SUCCEEDED(hrc) && !SUCCEEDED_WARNING(hrc)) \
101 { /*likely*/ } \
102 else \
103 { \
104 com::GlueHandleComError(iface, #method, (hrc), __FILE__, __LINE__); \
105 if (!SUCCEEDED_WARNING(hrc)) \
106 { \
107 stmtError; \
108 } \
109 } \
110 } else do { /* nothing */ } while (0)
111
112
113/**
114 * Calls the given method of the given interface and then checks if the return
115 * value (COM result code) indicates a failure. If so, prints the failed
116 * function/line/file, the description of the result code and attempts to
117 * query the extended error information on the current thread (using
118 * com::ErrorInfo) if the interface reports that it supports error information.
119 *
120 * Used by command line tools or for debugging and assumes the |HRESULT hrc|
121 * variable is accessible for assigning in the current scope.
122 * @sa CHECK_ERROR2, CHECK_ERROR2I
123 */
124#define CHECK_ERROR(iface, method) \
125 do { \
126 hrc = iface->method; \
127 if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \
128 com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \
129 } while (0)
130/**
131 * Simplified version of CHECK_ERROR2_EX, no error statement or type necessary.
132 *
133 * @param hrc Name of the HRESULT variable to assign the result of the
134 * method call to.
135 * @param iface The interface pointer (can be a smart pointer object).
136 * @param method The method to invoke together with the parameters.
137 * @sa CHECK_ERROR2I, CHECK_ERROR2_EX
138 */
139#define CHECK_ERROR2(hrc, iface, method) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, (void)1)
140/**
141 * Simplified version of CHECK_ERROR2_EX that uses an internal variable
142 * |hrcCheck| for holding the result and have no error statement.
143 *
144 * @param iface The interface pointer (can be a smart pointer object).
145 * @param method The method to invoke together with the parameters.
146 * @sa CHECK_ERROR2, CHECK_ERROR2_EX
147 */
148#define CHECK_ERROR2I(iface, method) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, (void)1)
149
150
151/**
152 * Same as CHECK_ERROR except that it also executes the statement |stmt| on
153 * failure.
154 * @sa CHECK_ERROR2_STMT, CHECK_ERROR2I_STMT
155 */
156#define CHECK_ERROR_STMT(iface, method, stmt) \
157 do { \
158 hrc = iface->method; \
159 if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \
160 { \
161 com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \
162 if (!SUCCEEDED_WARNING(hrc) \
163 { \
164 stmt; \
165 } \
166 } \
167 } while (0)
168/**
169 * Simplified version of CHECK_ERROR2_EX (no @a hrc type).
170 *
171 * @param hrc Name of the HRESULT variable to assign the result of the
172 * method call to.
173 * @param iface The interface pointer (can be a smart pointer object).
174 * @param method The method to invoke together with the parameters.
175 * @param stmt Statement to be executed after reporting failures.
176 * @sa CHECK_ERROR2I_STMT, CHECK_ERROR2_EX
177 */
178#define CHECK_ERROR2_STMT(hrc, iface, method, stmt) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, stmt)
179/**
180 * Simplified version of CHECK_ERROR2_EX that uses an internal variable
181 * |hrcCheck| for holding the result.
182 *
183 * @param iface The interface pointer (can be a smart pointer object).
184 * @param method The method to invoke together with the parameters.
185 * @param stmt Statement to be executed after reporting failures.
186 * @sa CHECK_ERROR2_STMT, CHECK_ERROR2_EX
187 */
188#define CHECK_ERROR2I_STMT(iface, method, stmt) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, stmt)
189
190
191/**
192 * Does the same as CHECK_ERROR(), but executes the |break| statement on
193 * failure.
194 * @sa CHECK_ERROR2_BREAK, CHECK_ERROR2I_BREAK
195 */
196#ifdef __GNUC__
197# define CHECK_ERROR_BREAK(iface, method) \
198 __extension__ \
199 ({ \
200 hrc = iface->method; \
201 if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \
202 { \
203 com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \
204 if (!SUCCEEDED_WARNING(hrc)) \
205 break; \
206 } \
207 })
208#else
209# define CHECK_ERROR_BREAK(iface, method) \
210 if (1) \
211 { \
212 hrc = iface->method; \
213 if (FAILED(hrc)) \
214 { \
215 com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \
216 if (!SUCCEEDED_WARNING(hrc)) \
217 break; \
218 } \
219 } \
220 else do {} while (0)
221#endif
222/**
223 * Simplified version of CHECK_ERROR2_EX that executes the |break| statement
224 * after error reporting (no @a hrc type).
225 *
226 * @param hrc The result variable (type HRESULT).
227 * @param iface The interface pointer (can be a smart pointer object).
228 * @param method The method to invoke together with the parameters.
229 * @sa CHECK_ERROR2I_BREAK, CHECK_ERROR2_EX
230 */
231#define CHECK_ERROR2_BREAK(hrc, iface, method) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, break)
232/**
233 * Simplified version of CHECK_ERROR2_EX that executes the |break| statement
234 * after error reporting and that uses an internal variable |hrcCheck| for
235 * holding the result.
236 *
237 * @param iface The interface pointer (can be a smart pointer object).
238 * @param method The method to invoke together with the parameters.
239 * @sa CHECK_ERROR2_BREAK, CHECK_ERROR2_EX
240 */
241#define CHECK_ERROR2I_BREAK(iface, method) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, break)
242/**
243 * Simplified version of CHECK_ERROR2_EX that executes the |stmt;break|
244 * statements after error reporting and that uses an internal variable
245 * |hrcCheck| for holding the result.
246 *
247 * @param iface The interface pointer (can be a smart pointer object).
248 * @param method The method to invoke together with the parameters.
249 * @param stmt Statement to be executed after reporting failures.
250 * @sa CHECK_ERROR2_BREAK, CHECK_ERROR2_EX
251 */
252#define CHECK_ERROR2I_BREAK_STMT(iface, method, stmt) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, stmt; break)
253
254
255/**
256 * Does the same as CHECK_ERROR(), but executes the |return ret| statement on
257 * failure.
258 * @sa CHECK_ERROR2_RET, CHECK_ERROR2I_RET
259 */
260#define CHECK_ERROR_RET(iface, method, ret) \
261 do { \
262 hrc = iface->method; \
263 if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \
264 { \
265 com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \
266 if (!SUCCEEDED_WARNING(hrc)) \
267 return (ret); \
268 } \
269 } while (0)
270/**
271 * Simplified version of CHECK_ERROR2_EX that executes the |return (rcRet)|
272 * statement after error reporting.
273 *
274 * @param hrc The result variable (type HRESULT).
275 * @param iface The interface pointer (can be a smart pointer object).
276 * @param method The method to invoke together with the parameters.
277 * @param rcRet What to return on failure.
278 */
279#define CHECK_ERROR2_RET(hrc, iface, method, rcRet) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, return (rcRet))
280/**
281 * Simplified version of CHECK_ERROR2_EX that executes the |return (rcRet)|
282 * statement after error reporting and that uses an internal variable |hrcCheck|
283 * for holding the result.
284 *
285 * @param iface The interface pointer (can be a smart pointer object).
286 * @param method The method to invoke together with the parameters.
287 * @param rcRet What to return on failure. Use |hrcCheck| to return
288 * the status code of the method call.
289 */
290#define CHECK_ERROR2I_RET(iface, method, rcRet) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, return (rcRet))
291
292
293/**
294 * Check the progress object for an error and if there is one print out the
295 * extended error information.
296 * @remarks Requires HRESULT variable named @a rc.
297 */
298#define CHECK_PROGRESS_ERROR(progress, msg) \
299 do { \
300 LONG iRc; \
301 hrc = progress->COMGETTER(ResultCode)(&iRc); \
302 if (FAILED(hrc) || FAILED(iRc)) \
303 { \
304 if (SUCCEEDED(hrc)) hrc = iRc; else iRc = hrc; \
305 RTMsgError msg; \
306 com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \
307 } \
308 } while (0)
309
310/**
311 * Does the same as CHECK_PROGRESS_ERROR(), but executes the |break| statement
312 * on failure.
313 * @remarks Requires HRESULT variable named @a rc.
314 */
315#ifdef __GNUC__
316# define CHECK_PROGRESS_ERROR_BREAK(progress, msg) \
317 __extension__ \
318 ({ \
319 LONG iRc; \
320 hrc = progress->COMGETTER(ResultCode)(&iRc); \
321 if (FAILED(hrc) || FAILED(iRc)) \
322 { \
323 if (SUCCEEDED(hrc)) hrc = iRc; else iRc = hrc; \
324 RTMsgError msg; \
325 com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \
326 break; \
327 } \
328 })
329#else
330# define CHECK_PROGRESS_ERROR_BREAK(progress, msg) \
331 if (1) \
332 { \
333 LONG iRc; \
334 hrc = progress->COMGETTER(ResultCode)(&iRc); \
335 if (FAILED(hrc) || FAILED(iRc)) \
336 { \
337 if (SUCCEEDED(hrc)) hrc = iRc; else iRc = hrc; \
338 RTMsgError msg; \
339 com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \
340 break; \
341 } \
342 } \
343 else do {} while (0)
344#endif
345
346/**
347 * Does the same as CHECK_PROGRESS_ERROR(), but executes the |return ret|
348 * statement on failure.
349 */
350#define CHECK_PROGRESS_ERROR_RET(progress, msg, ret) \
351 do { \
352 LONG iRc; \
353 HRESULT hrcCheck = progress->COMGETTER(ResultCode)(&iRc); \
354 if (SUCCEEDED(hrcCheck) && SUCCEEDED(iRc)) \
355 { /* likely */ } \
356 else \
357 { \
358 RTMsgError msg; \
359 com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, \
360 SUCCEEDED(hrcCheck) ? iRc : hrcCheck, __FILE__, __LINE__); \
361 return (ret); \
362 } \
363 } while (0)
364
365/**
366 * Asserts the given expression is true. When the expression is false, prints
367 * a line containing the failed function/line/file; otherwise does nothing.
368 */
369#define ASSERT(expr) \
370 do { \
371 if (!(expr)) \
372 { \
373 RTPrintf ("[!] ASSERTION FAILED at line %d: %s\n", __LINE__, #expr); \
374 Log (("[!] ASSERTION FAILED at line %d: %s\n", __LINE__, #expr)); \
375 } \
376 } while (0)
377
378
379/**
380 * Does the same as ASSERT(), but executes the |return ret| statement if the
381 * expression to assert is false;
382 * @remarks WARNING! @a expr is evalutated TWICE!
383 */
384#define ASSERT_RET(expr, ret) \
385 do { ASSERT(expr); if (!(expr)) return (ret); } while (0)
386
387/**
388 * Does the same as ASSERT(), but executes the |break| statement if the
389 * expression to assert is false;
390 * @remarks WARNING! @a expr is evalutated TWICE!
391 */
392#define ASSERT_BREAK(expr, ret) \
393 if (1) { ASSERT(expr); if (!(expr)) break; } else do {} while (0)
394
395} /* namespace com */
396
397
398/** @} */
399
400#endif /* !VBOX_INCLUDED_com_errorprint_h */
401
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