VirtualBox

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

Last change on this file since 18145 was 13580, checked in by vboxsync, 16 years ago

Ported s2 branch (r37120:38456).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 11.8 KB
Line 
1/* $Id: SupportErrorInfo.cpp 13580 2008-10-27 14:04:18Z 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 (
101 HRESULT aResultCode, const GUID *aIID,
102 const char *aComponent, const char *aText,
103 bool aWarning, IVirtualBoxErrorInfo *aInfo /*= NULL*/)
104{
105 /* whether multi-error mode is turned on */
106 bool preserve = ((uintptr_t) RTTlsGet (MultiResult::sCounter)) > 0;
107
108 LogRel (("ERROR [COM]: aRC=%#08x aIID={%Vuuid} aComponent={%s} aText={%s} "
109 "aWarning=%RTbool, aInfo=%p, preserve=%RTbool\n",
110 aResultCode, aIID, aComponent, aText, aWarning, aInfo,
111 preserve));
112
113 if (aInfo == NULL)
114 {
115 /* these are mandatory, others -- not */
116 AssertReturn ((!aWarning && FAILED (aResultCode)) ||
117 (aWarning && aResultCode != S_OK),
118 E_FAIL);
119 AssertReturn (aText != NULL, E_FAIL);
120 AssertReturn (*aText != '\0', E_FAIL);
121
122 /* reset the error severity bit if it's a warning */
123 if (aWarning)
124 aResultCode &= ~0x80000000;
125 }
126
127 HRESULT rc = S_OK;
128
129 do
130 {
131 ComPtr <IVirtualBoxErrorInfo> info;
132
133#if !defined (VBOX_WITH_XPCOM)
134
135 ComPtr <IVirtualBoxErrorInfo> curInfo;
136 if (preserve)
137 {
138 /* get the current error info if any */
139 ComPtr <IErrorInfo> err;
140 rc = ::GetErrorInfo (0, err.asOutParam());
141 CheckComRCBreakRC (rc);
142 rc = err.queryInterfaceTo (curInfo.asOutParam());
143 if (FAILED (rc))
144 {
145 /* create a IVirtualBoxErrorInfo wrapper for the native
146 * IErrorInfo object */
147 ComObjPtr <VirtualBoxErrorInfo> wrapper;
148 rc = wrapper.createObject();
149 if (SUCCEEDED (rc))
150 {
151 rc = wrapper->init (err);
152 if (SUCCEEDED (rc))
153 curInfo = wrapper;
154 }
155 }
156 }
157 /* On failure, curInfo will stay null */
158 Assert (SUCCEEDED (rc) || curInfo.isNull());
159
160 /* set the current error info and preserve the previous one if any */
161 if (aInfo != NULL)
162 {
163 if (curInfo.isNull())
164 {
165 info = aInfo;
166 }
167 else
168 {
169 ComObjPtr <VirtualBoxErrorInfoGlue> infoObj;
170 rc = infoObj.createObject();
171 CheckComRCBreakRC (rc);
172
173 rc = infoObj->init (aInfo, curInfo);
174 CheckComRCBreakRC (rc);
175
176 info = infoObj;
177 }
178
179 /* we want to return the head's result code */
180 rc = info->COMGETTER(ResultCode) (&aResultCode);
181 CheckComRCBreakRC (rc);
182 }
183 else
184 {
185 ComObjPtr <VirtualBoxErrorInfo> infoObj;
186 rc = infoObj.createObject();
187 CheckComRCBreakRC (rc);
188
189 rc = infoObj->init (aResultCode, aIID, aComponent, aText, curInfo);
190 CheckComRCBreakRC (rc);
191
192 info = infoObj;
193 }
194
195 ComPtr <IErrorInfo> err;
196 rc = info.queryInterfaceTo (err.asOutParam());
197 if (SUCCEEDED (rc))
198 rc = ::SetErrorInfo (0, err);
199
200#else // !defined (VBOX_WITH_XPCOM)
201
202 nsCOMPtr <nsIExceptionService> es;
203 es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
204 if (NS_SUCCEEDED (rc))
205 {
206 nsCOMPtr <nsIExceptionManager> em;
207 rc = es->GetCurrentExceptionManager (getter_AddRefs (em));
208 CheckComRCBreakRC (rc);
209
210 ComPtr <IVirtualBoxErrorInfo> curInfo;
211 if (preserve)
212 {
213 /* get the current error info if any */
214 ComPtr <nsIException> ex;
215 rc = em->GetCurrentException (ex.asOutParam());
216 CheckComRCBreakRC (rc);
217 rc = ex.queryInterfaceTo (curInfo.asOutParam());
218 if (FAILED (rc))
219 {
220 /* create a IVirtualBoxErrorInfo wrapper for the native
221 * nsIException object */
222 ComObjPtr <VirtualBoxErrorInfo> wrapper;
223 rc = wrapper.createObject();
224 if (SUCCEEDED (rc))
225 {
226 rc = wrapper->init (ex);
227 if (SUCCEEDED (rc))
228 curInfo = wrapper;
229 }
230 }
231 }
232 /* On failure, curInfo will stay null */
233 Assert (SUCCEEDED (rc) || curInfo.isNull());
234
235 /* set the current error info and preserve the previous one if any */
236 if (aInfo != NULL)
237 {
238 if (curInfo.isNull())
239 {
240 info = aInfo;
241 }
242 else
243 {
244 ComObjPtr <VirtualBoxErrorInfoGlue> infoObj;
245 rc = infoObj.createObject();
246 CheckComRCBreakRC (rc);
247
248 rc = infoObj->init (aInfo, curInfo);
249 CheckComRCBreakRC (rc);
250
251 info = infoObj;
252 }
253
254 /* we want to return the head's result code */
255 rc = info->COMGETTER(ResultCode) (&aResultCode);
256 CheckComRCBreakRC (rc);
257 }
258 else
259 {
260 ComObjPtr <VirtualBoxErrorInfo> infoObj;
261 rc = infoObj.createObject();
262 CheckComRCBreakRC (rc);
263
264 rc = infoObj->init (aResultCode, aIID, aComponent, aText, curInfo);
265 CheckComRCBreakRC (rc);
266
267 info = infoObj;
268 }
269
270 ComPtr <nsIException> ex;
271 rc = info.queryInterfaceTo (ex.asOutParam());
272 if (SUCCEEDED (rc))
273 rc = em->SetCurrentException (ex);
274 }
275 else if (rc == NS_ERROR_UNEXPECTED)
276 {
277 /*
278 * It is possible that setError() is being called by the object
279 * after the XPCOM shutdown sequence has been initiated
280 * (for example, when XPCOM releases all instances it internally
281 * references, which can cause object's FinalConstruct() and then
282 * uninit()). In this case, do_GetService() above will return
283 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
284 * set the exception (nobody will be able to read it).
285 */
286 LogWarningFunc (("Will not set an exception because "
287 "nsIExceptionService is not available "
288 "(NS_ERROR_UNEXPECTED). "
289 "XPCOM is being shutdown?\n"));
290 rc = NS_OK;
291 }
292
293#endif // !defined (VBOX_WITH_XPCOM)
294 }
295 while (0);
296
297 AssertComRC (rc);
298
299 return SUCCEEDED (rc) ? aResultCode : rc;
300}
301
302/* static */
303HRESULT SupportErrorInfoBase::setError (HRESULT aResultCode, const GUID &aIID,
304 const char *aComponent, const char *aText,
305 ...)
306{
307 va_list args;
308 va_start (args, aText);
309 HRESULT rc = setErrorV (aResultCode, aIID, aComponent, aText, args);
310 va_end (args);
311 return rc;
312}
313
314/* static */
315HRESULT SupportErrorInfoBase::setWarning (HRESULT aResultCode, const GUID &aIID,
316 const char *aComponent, const char *aText,
317 ...)
318{
319 va_list args;
320 va_start (args, aText);
321 HRESULT rc = setWarningV (aResultCode, aIID, aComponent, aText, args);
322 va_end (args);
323 return rc;
324}
325
326HRESULT SupportErrorInfoBase::setError (HRESULT aResultCode, const char *aText, ...)
327{
328 va_list args;
329 va_start (args, aText);
330 HRESULT rc = setErrorV (aResultCode, mainInterfaceID(), componentName(),
331 aText, args);
332 va_end (args);
333 return rc;
334}
335
336HRESULT SupportErrorInfoBase::setWarning (HRESULT aResultCode, const char *aText, ...)
337{
338 va_list args;
339 va_start (args, aText);
340 HRESULT rc = setWarningV (aResultCode, mainInterfaceID(), componentName(),
341 aText, args);
342 va_end (args);
343 return rc;
344}
345
346HRESULT SupportErrorInfoBase::setError (HRESULT aResultCode, const GUID &aIID,
347 const char *aText, ...)
348{
349 va_list args;
350 va_start (args, aText);
351 HRESULT rc = setErrorV (aResultCode, aIID, componentName(), aText, args);
352 va_end (args);
353 return rc;
354}
355
356HRESULT SupportErrorInfoBase::setWarning (HRESULT aResultCode, const GUID &aIID,
357 const char *aText, ...)
358{
359 va_list args;
360 va_start (args, aText);
361 HRESULT rc = setWarningV (aResultCode, aIID, componentName(), aText, args);
362 va_end (args);
363 return rc;
364}
365
366} /* namespace com */
367
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