VirtualBox

source: vbox/trunk/src/VBox/Main/glue/SupportErrorInfo.cpp@ 25414

Last change on this file since 25414 was 25149, checked in by vboxsync, 15 years ago

Main: cleanup: remove all CheckComRC* macros (no functional change)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 12.3 KB
Line 
1/* $Id: SupportErrorInfo.cpp 25149 2009-12-02 14:34:47Z vboxsync $ */
2
3/** @file
4 * MS COM / XPCOM Abstraction Layer:
5 * SupportErrorInfo* class family implementations
6 */
7
8/*
9 * Copyright (C) 2008 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#include "VBox/com/SupportErrorInfo.h"
25
26#include "VBox/com/ptr.h"
27#include "VBox/com/VirtualBoxErrorInfo.h"
28
29#include "../include/Logging.h"
30
31#include <iprt/thread.h>
32
33#if defined (VBOX_WITH_XPCOM)
34# include <nsIServiceManager.h>
35# include <nsIExceptionService.h>
36#endif /* defined (VBOX_WITH_XPCOM) */
37
38namespace com
39{
40
41// MultiResult methods
42////////////////////////////////////////////////////////////////////////////////
43
44RTTLS MultiResult::sCounter = NIL_RTTLS;
45
46/*static*/
47void MultiResult::incCounter()
48{
49 if (sCounter == NIL_RTTLS)
50 {
51 sCounter = RTTlsAlloc();
52 AssertReturnVoid (sCounter != NIL_RTTLS);
53 }
54
55 uintptr_t counter = (uintptr_t) RTTlsGet (sCounter);
56 ++ counter;
57 RTTlsSet (sCounter, (void *) counter);
58}
59
60/*static*/
61void MultiResult::decCounter()
62{
63 uintptr_t counter = (uintptr_t) RTTlsGet (sCounter);
64 AssertReturnVoid (counter != 0);
65 -- counter;
66 RTTlsSet (sCounter, (void *) counter);
67}
68
69// SupportErrorInfoBase methods
70////////////////////////////////////////////////////////////////////////////////
71
72/**
73 * Sets error info for the current thread. This is an internal function that
74 * gets eventually called by all public setError(), setWarning() and
75 * setErrorInfo() variants.
76 *
77 * The previous error info object (if any) will be preserved if the multi-error
78 * mode (see MultiResult) is turned on for the current thread.
79 *
80 * If @a aWarning is @c true, then the highest (31) bit in the @a aResultCode
81 * value which indicates the error severity is reset to zero to make sure the
82 * receiver will recognize that the created error info object represents a
83 * warning rather than an error.
84 *
85 * If @a aInfo is not NULL then all other paremeters are ignored and the given
86 * error info object is set on the current thread. Note that in this case, the
87 * existing error info object (if any) will be preserved by attaching it to the
88 * tail of the error chain of the given aInfo object in multi-error mode.
89 *
90 * If the error info is successfully set then this method returns aResultCode
91 * (or the result code returned as an output parameter of the
92 * aInfo->GetResultCode() call when @a aInfo is not NULL). This is done for
93 * conveinence: this way, setError() and friends may be used in return
94 * statements of COM method implementations.
95 *
96 * If setting error info fails then this method asserts and the failed result
97 * code is returned.
98 */
99/* static */
100HRESULT SupportErrorInfoBase::setErrorInternal(HRESULT aResultCode,
101 const GUID *aIID,
102 const char *aComponent,
103 const Utf8Str &strText,
104 bool aWarning,
105 IVirtualBoxErrorInfo *aInfo /*= NULL*/)
106{
107 /* whether multi-error mode is turned on */
108 bool preserve = ((uintptr_t) RTTlsGet (MultiResult::sCounter)) > 0;
109
110 LogRel(("ERROR [COM]: aRC=%#08x aIID={%Vuuid} aComponent={%s} aText={%s} aWarning=%RTbool, aInfo=%p, preserve=%RTbool\n",
111 aResultCode,
112 aIID,
113 aComponent,
114 strText.c_str(),
115 aWarning,
116 aInfo,
117 preserve));
118
119 if (aInfo == NULL)
120 {
121 /* these are mandatory, others -- not */
122 AssertReturn((!aWarning && FAILED (aResultCode)) ||
123 (aWarning && aResultCode != S_OK),
124 E_FAIL);
125 AssertReturn(!strText.isEmpty(), E_FAIL);
126
127 /* reset the error severity bit if it's a warning */
128 if (aWarning)
129 aResultCode &= ~0x80000000;
130 }
131
132 HRESULT rc = S_OK;
133
134 do
135 {
136 ComPtr<IVirtualBoxErrorInfo> info;
137
138#if !defined (VBOX_WITH_XPCOM)
139
140 ComPtr<IVirtualBoxErrorInfo> curInfo;
141 if (preserve)
142 {
143 /* get the current error info if any */
144 ComPtr<IErrorInfo> err;
145 rc = ::GetErrorInfo (0, err.asOutParam());
146 if (FAILED(rc)) break;
147 rc = err.queryInterfaceTo(curInfo.asOutParam());
148 if (FAILED (rc))
149 {
150 /* create a IVirtualBoxErrorInfo wrapper for the native
151 * IErrorInfo object */
152 ComObjPtr<VirtualBoxErrorInfo> wrapper;
153 rc = wrapper.createObject();
154 if (SUCCEEDED(rc))
155 {
156 rc = wrapper->init (err);
157 if (SUCCEEDED(rc))
158 curInfo = wrapper;
159 }
160 }
161 }
162 /* On failure, curInfo will stay null */
163 Assert(SUCCEEDED(rc) || curInfo.isNull());
164
165 /* set the current error info and preserve the previous one if any */
166 if (aInfo != NULL)
167 {
168 if (curInfo.isNull())
169 {
170 info = aInfo;
171 }
172 else
173 {
174 ComObjPtr<VirtualBoxErrorInfoGlue> infoObj;
175 rc = infoObj.createObject();
176 if (FAILED(rc)) break;
177
178 rc = infoObj->init (aInfo, curInfo);
179 if (FAILED(rc)) break;
180
181 info = infoObj;
182 }
183
184 /* we want to return the head's result code */
185 rc = info->COMGETTER(ResultCode) (&aResultCode);
186 if (FAILED(rc)) break;
187 }
188 else
189 {
190 ComObjPtr<VirtualBoxErrorInfo> infoObj;
191 rc = infoObj.createObject();
192 if (FAILED(rc)) break;
193
194 rc = infoObj->init (aResultCode, aIID, aComponent, strText.c_str(), curInfo);
195 if (FAILED(rc)) break;
196
197 info = infoObj;
198 }
199
200 ComPtr<IErrorInfo> err;
201 rc = info.queryInterfaceTo(err.asOutParam());
202 if (SUCCEEDED(rc))
203 rc = ::SetErrorInfo (0, err);
204
205#else // !defined (VBOX_WITH_XPCOM)
206
207 nsCOMPtr <nsIExceptionService> es;
208 es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
209 if (NS_SUCCEEDED(rc))
210 {
211 nsCOMPtr <nsIExceptionManager> em;
212 rc = es->GetCurrentExceptionManager (getter_AddRefs (em));
213 if (FAILED(rc)) break;
214
215 ComPtr<IVirtualBoxErrorInfo> curInfo;
216 if (preserve)
217 {
218 /* get the current error info if any */
219 ComPtr<nsIException> ex;
220 rc = em->GetCurrentException (ex.asOutParam());
221 if (FAILED(rc)) break;
222 rc = ex.queryInterfaceTo(curInfo.asOutParam());
223 if (FAILED (rc))
224 {
225 /* create a IVirtualBoxErrorInfo wrapper for the native
226 * nsIException object */
227 ComObjPtr<VirtualBoxErrorInfo> wrapper;
228 rc = wrapper.createObject();
229 if (SUCCEEDED(rc))
230 {
231 rc = wrapper->init (ex);
232 if (SUCCEEDED(rc))
233 curInfo = wrapper;
234 }
235 }
236 }
237 /* On failure, curInfo will stay null */
238 Assert (SUCCEEDED(rc) || curInfo.isNull());
239
240 /* set the current error info and preserve the previous one if any */
241 if (aInfo != NULL)
242 {
243 if (curInfo.isNull())
244 {
245 info = aInfo;
246 }
247 else
248 {
249 ComObjPtr<VirtualBoxErrorInfoGlue> infoObj;
250 rc = infoObj.createObject();
251 if (FAILED(rc)) break;
252
253 rc = infoObj->init (aInfo, curInfo);
254 if (FAILED(rc)) break;
255
256 info = infoObj;
257 }
258
259 /* we want to return the head's result code */
260 PRInt32 lrc;
261 rc = info->COMGETTER(ResultCode) (&lrc); aResultCode = lrc;
262 if (FAILED(rc)) break;
263 }
264 else
265 {
266 ComObjPtr<VirtualBoxErrorInfo> infoObj;
267 rc = infoObj.createObject();
268 if (FAILED(rc)) break;
269
270 rc = infoObj->init(aResultCode, aIID, aComponent, strText, curInfo);
271 if (FAILED(rc)) break;
272
273 info = infoObj;
274 }
275
276 ComPtr<nsIException> ex;
277 rc = info.queryInterfaceTo(ex.asOutParam());
278 if (SUCCEEDED(rc))
279 rc = em->SetCurrentException (ex);
280 }
281 else if (rc == NS_ERROR_UNEXPECTED)
282 {
283 /*
284 * It is possible that setError() is being called by the object
285 * after the XPCOM shutdown sequence has been initiated
286 * (for example, when XPCOM releases all instances it internally
287 * references, which can cause object's FinalConstruct() and then
288 * uninit()). In this case, do_GetService() above will return
289 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
290 * set the exception (nobody will be able to read it).
291 */
292 LogWarningFunc (("Will not set an exception because "
293 "nsIExceptionService is not available "
294 "(NS_ERROR_UNEXPECTED). "
295 "XPCOM is being shutdown?\n"));
296 rc = NS_OK;
297 }
298
299#endif // !defined (VBOX_WITH_XPCOM)
300 }
301 while (0);
302
303 AssertComRC (rc);
304
305 return SUCCEEDED(rc) ? aResultCode : rc;
306}
307
308/* static */
309HRESULT SupportErrorInfoBase::setError (HRESULT aResultCode, const GUID &aIID,
310 const char *aComponent, const char *aText,
311 ...)
312{
313 va_list args;
314 va_start (args, aText);
315 HRESULT rc = setErrorV (aResultCode, aIID, aComponent, aText, args);
316 va_end (args);
317 return rc;
318}
319
320/* static */
321HRESULT SupportErrorInfoBase::setWarning (HRESULT aResultCode, const GUID &aIID,
322 const char *aComponent, const char *aText,
323 ...)
324{
325 va_list args;
326 va_start (args, aText);
327 HRESULT rc = setWarningV (aResultCode, aIID, aComponent, aText, args);
328 va_end (args);
329 return rc;
330}
331
332HRESULT SupportErrorInfoBase::setError (HRESULT aResultCode, const char *aText, ...)
333{
334 va_list args;
335 va_start (args, aText);
336 HRESULT rc = setErrorV (aResultCode, mainInterfaceID(), componentName(),
337 aText, args);
338 va_end (args);
339 return rc;
340}
341
342HRESULT SupportErrorInfoBase::setError (HRESULT aResultCode, const Utf8Str &strText)
343{
344 HRESULT rc = setError(aResultCode,
345 mainInterfaceID(),
346 componentName(),
347 strText);
348 return rc;
349}
350
351HRESULT SupportErrorInfoBase::setWarning (HRESULT aResultCode, const char *aText, ...)
352{
353 va_list args;
354 va_start (args, aText);
355 HRESULT rc = setWarningV (aResultCode, mainInterfaceID(), componentName(),
356 aText, args);
357 va_end (args);
358 return rc;
359}
360
361HRESULT SupportErrorInfoBase::setError (HRESULT aResultCode, const GUID &aIID,
362 const char *aText, ...)
363{
364 va_list args;
365 va_start (args, aText);
366 HRESULT rc = setErrorV (aResultCode, aIID, componentName(), aText, args);
367 va_end (args);
368 return rc;
369}
370
371HRESULT SupportErrorInfoBase::setWarning (HRESULT aResultCode, const GUID &aIID,
372 const char *aText, ...)
373{
374 va_list args;
375 va_start (args, aText);
376 HRESULT rc = setWarningV (aResultCode, aIID, componentName(), aText, args);
377 va_end (args);
378 return rc;
379}
380
381} /* namespace com */
382
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use