xref: /reactos/dll/win32/ole32/errorinfo.c (revision 845faec4)
1 /*
2  * ErrorInfo API
3  *
4  * Copyright 2000 Patrik Stridvall, Juergen Schmied
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * NOTES:
21  *
22  * The errorinfo is a per-thread object. The reference is stored in the
23  * TEB at offset 0xf80.
24  */
25 
26 #include <stdarg.h>
27 #include <string.h>
28 
29 #define COBJMACROS
30 
31 #include "windef.h"
32 #include "winbase.h"
33 #include "objbase.h"
34 #include "oleauto.h"
35 #include "winerror.h"
36 
37 #include "wine/unicode.h"
38 #include "compobj_private.h"
39 
40 #include "wine/debug.h"
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(ole);
43 
44 static inline WCHAR *heap_strdupW(const WCHAR *str)
45 {
46     WCHAR *ret = NULL;
47 
48     if(str) {
49         size_t size;
50 
51         size = (strlenW(str)+1)*sizeof(WCHAR);
52         ret = heap_alloc(size);
53         if(ret)
54             memcpy(ret, str, size);
55     }
56 
57     return ret;
58 }
59 
60 typedef struct ErrorInfoImpl
61 {
62     IErrorInfo IErrorInfo_iface;
63     ICreateErrorInfo ICreateErrorInfo_iface;
64     ISupportErrorInfo ISupportErrorInfo_iface;
65     LONG ref;
66 
67     GUID m_Guid;
68     WCHAR *source;
69     WCHAR *description;
70     WCHAR *help_file;
71     DWORD m_dwHelpContext;
72 } ErrorInfoImpl;
73 
74 static inline ErrorInfoImpl *impl_from_IErrorInfo( IErrorInfo *iface )
75 {
76     return CONTAINING_RECORD(iface, ErrorInfoImpl, IErrorInfo_iface);
77 }
78 
79 static inline ErrorInfoImpl *impl_from_ICreateErrorInfo( ICreateErrorInfo *iface )
80 {
81     return CONTAINING_RECORD(iface, ErrorInfoImpl, ICreateErrorInfo_iface);
82 }
83 
84 static inline ErrorInfoImpl *impl_from_ISupportErrorInfo( ISupportErrorInfo *iface )
85 {
86     return CONTAINING_RECORD(iface, ErrorInfoImpl, ISupportErrorInfo_iface);
87 }
88 
89 static HRESULT WINAPI IErrorInfoImpl_QueryInterface(
90 	IErrorInfo* iface,
91 	REFIID     riid,
92 	void**     ppvoid)
93 {
94 	ErrorInfoImpl *This = impl_from_IErrorInfo(iface);
95 	TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid),ppvoid);
96 
97 	*ppvoid = NULL;
98 
99 	if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IErrorInfo))
100 	{
101 	  *ppvoid = &This->IErrorInfo_iface;
102 	}
103 	else if(IsEqualIID(riid, &IID_ICreateErrorInfo))
104 	{
105 	  *ppvoid = &This->ICreateErrorInfo_iface;
106 	}
107 	else if(IsEqualIID(riid, &IID_ISupportErrorInfo))
108 	{
109 	  *ppvoid = &This->ISupportErrorInfo_iface;
110 	}
111 
112 	if(*ppvoid)
113 	{
114 	  IUnknown_AddRef( (IUnknown*)*ppvoid );
115 	  TRACE("-- Interface: (%p)->(%p)\n",ppvoid,*ppvoid);
116 	  return S_OK;
117 	}
118 	TRACE("-- Interface: E_NOINTERFACE\n");
119 	return E_NOINTERFACE;
120 }
121 
122 static ULONG WINAPI IErrorInfoImpl_AddRef(
123  	IErrorInfo* iface)
124 {
125 	ErrorInfoImpl *This = impl_from_IErrorInfo(iface);
126 	TRACE("(%p)->(count=%u)\n",This,This->ref);
127 	return InterlockedIncrement(&This->ref);
128 }
129 
130 static ULONG WINAPI IErrorInfoImpl_Release(
131 	IErrorInfo* iface)
132 {
133 	ErrorInfoImpl *This = impl_from_IErrorInfo(iface);
134         ULONG ref = InterlockedDecrement(&This->ref);
135 
136 	TRACE("(%p)->(count=%u)\n",This,ref+1);
137 
138 	if (!ref)
139 	{
140 	  TRACE("-- destroying IErrorInfo(%p)\n",This);
141 
142           heap_free(This->source);
143           heap_free(This->description);
144           heap_free(This->help_file);
145           heap_free(This);
146 	}
147 	return ref;
148 }
149 
150 static HRESULT WINAPI IErrorInfoImpl_GetGUID(
151 	IErrorInfo* iface,
152 	GUID * pGUID)
153 {
154 	ErrorInfoImpl *This = impl_from_IErrorInfo(iface);
155 	TRACE("(%p)->(count=%u)\n",This,This->ref);
156 	if(!pGUID )return E_INVALIDARG;
157 	*pGUID = This->m_Guid;
158 	return S_OK;
159 }
160 
161 static HRESULT WINAPI IErrorInfoImpl_GetSource(
162 	IErrorInfo* iface,
163 	BSTR *pBstrSource)
164 {
165 	ErrorInfoImpl *This = impl_from_IErrorInfo(iface);
166 	TRACE("(%p)->(pBstrSource=%p)\n",This,pBstrSource);
167 	if (pBstrSource == NULL)
168 	    return E_INVALIDARG;
169 	*pBstrSource = SysAllocString(This->source);
170 	return S_OK;
171 }
172 
173 static HRESULT WINAPI IErrorInfoImpl_GetDescription(
174 	IErrorInfo* iface,
175 	BSTR *pBstrDescription)
176 {
177 	ErrorInfoImpl *This = impl_from_IErrorInfo(iface);
178 
179 	TRACE("(%p)->(pBstrDescription=%p)\n",This,pBstrDescription);
180 	if (pBstrDescription == NULL)
181 	    return E_INVALIDARG;
182 	*pBstrDescription = SysAllocString(This->description);
183 
184 	return S_OK;
185 }
186 
187 static HRESULT WINAPI IErrorInfoImpl_GetHelpFile(
188 	IErrorInfo* iface,
189 	BSTR *pBstrHelpFile)
190 {
191 	ErrorInfoImpl *This = impl_from_IErrorInfo(iface);
192 
193 	TRACE("(%p)->(pBstrHelpFile=%p)\n",This, pBstrHelpFile);
194 	if (pBstrHelpFile == NULL)
195 	    return E_INVALIDARG;
196 	*pBstrHelpFile = SysAllocString(This->help_file);
197 
198 	return S_OK;
199 }
200 
201 static HRESULT WINAPI IErrorInfoImpl_GetHelpContext(
202 	IErrorInfo* iface,
203 	DWORD *pdwHelpContext)
204 {
205 	ErrorInfoImpl *This = impl_from_IErrorInfo(iface);
206 	TRACE("(%p)->(pdwHelpContext=%p)\n",This, pdwHelpContext);
207 	if (pdwHelpContext == NULL)
208 	    return E_INVALIDARG;
209 	*pdwHelpContext = This->m_dwHelpContext;
210 
211 	return S_OK;
212 }
213 
214 static const IErrorInfoVtbl ErrorInfoVtbl =
215 {
216   IErrorInfoImpl_QueryInterface,
217   IErrorInfoImpl_AddRef,
218   IErrorInfoImpl_Release,
219   IErrorInfoImpl_GetGUID,
220   IErrorInfoImpl_GetSource,
221   IErrorInfoImpl_GetDescription,
222   IErrorInfoImpl_GetHelpFile,
223   IErrorInfoImpl_GetHelpContext
224 };
225 
226 
227 static HRESULT WINAPI ICreateErrorInfoImpl_QueryInterface(
228 	ICreateErrorInfo* iface,
229 	REFIID     riid,
230 	VOID**     ppvoid)
231 {
232     ErrorInfoImpl *This = impl_from_ICreateErrorInfo(iface);
233     return IErrorInfo_QueryInterface(&This->IErrorInfo_iface, riid, ppvoid);
234 }
235 
236 static ULONG WINAPI ICreateErrorInfoImpl_AddRef(
237  	ICreateErrorInfo* iface)
238 {
239     ErrorInfoImpl *This = impl_from_ICreateErrorInfo(iface);
240     return IErrorInfo_AddRef(&This->IErrorInfo_iface);
241 }
242 
243 static ULONG WINAPI ICreateErrorInfoImpl_Release(
244 	ICreateErrorInfo* iface)
245 {
246     ErrorInfoImpl *This = impl_from_ICreateErrorInfo(iface);
247     return IErrorInfo_Release(&This->IErrorInfo_iface);
248 }
249 
250 
251 static HRESULT WINAPI ICreateErrorInfoImpl_SetGUID(
252 	ICreateErrorInfo* iface,
253 	REFGUID rguid)
254 {
255 	ErrorInfoImpl *This = impl_from_ICreateErrorInfo(iface);
256 	TRACE("(%p)->(%s)\n", This, debugstr_guid(rguid));
257 	This->m_Guid = *rguid;
258 	return S_OK;
259 }
260 
261 static HRESULT WINAPI ICreateErrorInfoImpl_SetSource(
262 	ICreateErrorInfo* iface,
263 	LPOLESTR szSource)
264 {
265 	ErrorInfoImpl *This = impl_from_ICreateErrorInfo(iface);
266 	TRACE("(%p): %s\n",This, debugstr_w(szSource));
267 
268 	heap_free(This->source);
269 	This->source = heap_strdupW(szSource);
270 
271 	return S_OK;
272 }
273 
274 static HRESULT WINAPI ICreateErrorInfoImpl_SetDescription(
275 	ICreateErrorInfo* iface,
276 	LPOLESTR szDescription)
277 {
278 	ErrorInfoImpl *This = impl_from_ICreateErrorInfo(iface);
279 	TRACE("(%p): %s\n",This, debugstr_w(szDescription));
280 
281 	heap_free(This->description);
282 	This->description = heap_strdupW(szDescription);
283 	return S_OK;
284 }
285 
286 static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpFile(
287 	ICreateErrorInfo* iface,
288 	LPOLESTR szHelpFile)
289 {
290 	ErrorInfoImpl *This = impl_from_ICreateErrorInfo(iface);
291 	TRACE("(%p,%s)\n",This,debugstr_w(szHelpFile));
292 	heap_free(This->help_file);
293 	This->help_file = heap_strdupW(szHelpFile);
294 	return S_OK;
295 }
296 
297 static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpContext(
298 	ICreateErrorInfo* iface,
299  	DWORD dwHelpContext)
300 {
301 	ErrorInfoImpl *This = impl_from_ICreateErrorInfo(iface);
302 	TRACE("(%p,%d)\n",This,dwHelpContext);
303 	This->m_dwHelpContext = dwHelpContext;
304 	return S_OK;
305 }
306 
307 static const ICreateErrorInfoVtbl CreateErrorInfoVtbl =
308 {
309   ICreateErrorInfoImpl_QueryInterface,
310   ICreateErrorInfoImpl_AddRef,
311   ICreateErrorInfoImpl_Release,
312   ICreateErrorInfoImpl_SetGUID,
313   ICreateErrorInfoImpl_SetSource,
314   ICreateErrorInfoImpl_SetDescription,
315   ICreateErrorInfoImpl_SetHelpFile,
316   ICreateErrorInfoImpl_SetHelpContext
317 };
318 
319 static HRESULT WINAPI ISupportErrorInfoImpl_QueryInterface(
320 	ISupportErrorInfo* iface,
321 	REFIID     riid,
322 	VOID**     ppvoid)
323 {
324     ErrorInfoImpl *This = impl_from_ISupportErrorInfo(iface);
325     return IErrorInfo_QueryInterface(&This->IErrorInfo_iface, riid, ppvoid);
326 }
327 
328 static ULONG WINAPI ISupportErrorInfoImpl_AddRef(ISupportErrorInfo* iface)
329 {
330     ErrorInfoImpl *This = impl_from_ISupportErrorInfo(iface);
331     return IErrorInfo_AddRef(&This->IErrorInfo_iface);
332 }
333 
334 static ULONG WINAPI ISupportErrorInfoImpl_Release(ISupportErrorInfo* iface)
335 {
336     ErrorInfoImpl *This = impl_from_ISupportErrorInfo(iface);
337     return IErrorInfo_Release(&This->IErrorInfo_iface);
338 }
339 
340 static HRESULT WINAPI ISupportErrorInfoImpl_InterfaceSupportsErrorInfo(
341 	ISupportErrorInfo* iface,
342 	REFIID riid)
343 {
344 	ErrorInfoImpl *This = impl_from_ISupportErrorInfo(iface);
345 	TRACE("(%p)->(%s)\n", This, debugstr_guid(riid));
346 	return (IsEqualIID(riid, &This->m_Guid)) ? S_OK : S_FALSE;
347 }
348 
349 static const ISupportErrorInfoVtbl SupportErrorInfoVtbl =
350 {
351   ISupportErrorInfoImpl_QueryInterface,
352   ISupportErrorInfoImpl_AddRef,
353   ISupportErrorInfoImpl_Release,
354   ISupportErrorInfoImpl_InterfaceSupportsErrorInfo
355 };
356 
357 static IErrorInfo* IErrorInfoImpl_Constructor(void)
358 {
359     ErrorInfoImpl *This = heap_alloc(sizeof(ErrorInfoImpl));
360 
361     if (!This) return NULL;
362 
363     This->IErrorInfo_iface.lpVtbl = &ErrorInfoVtbl;
364     This->ICreateErrorInfo_iface.lpVtbl = &CreateErrorInfoVtbl;
365     This->ISupportErrorInfo_iface.lpVtbl = &SupportErrorInfoVtbl;
366     This->ref = 1;
367     This->source = NULL;
368     This->description = NULL;
369     This->help_file = NULL;
370     This->m_dwHelpContext = 0;
371 
372     return &This->IErrorInfo_iface;
373 }
374 
375 /***********************************************************************
376  *		CreateErrorInfo (OLE32.@)
377  *
378  * Creates an object used to set details for an error info object.
379  *
380  * PARAMS
381  *  pperrinfo [O]. Address where error info creation object will be stored.
382  *
383  * RETURNS
384  *  Success: S_OK.
385  *  Failure: HRESULT code.
386  */
387 HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo)
388 {
389 	IErrorInfo * pei;
390 	HRESULT res;
391 	TRACE("(%p)\n", pperrinfo);
392 	if(! pperrinfo ) return E_INVALIDARG;
393 	if(!(pei=IErrorInfoImpl_Constructor()))return E_OUTOFMEMORY;
394 
395 	res = IErrorInfo_QueryInterface(pei, &IID_ICreateErrorInfo, (LPVOID*)pperrinfo);
396 	IErrorInfo_Release(pei);
397 	return res;
398 }
399 
400 /***********************************************************************
401  *		GetErrorInfo (OLE32.@)
402  *
403  * Retrieves the error information object for the current thread.
404  *
405  * PARAMS
406  *  dwReserved [I]. Reserved. Must be zero.
407  *  pperrinfo  [O]. Address where error information object will be stored on return.
408  *
409  * RETURNS
410  *  Success: S_OK if an error information object was set for the current thread.
411  *           S_FALSE if otherwise.
412  *  Failure: E_INVALIDARG if dwReserved is not zero.
413  *
414  * NOTES
415  *  This function causes the current error info object for the thread to be
416  *  cleared if one was set beforehand.
417  */
418 HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo)
419 {
420 	TRACE("(%d, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->errorinfo);
421 
422 	if (dwReserved)
423 	{
424 		ERR("dwReserved (0x%x) != 0\n", dwReserved);
425 		return E_INVALIDARG;
426 	}
427 
428 	if(!pperrinfo) return E_INVALIDARG;
429 
430 	if (!COM_CurrentInfo()->errorinfo)
431 	{
432 	   *pperrinfo = NULL;
433 	   return S_FALSE;
434 	}
435 
436 	*pperrinfo = COM_CurrentInfo()->errorinfo;
437 
438 	/* clear thread error state */
439 	COM_CurrentInfo()->errorinfo = NULL;
440 	return S_OK;
441 }
442 
443 /***********************************************************************
444  *		SetErrorInfo (OLE32.@)
445  *
446  * Sets the error information object for the current thread.
447  *
448  * PARAMS
449  *  dwReserved [I] Reserved. Must be zero.
450  *  perrinfo   [I] Error info object.
451  *
452  * RETURNS
453  *  Success: S_OK.
454  *  Failure: E_INVALIDARG if dwReserved is not zero.
455  */
456 HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo)
457 {
458 	IErrorInfo * pei;
459 
460 	TRACE("(%d, %p)\n", dwReserved, perrinfo);
461 
462 	if (dwReserved)
463 	{
464 		ERR("dwReserved (0x%x) != 0\n", dwReserved);
465 		return E_INVALIDARG;
466 	}
467 
468 	/* release old errorinfo */
469 	pei = COM_CurrentInfo()->errorinfo;
470 	if (pei) IErrorInfo_Release(pei);
471 
472 	/* set to new value */
473 	COM_CurrentInfo()->errorinfo = perrinfo;
474 	if (perrinfo) IErrorInfo_AddRef(perrinfo);
475 
476 	return S_OK;
477 }
478