VirtualBox

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

Last change on this file since 20598 was 20267, checked in by vboxsync, 16 years ago

Main: completed scriptable changes
Make VBox buildable on SMB share exported by Win box.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 11.9 KB
Line 
1/* $Id: SupportErrorInfo.cpp 20267 2009-06-04 11:27:27Z 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 PRInt32 lrc;
256 rc = info->COMGETTER(ResultCode) (&lrc); aResultCode = lrc;
257 CheckComRCBreakRC (rc);
258 }
259 else
260 {
261 ComObjPtr <VirtualBoxErrorInfo> infoObj;
262 rc = infoObj.createObject();
263 CheckComRCBreakRC (rc);
264
265 rc = infoObj->init (aResultCode, aIID, aComponent, aText, curInfo);
266 CheckComRCBreakRC (rc);
267
268 info = infoObj;
269 }
270
271 ComPtr <nsIException> ex;
272 rc = info.queryInterfaceTo (ex.asOutParam());
273 if (SUCCEEDED (rc))
274 rc = em->SetCurrentException (ex);
275 }
276 else if (rc == NS_ERROR_UNEXPECTED)
277 {
278 /*
279 * It is possible that setError() is being called by the object
280 * after the XPCOM shutdown sequence has been initiated
281 * (for example, when XPCOM releases all instances it internally
282 * references, which can cause object's FinalConstruct() and then
283 * uninit()). In this case, do_GetService() above will return
284 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
285 * set the exception (nobody will be able to read it).
286 */
287 LogWarningFunc (("Will not set an exception because "
288 "nsIExceptionService is not available "
289 "(NS_ERROR_UNEXPECTED). "
290 "XPCOM is being shutdown?\n"));
291 rc = NS_OK;
292 }
293
294#endif // !defined (VBOX_WITH_XPCOM)
295 }
296 while (0);
297
298 AssertComRC (rc);
299
300 return SUCCEEDED (rc) ? aResultCode : rc;
301}
302
303/* static */
304HRESULT SupportErrorInfoBase::setError (HRESULT aResultCode, const GUID &aIID,
305 const char *aComponent, const char *aText,
306 ...)
307{
308 va_list args;
309 va_start (args, aText);
310 HRESULT rc = setErrorV (aResultCode, aIID, aComponent, aText, args);
311 va_end (args);
312 return rc;
313}
314
315/* static */
316HRESULT SupportErrorInfoBase::setWarning (HRESULT aResultCode, const GUID &aIID,
317 const char *aComponent, const char *aText,
318 ...)
319{
320 va_list args;
321 va_start (args, aText);
322 HRESULT rc = setWarningV (aResultCode, aIID, aComponent, aText, args);
323 va_end (args);
324 return rc;
325}
326
327HRESULT SupportErrorInfoBase::setError (HRESULT aResultCode, const char *aText, ...)
328{
329 va_list args;
330 va_start (args, aText);
331 HRESULT rc = setErrorV (aResultCode, mainInterfaceID(), componentName(),
332 aText, args);
333 va_end (args);
334 return rc;
335}
336
337HRESULT SupportErrorInfoBase::setWarning (HRESULT aResultCode, const char *aText, ...)
338{
339 va_list args;
340 va_start (args, aText);
341 HRESULT rc = setWarningV (aResultCode, mainInterfaceID(), componentName(),
342 aText, args);
343 va_end (args);
344 return rc;
345}
346
347HRESULT SupportErrorInfoBase::setError (HRESULT aResultCode, const GUID &aIID,
348 const char *aText, ...)
349{
350 va_list args;
351 va_start (args, aText);
352 HRESULT rc = setErrorV (aResultCode, aIID, componentName(), aText, args);
353 va_end (args);
354 return rc;
355}
356
357HRESULT SupportErrorInfoBase::setWarning (HRESULT aResultCode, const GUID &aIID,
358 const char *aText, ...)
359{
360 va_list args;
361 va_start (args, aText);
362 HRESULT rc = setWarningV (aResultCode, aIID, componentName(), aText, args);
363 va_end (args);
364 return rc;
365}
366
367} /* namespace com */
368
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