VirtualBox

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

Last change on this file since 28851 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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