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