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