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