Remember (do not reset) font size and style parameters in the initial
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 #include "windef.h"
30 #include "winbase.h"
31 #include "oleauto.h"
32 #include "winerror.h"
33
34 #include "objbase.h"
35 #include "wine/unicode.h"
36 #include "compobj_private.h"
37
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(ole);
41
42 /* this code is from SysAllocStringLen (ole2disp.c in oleaut32) */
43 static BSTR WINAPI ERRORINFO_SysAllocString(const OLECHAR* in)
44 {
45     DWORD  bufferSize;
46     DWORD* newBuffer;
47     WCHAR* stringBuffer;
48     DWORD len;
49
50     if (in == NULL)
51         return NULL;
52     /*
53      * Find the lenth of the buffer passed-in in bytes.
54      */
55     len = strlenW(in);
56     bufferSize = len * sizeof (WCHAR);
57
58     /*
59      * Allocate a new buffer to hold the string.
60      * dont't forget to keep an empty spot at the beginning of the
61      * buffer for the character count and an extra character at the
62      * end for the '\0'.
63      */
64     newBuffer = (DWORD*)HeapAlloc(GetProcessHeap(),
65                                  0,
66                                  bufferSize + sizeof(WCHAR) + sizeof(DWORD));
67
68     /*
69      * If the memory allocation failed, return a null pointer.
70      */
71     if (newBuffer==0)
72       return 0;
73
74     /*
75      * Copy the length of the string in the placeholder.
76      */
77     *newBuffer = bufferSize;
78
79     /*
80      * Skip the byte count.
81      */
82     newBuffer++;
83
84     /*
85      * Copy the information in the buffer.
86      * Since it is valid to pass a NULL pointer here, we'll initialize the
87      * buffer to nul if it is the case.
88      */
89     if (in != 0)
90       memcpy(newBuffer, in, bufferSize);
91     else
92       memset(newBuffer, 0, bufferSize);
93
94     /*
95      * Make sure that there is a nul character at the end of the
96      * string.
97      */
98     stringBuffer = (WCHAR*)newBuffer;
99     stringBuffer[len] = 0;
100
101     return (LPWSTR)stringBuffer;
102 }
103
104 /* this code is from SysFreeString (ole2disp.c in oleaut32)*/
105 static VOID WINAPI ERRORINFO_SysFreeString(BSTR in)
106 {
107     DWORD* bufferPointer;
108
109     /* NULL is a valid parameter */
110     if(!in) return;
111
112     /*
113      * We have to be careful when we free a BSTR pointer, it points to
114      * the beginning of the string but it skips the byte count contained
115      * before the string.
116      */
117     bufferPointer = (DWORD*)in;
118
119     bufferPointer--;
120
121     /*
122      * Free the memory from it's "real" origin.
123      */
124     HeapFree(GetProcessHeap(), 0, bufferPointer);
125 }
126
127
128 typedef struct ErrorInfoImpl
129 {
130         ICOM_VTABLE(IErrorInfo)         *lpvtei;
131         ICOM_VTABLE(ICreateErrorInfo)   *lpvtcei;
132         ICOM_VTABLE(ISupportErrorInfo)  *lpvtsei;
133         DWORD                           ref;
134
135         GUID m_Guid;
136         BSTR bstrSource;
137         BSTR bstrDescription;
138         BSTR bstrHelpFile;
139         DWORD m_dwHelpContext;
140 } ErrorInfoImpl;
141
142 static ICOM_VTABLE(IErrorInfo)          IErrorInfoImpl_VTable;
143 static ICOM_VTABLE(ICreateErrorInfo)    ICreateErrorInfoImpl_VTable;
144 static ICOM_VTABLE(ISupportErrorInfo)   ISupportErrorInfoImpl_VTable;
145
146 /*
147  converts a objectpointer to This
148  */
149 #define _IErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtei)))
150 #define _ICOM_THIS_From_IErrorInfo(class, name) class* This = (class*)(((char*)name)-_IErrorInfo_Offset);
151
152 #define _ICreateErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtcei)))
153 #define _ICOM_THIS_From_ICreateErrorInfo(class, name) class* This = (class*)(((char*)name)-_ICreateErrorInfo_Offset);
154
155 #define _ISupportErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtsei)))
156 #define _ICOM_THIS_From_ISupportErrorInfo(class, name) class* This = (class*)(((char*)name)-_ISupportErrorInfo_Offset);
157
158 /*
159  converts This to a objectpointer
160  */
161 #define _IErrorInfo_(This)              (IErrorInfo*)&(This->lpvtei)
162 #define _ICreateErrorInfo_(This)        (ICreateErrorInfo*)&(This->lpvtcei)
163 #define _ISupportErrorInfo_(This)       (ISupportErrorInfo*)&(This->lpvtsei)
164
165 IErrorInfo * IErrorInfoImpl_Constructor()
166 {
167         ErrorInfoImpl * ei = HeapAlloc(GetProcessHeap(), 0, sizeof(ErrorInfoImpl));
168         if (ei)
169         {
170           ei->lpvtei = &IErrorInfoImpl_VTable;
171           ei->lpvtcei = &ICreateErrorInfoImpl_VTable;
172           ei->lpvtsei = &ISupportErrorInfoImpl_VTable;
173           ei->ref = 1;
174           ei->bstrSource = NULL;
175           ei->bstrDescription = NULL;
176           ei->bstrHelpFile = NULL;
177           ei->m_dwHelpContext = 0;
178         }
179         return (IErrorInfo *)ei;
180 }
181
182
183 static HRESULT WINAPI IErrorInfoImpl_QueryInterface(
184         IErrorInfo* iface,
185         REFIID     riid,
186         VOID**     ppvoid)
187 {
188         _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface);
189         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvoid);
190
191         *ppvoid = NULL;
192
193         if(IsEqualIID(riid, &IID_IErrorInfo))
194         {
195           *ppvoid = _IErrorInfo_(This);
196         }
197         else if(IsEqualIID(riid, &IID_ICreateErrorInfo))
198         {
199           *ppvoid = _ICreateErrorInfo_(This);
200         }
201         else if(IsEqualIID(riid, &IID_ISupportErrorInfo))
202         {
203           *ppvoid = _ISupportErrorInfo_(This);
204         }
205
206         if(*ppvoid)
207         {
208           IUnknown_AddRef( (IUnknown*)*ppvoid );
209           TRACE("-- Interface: (%p)->(%p)\n",ppvoid,*ppvoid);
210           return S_OK;
211         }
212         TRACE("-- Interface: E_NOINTERFACE\n");
213         return E_NOINTERFACE;
214 }
215
216 static ULONG WINAPI IErrorInfoImpl_AddRef(
217         IErrorInfo* iface)
218 {
219         _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface);
220         TRACE("(%p)->(count=%lu)\n",This,This->ref);
221         return InterlockedIncrement(&This->ref);
222 }
223
224 static ULONG WINAPI IErrorInfoImpl_Release(
225         IErrorInfo* iface)
226 {
227         _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface);
228         TRACE("(%p)->(count=%lu)\n",This,This->ref);
229
230         if (!InterlockedDecrement(&This->ref))
231         {
232           TRACE("-- destroying IErrorInfo(%p)\n",This);
233           HeapFree(GetProcessHeap(),0,This);
234           return 0;
235         }
236         return This->ref;
237 }
238
239 static HRESULT WINAPI IErrorInfoImpl_GetGUID(
240         IErrorInfo* iface,
241         GUID * pGUID)
242 {
243         _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface);
244         TRACE("(%p)->(count=%lu)\n",This,This->ref);
245         if(!pGUID )return E_INVALIDARG;
246         memcpy(pGUID, &This->m_Guid, sizeof(GUID));
247         return S_OK;
248 }
249
250 static HRESULT WINAPI IErrorInfoImpl_GetSource(
251         IErrorInfo* iface,
252         BSTR *pBstrSource)
253 {
254         _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface);
255         TRACE("(%p)->(pBstrSource=%p)\n",This,pBstrSource);
256         if (pBstrSource == NULL)
257             return E_INVALIDARG;
258         *pBstrSource = ERRORINFO_SysAllocString(This->bstrSource);
259         return S_OK;
260 }
261
262 static HRESULT WINAPI IErrorInfoImpl_GetDescription(
263         IErrorInfo* iface,
264         BSTR *pBstrDescription)
265 {
266         _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface);
267
268         TRACE("(%p)->(pBstrDescription=%p)\n",This,pBstrDescription);
269         if (pBstrDescription == NULL)
270             return E_INVALIDARG;
271         *pBstrDescription = ERRORINFO_SysAllocString(This->bstrDescription);
272
273         return S_OK;
274 }
275
276 static HRESULT WINAPI IErrorInfoImpl_GetHelpFile(
277         IErrorInfo* iface,
278         BSTR *pBstrHelpFile)
279 {
280         _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface);
281
282         TRACE("(%p)->(pBstrHelpFile=%p)\n",This, pBstrHelpFile);
283         if (pBstrHelpFile == NULL)
284             return E_INVALIDARG;
285         *pBstrHelpFile = ERRORINFO_SysAllocString(This->bstrHelpFile);
286
287         return S_OK;
288 }
289
290 static HRESULT WINAPI IErrorInfoImpl_GetHelpContext(
291         IErrorInfo* iface,
292         DWORD *pdwHelpContext)
293 {
294         _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface);
295         TRACE("(%p)->(pdwHelpContext=%p)\n",This, pdwHelpContext);
296         if (pdwHelpContext == NULL)
297             return E_INVALIDARG;
298         *pdwHelpContext = This->m_dwHelpContext;
299
300         return S_OK;
301 }
302
303 static ICOM_VTABLE(IErrorInfo) IErrorInfoImpl_VTable =
304 {
305   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
306   IErrorInfoImpl_QueryInterface,
307   IErrorInfoImpl_AddRef,
308   IErrorInfoImpl_Release,
309
310   IErrorInfoImpl_GetGUID,
311   IErrorInfoImpl_GetSource,
312   IErrorInfoImpl_GetDescription,
313   IErrorInfoImpl_GetHelpFile,
314   IErrorInfoImpl_GetHelpContext
315 };
316
317
318 static HRESULT WINAPI ICreateErrorInfoImpl_QueryInterface(
319         ICreateErrorInfo* iface,
320         REFIID     riid,
321         VOID**     ppvoid)
322 {
323         _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface);
324         TRACE("(%p)\n", This);
325         return IErrorInfo_QueryInterface(_IErrorInfo_(This), riid, ppvoid);
326 }
327
328 static ULONG WINAPI ICreateErrorInfoImpl_AddRef(
329         ICreateErrorInfo* iface)
330 {
331         _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface);
332         TRACE("(%p)\n", This);
333         return IErrorInfo_AddRef(_IErrorInfo_(This));
334 }
335
336 static ULONG WINAPI ICreateErrorInfoImpl_Release(
337         ICreateErrorInfo* iface)
338 {
339         _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface);
340         TRACE("(%p)\n", This);
341         return IErrorInfo_Release(_IErrorInfo_(This));
342 }
343
344
345 static HRESULT WINAPI ICreateErrorInfoImpl_SetGUID(
346         ICreateErrorInfo* iface,
347         REFGUID rguid)
348 {
349         _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface);
350         TRACE("(%p)->(%s)\n", This, debugstr_guid(rguid));
351         memcpy(&This->m_Guid,  rguid, sizeof(GUID));
352         return S_OK;
353 }
354
355 static HRESULT WINAPI ICreateErrorInfoImpl_SetSource(
356         ICreateErrorInfo* iface,
357         LPOLESTR szSource)
358 {
359         _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface);
360         TRACE("(%p)\n",This);
361         if (This->bstrSource != NULL)
362             ERRORINFO_SysFreeString(This->bstrSource);
363         This->bstrSource = ERRORINFO_SysAllocString(szSource);
364
365         return S_OK;
366 }
367
368 static HRESULT WINAPI ICreateErrorInfoImpl_SetDescription(
369         ICreateErrorInfo* iface,
370         LPOLESTR szDescription)
371 {
372         _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface);
373         TRACE("(%p)\n",This);
374         if (This->bstrDescription != NULL)
375             ERRORINFO_SysFreeString(This->bstrDescription);
376         This->bstrDescription = ERRORINFO_SysAllocString(szDescription);
377
378         return S_OK;
379 }
380
381 static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpFile(
382         ICreateErrorInfo* iface,
383         LPOLESTR szHelpFile)
384 {
385         _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface);
386         TRACE("(%p)\n",This);
387         if (This->bstrHelpFile != NULL)
388             ERRORINFO_SysFreeString(This->bstrHelpFile);
389         This->bstrHelpFile = ERRORINFO_SysAllocString(szHelpFile);
390
391         return S_OK;
392 }
393
394 static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpContext(
395         ICreateErrorInfo* iface,
396         DWORD dwHelpContext)
397 {
398         _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface);
399         TRACE("(%p)\n",This);
400         This->m_dwHelpContext = dwHelpContext;
401
402         return S_OK;
403 }
404
405 static ICOM_VTABLE(ICreateErrorInfo) ICreateErrorInfoImpl_VTable =
406 {
407   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
408   ICreateErrorInfoImpl_QueryInterface,
409   ICreateErrorInfoImpl_AddRef,
410   ICreateErrorInfoImpl_Release,
411
412   ICreateErrorInfoImpl_SetGUID,
413   ICreateErrorInfoImpl_SetSource,
414   ICreateErrorInfoImpl_SetDescription,
415   ICreateErrorInfoImpl_SetHelpFile,
416   ICreateErrorInfoImpl_SetHelpContext
417 };
418
419 static HRESULT WINAPI ISupportErrorInfoImpl_QueryInterface(
420         ISupportErrorInfo* iface,
421         REFIID     riid,
422         VOID**     ppvoid)
423 {
424         _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface);
425         TRACE("(%p)\n", This);
426
427         return IErrorInfo_QueryInterface(_IErrorInfo_(This), riid, ppvoid);
428 }
429
430 static ULONG WINAPI ISupportErrorInfoImpl_AddRef(
431         ISupportErrorInfo* iface)
432 {
433         _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface);
434         TRACE("(%p)\n", This);
435         return IErrorInfo_AddRef(_IErrorInfo_(This));
436 }
437
438 static ULONG WINAPI ISupportErrorInfoImpl_Release(
439         ISupportErrorInfo* iface)
440 {
441         _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface);
442         TRACE("(%p)\n", This);
443         return IErrorInfo_Release(_IErrorInfo_(This));
444 }
445
446
447 static HRESULT WINAPI ISupportErrorInfoImpl_InterfaceSupportsErrorInfo(
448         ISupportErrorInfo* iface,
449         REFIID riid)
450 {
451         _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface);
452         TRACE("(%p)->(%s)\n", This, debugstr_guid(riid));
453         return (IsEqualIID(riid, &This->m_Guid)) ? S_OK : S_FALSE;
454 }
455
456 static ICOM_VTABLE(ISupportErrorInfo) ISupportErrorInfoImpl_VTable =
457 {
458   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
459   ISupportErrorInfoImpl_QueryInterface,
460   ISupportErrorInfoImpl_AddRef,
461   ISupportErrorInfoImpl_Release,
462
463
464   ISupportErrorInfoImpl_InterfaceSupportsErrorInfo
465 };
466 /***********************************************************************
467  *              CreateErrorInfo (OLE32.@)
468  */
469 HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo)
470 {
471         IErrorInfo * pei;
472         HRESULT res;
473         TRACE("(%p): stub:\n", pperrinfo);
474         if(! pperrinfo ) return E_INVALIDARG;
475         if(!(pei=IErrorInfoImpl_Constructor()))return E_OUTOFMEMORY;
476
477         res = IErrorInfo_QueryInterface(pei, &IID_ICreateErrorInfo, (LPVOID*)pperrinfo);
478         IErrorInfo_Release(pei);
479         return res;
480 }
481
482 /***********************************************************************
483  *              GetErrorInfo (OLE32.@)
484  */
485 HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo)
486 {
487         TRACE("(%ld, %p, %p): stub:\n", dwReserved, pperrinfo, COM_CurrentInfo()->ErrorInfo);
488
489         if(! pperrinfo ) return E_INVALIDARG;
490         if(!(*pperrinfo = (IErrorInfo*)(COM_CurrentInfo()->ErrorInfo))) return S_FALSE;
491
492         /* clear thread error state */
493         COM_CurrentInfo()->ErrorInfo = NULL;
494         return S_OK;
495 }
496
497 /***********************************************************************
498  *              SetErrorInfo (OLE32.@)
499  */
500 HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo)
501 {
502         IErrorInfo * pei;
503         TRACE("(%ld, %p): stub:\n", dwReserved, perrinfo);
504
505         /* release old errorinfo */
506         pei = (IErrorInfo*)COM_CurrentInfo()->ErrorInfo;
507         if(pei) IErrorInfo_Release(pei);
508
509         /* set to new value */
510         COM_CurrentInfo()->ErrorInfo = perrinfo;
511         if(perrinfo) IErrorInfo_AddRef(perrinfo);
512         return S_OK;
513 }