windowscodecs: BMP decoder should always return valid image resolution.
[wine] / dlls / oleaut32 / recinfo.c
1 /*
2  * Copyright 2005 Jacek Caban
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28 #include "oaidl.h"
29 #include "oleauto.h"
30
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(ole);
35
36 typedef struct {
37     enum VARENUM vt;
38     VARKIND varkind;
39     ULONG offset;
40     BSTR name;
41 } fieldstr;
42
43 typedef struct {
44     IRecordInfo IRecordInfo_iface;
45     LONG ref;
46
47     GUID guid;
48     UINT lib_index;
49     WORD n_vars;
50     ULONG size;
51     BSTR name;
52     fieldstr *fields;
53     ITypeInfo *pTypeInfo;
54 } IRecordInfoImpl;
55
56 static inline IRecordInfoImpl *impl_from_IRecordInfo(IRecordInfo *iface)
57 {
58     return CONTAINING_RECORD(iface, IRecordInfoImpl, IRecordInfo_iface);
59 }
60
61 static HRESULT copy_to_variant(void *src, VARIANT *pvar, enum VARENUM vt)
62 {
63     TRACE("%p %p %d\n", src, pvar, vt);
64
65 #define CASE_COPY(x) \
66     case VT_ ## x: \
67         memcpy(&V_ ## x(pvar), src, sizeof(V_ ## x(pvar))); \
68         break 
69
70     switch(vt) {
71         CASE_COPY(I2);
72         CASE_COPY(I4);
73         CASE_COPY(R4);
74         CASE_COPY(R8);
75         CASE_COPY(CY);
76         CASE_COPY(DATE);
77         CASE_COPY(BSTR);
78         CASE_COPY(ERROR);
79         CASE_COPY(BOOL);
80         CASE_COPY(DECIMAL);
81         CASE_COPY(I1);
82         CASE_COPY(UI1);
83         CASE_COPY(UI2);
84         CASE_COPY(UI4);
85         CASE_COPY(I8);
86         CASE_COPY(UI8);
87         CASE_COPY(INT);
88         CASE_COPY(UINT);
89         CASE_COPY(INT_PTR);
90         CASE_COPY(UINT_PTR);
91     default:
92         FIXME("Not supported type: %d\n", vt);
93         return E_NOTIMPL;
94     };
95 #undef CASE_COPY
96
97     V_VT(pvar) = vt;
98     return S_OK;
99 }
100
101 static HRESULT copy_from_variant(VARIANT *src, void *dest, enum VARENUM vt)
102 {
103     VARIANT var;
104     HRESULT hres;
105
106     TRACE("(%p(%d) %p %d)\n", src, V_VT(src), dest, vt);
107
108     hres = VariantChangeType(&var, src, 0, vt);
109     if(FAILED(hres))
110         return hres;
111
112 #define CASE_COPY(x) \
113     case VT_ ## x: \
114         memcpy(dest, &V_ ## x(&var), sizeof(V_ ## x(&var))); \
115         break
116
117     switch(vt) {
118         CASE_COPY(I2);
119         CASE_COPY(I4);
120         CASE_COPY(R4);
121         CASE_COPY(R8);
122         CASE_COPY(CY);
123         CASE_COPY(DATE);
124         CASE_COPY(BSTR);
125         CASE_COPY(ERROR);
126         CASE_COPY(BOOL);
127         CASE_COPY(DECIMAL);
128         CASE_COPY(I1);
129         CASE_COPY(UI1);
130         CASE_COPY(UI2);
131         CASE_COPY(UI4);
132         CASE_COPY(I8);
133         CASE_COPY(UI8);
134         CASE_COPY(INT);
135         CASE_COPY(UINT);
136         CASE_COPY(INT_PTR);
137         CASE_COPY(UINT_PTR);
138     default:
139         FIXME("Not supported type: %d\n", V_VT(&var));
140         return E_NOTIMPL;
141     };
142 #undef CASE_COPY
143     return S_OK;
144 }
145
146 static HRESULT WINAPI IRecordInfoImpl_QueryInterface(IRecordInfo *iface, REFIID riid,
147                                                 void **ppvObject)
148 {
149     TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
150
151     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRecordInfo, riid)) {
152        *ppvObject = iface;
153        IRecordInfo_AddRef(iface);
154        return S_OK;
155     }
156
157     FIXME("Not supported interface: %s\n", debugstr_guid(riid));
158     return E_NOINTERFACE;
159 }
160
161 static ULONG WINAPI IRecordInfoImpl_AddRef(IRecordInfo *iface)
162 {
163     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
164     ULONG ref = InterlockedIncrement(&This->ref);
165     TRACE("(%p) -> %d\n", This, ref);
166     return ref;
167 }
168
169 static ULONG WINAPI IRecordInfoImpl_Release(IRecordInfo *iface)
170 {
171     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
172     ULONG ref = InterlockedDecrement(&This->ref);
173
174     TRACE("(%p) -> %d\n", This, ref);
175
176     if(!ref) {
177         int i;
178         for(i=0; i<This->n_vars; i++)
179             SysFreeString(This->fields[i].name);
180         HeapFree(GetProcessHeap(), 0, This->name);
181         HeapFree(GetProcessHeap(), 0, This->fields);
182         ITypeInfo_Release(This->pTypeInfo);
183         HeapFree(GetProcessHeap(), 0, This);
184     }
185     return ref;
186 }
187
188 static HRESULT WINAPI IRecordInfoImpl_RecordInit(IRecordInfo *iface, PVOID pvNew)
189 {
190     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
191     TRACE("(%p)->(%p)\n", This, pvNew);
192
193     if(!pvNew)
194         return E_INVALIDARG;
195
196     memset(pvNew, 0, This->size);
197     return S_OK;
198 }
199
200 static HRESULT WINAPI IRecordInfoImpl_RecordClear(IRecordInfo *iface, PVOID pvExisting)
201 {
202     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
203     int i;
204     PVOID var;
205
206     TRACE("(%p)->(%p)\n", This, pvExisting);
207
208     if(!pvExisting)
209         return E_INVALIDARG;
210
211     for(i=0; i<This->n_vars; i++) {
212         if(This->fields[i].varkind != VAR_PERINSTANCE) {
213             ERR("varkind != VAR_PERINSTANCE\n");
214             continue;
215         }
216         var = ((PBYTE)pvExisting)+This->fields[i].offset;
217         switch(This->fields[i].vt) {
218             case VT_BSTR:
219                SysFreeString(*(BSTR*)var);
220                 *(BSTR*)var = NULL;
221                 break;
222             case VT_I2:
223             case VT_I4:
224             case VT_R4:
225             case VT_R8:
226             case VT_CY:
227             case VT_DATE:
228             case VT_ERROR:
229             case VT_BOOL:
230             case VT_DECIMAL:
231             case VT_I1:
232             case VT_UI1:
233             case VT_UI2:
234             case VT_UI4:
235             case VT_I8:
236             case VT_UI8:
237             case VT_INT:
238             case VT_UINT:
239                 break;
240             case VT_INT_PTR:
241             case VT_UINT_PTR:
242                 *(void**)var = NULL;
243                 break;
244             case VT_SAFEARRAY:
245                 SafeArrayDestroy(var);
246                 break;
247             default:
248                 FIXME("Not supported vt = %d\n", This->fields[i].vt);
249                 break;
250         }
251     }
252     
253     return S_OK;
254 }
255
256 static HRESULT WINAPI IRecordInfoImpl_RecordCopy(IRecordInfo *iface, PVOID pvExisting,
257                                                 PVOID pvNew)
258 {
259     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
260
261     TRACE("(%p)->(%p %p)\n", This, pvExisting, pvNew);
262     
263     if(!pvExisting || !pvNew)
264         return E_INVALIDARG;
265
266     memcpy(pvExisting, pvNew, This->size);
267     return S_OK;
268 }
269
270 static HRESULT WINAPI IRecordInfoImpl_GetGuid(IRecordInfo *iface, GUID *pguid)
271 {
272     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
273
274     TRACE("(%p)->(%p)\n", This, pguid);
275
276     if(!pguid)
277         return E_INVALIDARG;
278
279     *pguid = This->guid;
280     return S_OK;
281 }
282
283 static HRESULT WINAPI IRecordInfoImpl_GetName(IRecordInfo *iface, BSTR *pbstrName)
284 {
285     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
286
287     TRACE("(%p)->(%p)\n", This, pbstrName);
288
289     if(!pbstrName)
290         return E_INVALIDARG;
291
292     *pbstrName = SysAllocString(This->name);
293     return S_OK;
294 }
295
296 static HRESULT WINAPI IRecordInfoImpl_GetSize(IRecordInfo *iface, ULONG *pcbSize)
297 {
298     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
299
300     TRACE("(%p)->(%p)\n", This, pcbSize);
301
302     if(!pcbSize)
303         return E_INVALIDARG;
304     
305     *pcbSize = This->size;
306     return S_OK;
307 }
308
309 static HRESULT WINAPI IRecordInfoImpl_GetTypeInfo(IRecordInfo *iface, ITypeInfo **ppTypeInfo)
310 {
311     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
312
313     TRACE("(%p)->(%p)\n", This, ppTypeInfo);
314
315     if(!ppTypeInfo)
316         return E_INVALIDARG;
317
318     ITypeInfo_AddRef(This->pTypeInfo);
319     *ppTypeInfo = This->pTypeInfo;
320
321     return S_OK;
322 }
323
324 static HRESULT WINAPI IRecordInfoImpl_GetField(IRecordInfo *iface, PVOID pvData,
325                                                 LPCOLESTR szFieldName, VARIANT *pvarField)
326 {
327     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
328     int i;
329
330     TRACE("(%p)->(%p %s %p)\n", This, pvData, debugstr_w(szFieldName), pvarField);
331
332     if(!pvData || !szFieldName || !pvarField)
333         return E_INVALIDARG;
334
335     for(i=0; i<This->n_vars; i++)
336         if(!strcmpW(This->fields[i].name, szFieldName))
337             break;
338     if(i == This->n_vars)
339         return TYPE_E_FIELDNOTFOUND;
340     
341     VariantClear(pvarField);
342     return copy_to_variant(((PBYTE)pvData)+This->fields[i].offset, pvarField,
343             This->fields[i].vt);
344 }
345
346 static HRESULT WINAPI IRecordInfoImpl_GetFieldNoCopy(IRecordInfo *iface, PVOID pvData,
347                             LPCOLESTR szFieldName, VARIANT *pvarField, PVOID *ppvDataCArray)
348 {
349     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
350     int i;
351
352     TRACE("(%p)->(%p %s %p %p)\n", This, pvData, debugstr_w(szFieldName), pvarField, ppvDataCArray);
353
354     if(!pvData || !szFieldName || !pvarField)
355         return E_INVALIDARG;
356
357     for(i=0; i<This->n_vars; i++)
358         if(!strcmpW(This->fields[i].name, szFieldName))
359             break;
360     if(i == This->n_vars)
361         return TYPE_E_FIELDNOTFOUND;
362
363     VariantClear(pvarField);
364     V_VT(pvarField) = VT_BYREF|This->fields[i].vt;
365     V_BYREF(pvarField) = ((PBYTE)pvData)+This->fields[i].offset;
366     *ppvDataCArray = NULL;
367     return S_OK;
368 }
369
370 static HRESULT WINAPI IRecordInfoImpl_PutField(IRecordInfo *iface, ULONG wFlags, PVOID pvData,
371                                             LPCOLESTR szFieldName, VARIANT *pvarField)
372 {
373     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
374     int i;
375
376     TRACE("(%p)->(%08x %p %s %p)\n", This, wFlags, pvData, debugstr_w(szFieldName),
377                                     pvarField);
378
379     if(!pvData || !szFieldName || !pvarField
380             || (wFlags != INVOKE_PROPERTYPUTREF && wFlags != INVOKE_PROPERTYPUT))
381         return E_INVALIDARG;
382
383     if(wFlags == INVOKE_PROPERTYPUTREF) {
384         FIXME("wFlag == INVOKE_PROPERTYPUTREF not supported\n");
385         return E_NOTIMPL;
386     }
387
388     for(i=0; i<This->n_vars; i++)
389         if(!strcmpW(This->fields[i].name, szFieldName))
390             break;
391     if(i == This->n_vars)
392         return TYPE_E_FIELDNOTFOUND;
393
394     return copy_from_variant(pvarField, ((PBYTE)pvData)+This->fields[i].offset,
395             This->fields[i].vt);
396 }
397
398 static HRESULT WINAPI IRecordInfoImpl_PutFieldNoCopy(IRecordInfo *iface, ULONG wFlags,
399                 PVOID pvData, LPCOLESTR szFieldName, VARIANT *pvarField)
400 {
401     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
402     int i;
403
404     FIXME("(%p)->(%08x %p %s %p) stub\n", This, wFlags, pvData, debugstr_w(szFieldName), pvarField);
405
406     if(!pvData || !szFieldName || !pvarField
407             || (wFlags != INVOKE_PROPERTYPUTREF && wFlags != INVOKE_PROPERTYPUT))
408         return E_INVALIDARG;
409
410     for(i=0; i<This->n_vars; i++)
411         if(!strcmpW(This->fields[i].name, szFieldName))
412             break;
413     if(i == This->n_vars)
414         return TYPE_E_FIELDNOTFOUND;
415
416     return E_NOTIMPL;
417 }
418
419 static HRESULT WINAPI IRecordInfoImpl_GetFieldNames(IRecordInfo *iface, ULONG *pcNames,
420                                                 BSTR *rgBstrNames)
421 {
422     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
423     ULONG n = This->n_vars, i;
424
425     TRACE("(%p)->(%p %p)\n", This, pcNames, rgBstrNames);
426
427     if(!pcNames)
428         return E_INVALIDARG;
429
430     if(*pcNames < n)
431         n =  *pcNames;
432
433     if(rgBstrNames) {
434         for(i=0; i<n; i++)
435             rgBstrNames[i] = SysAllocString(This->fields[i].name);
436     }
437     
438     *pcNames = n;
439     return S_OK;
440 }
441
442 static BOOL WINAPI IRecordInfoImpl_IsMatchingType(IRecordInfo *iface, IRecordInfo *info2)
443 {
444     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
445     GUID guid2;
446
447     TRACE( "(%p)->(%p)\n", This, info2 );
448
449     IRecordInfo_GetGuid( info2, &guid2 );
450     if (IsEqualGUID( &This->guid, &guid2 )) return TRUE;
451
452     FIXME( "records have different guids (%s %s) but could still match\n",
453            debugstr_guid( &This->guid ), debugstr_guid( &guid2 ) );
454
455     return FALSE;
456 }
457
458 static PVOID WINAPI IRecordInfoImpl_RecordCreate(IRecordInfo *iface)
459 {
460     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
461
462     TRACE("(%p)\n", This);
463
464     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->size);
465 }
466
467 static HRESULT WINAPI IRecordInfoImpl_RecordCreateCopy(IRecordInfo *iface, PVOID pvSource,
468                                                     PVOID *ppvDest)
469 {
470     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
471
472     TRACE("(%p)->(%p %p)\n", This, pvSource, ppvDest);
473
474     if(!pvSource || !ppvDest)
475         return E_INVALIDARG;
476     
477     *ppvDest = IRecordInfo_RecordCreate(iface);
478     return IRecordInfo_RecordCopy(iface, pvSource, *ppvDest);
479 }
480
481 static HRESULT WINAPI IRecordInfoImpl_RecordDestroy(IRecordInfo *iface, PVOID pvRecord)
482 {
483     IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
484     HRESULT hres;
485
486     TRACE("(%p)->(%p)\n", This, pvRecord);
487
488     hres = IRecordInfo_RecordClear(iface, pvRecord);
489     if(FAILED(hres))
490         return hres;
491
492     if(!HeapFree(GetProcessHeap(), 0, pvRecord))
493         return E_INVALIDARG;
494
495     return S_OK;
496 }
497
498 static const IRecordInfoVtbl IRecordInfoImplVtbl = {
499     IRecordInfoImpl_QueryInterface,
500     IRecordInfoImpl_AddRef,
501     IRecordInfoImpl_Release,
502     IRecordInfoImpl_RecordInit,
503     IRecordInfoImpl_RecordClear,
504     IRecordInfoImpl_RecordCopy,
505     IRecordInfoImpl_GetGuid,
506     IRecordInfoImpl_GetName,
507     IRecordInfoImpl_GetSize,
508     IRecordInfoImpl_GetTypeInfo,
509     IRecordInfoImpl_GetField,
510     IRecordInfoImpl_GetFieldNoCopy,
511     IRecordInfoImpl_PutField,
512     IRecordInfoImpl_PutFieldNoCopy,
513     IRecordInfoImpl_GetFieldNames,
514     IRecordInfoImpl_IsMatchingType,
515     IRecordInfoImpl_RecordCreate,
516     IRecordInfoImpl_RecordCreateCopy,
517     IRecordInfoImpl_RecordDestroy
518 };
519
520 /******************************************************************************
521  *      GetRecordInfoFromGuids  [OLEAUT32.322]
522  *
523  * RETURNS
524  *  Success: S_OK
525  *  Failure: E_INVALIDARG, if any argument is invalid.
526  */
527 HRESULT WINAPI GetRecordInfoFromGuids(REFGUID rGuidTypeLib, ULONG uVerMajor,
528                         ULONG uVerMinor, LCID lcid, REFGUID rGuidTypeInfo, IRecordInfo** ppRecInfo)
529 {
530     ITypeInfo *pTypeInfo;
531     ITypeLib *pTypeLib;
532     HRESULT hres;
533     
534     TRACE("(%p,%d,%d,%d,%p,%p)\n", rGuidTypeLib, uVerMajor, uVerMinor,
535             lcid, rGuidTypeInfo, ppRecInfo);
536
537     hres = LoadRegTypeLib(rGuidTypeLib, uVerMajor, uVerMinor, lcid, &pTypeLib);
538     if(FAILED(hres)) {
539         WARN("LoadRegTypeLib failed!\n");
540         return hres;
541     }
542
543     hres = ITypeLib_GetTypeInfoOfGuid(pTypeLib, rGuidTypeInfo, &pTypeInfo);
544     ITypeLib_Release(pTypeLib);
545     if(FAILED(hres)) {
546         WARN("GetTypeInfoOfGuid failed!\n");
547         return hres;
548     }
549
550     hres = GetRecordInfoFromTypeInfo(pTypeInfo, ppRecInfo);
551     ITypeInfo_Release(pTypeInfo);
552     return hres;
553 }
554
555 /******************************************************************************
556  *      GetRecordInfoFromTypeInfo [OLEAUT32.332]
557  */
558 HRESULT WINAPI GetRecordInfoFromTypeInfo(ITypeInfo* pTI, IRecordInfo** ppRecInfo) {
559     HRESULT hres;
560     TYPEATTR *typeattr;
561     IRecordInfoImpl *ret;
562     ITypeInfo *pTypeInfo;
563     int i;
564     GUID guid;
565
566     TRACE("(%p %p)\n", pTI, ppRecInfo);
567
568     if(!pTI || !ppRecInfo)
569         return E_INVALIDARG;
570     
571     hres = ITypeInfo_GetTypeAttr(pTI, &typeattr);
572     if(FAILED(hres) || !typeattr) {
573         WARN("GetTypeAttr failed: %08x\n", hres);
574         return hres;
575     }
576
577     if(typeattr->typekind == TKIND_ALIAS) {
578         hres = ITypeInfo_GetRefTypeInfo(pTI, typeattr->tdescAlias.u.hreftype, &pTypeInfo);
579         guid = typeattr->guid;
580         ITypeInfo_ReleaseTypeAttr(pTI, typeattr);
581         if(FAILED(hres)) {
582             WARN("GetRefTypeInfo failed: %08x\n", hres);
583             return hres;
584         }
585         ITypeInfo_GetTypeAttr(pTypeInfo, &typeattr);
586     }else  {
587         pTypeInfo = pTI;
588         ITypeInfo_AddRef(pTypeInfo);
589         guid = typeattr->guid;
590     }
591
592     if(typeattr->typekind != TKIND_RECORD) {
593         WARN("typekind != TKIND_RECORD\n");
594         ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr);
595         ITypeInfo_Release(pTypeInfo);
596         return E_INVALIDARG;
597     }
598
599     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
600     ret->IRecordInfo_iface.lpVtbl = &IRecordInfoImplVtbl;
601     ret->ref = 1;
602     ret->pTypeInfo = pTypeInfo;
603     ret->n_vars = typeattr->cVars;
604     ret->size = typeattr->cbSizeInstance;
605     ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr);
606
607     ret->guid = guid;
608
609     /* NOTE: Windows implementation calls ITypeInfo::GetCantainingTypeLib and
610      *       ITypeLib::GetLibAttr, but we currently don't need this.
611      */
612
613     hres = ITypeInfo_GetDocumentation(pTypeInfo, MEMBERID_NIL, &ret->name, NULL, NULL, NULL);
614     if(FAILED(hres)) {
615         WARN("ITypeInfo::GetDocumentation failed\n");
616         ret->name = NULL;
617     }
618
619     ret->fields = HeapAlloc(GetProcessHeap(), 0, ret->n_vars*sizeof(fieldstr));
620     for(i = 0; i<ret->n_vars; i++) {
621         VARDESC *vardesc;
622         hres = ITypeInfo_GetVarDesc(pTypeInfo, i, &vardesc);
623         if(FAILED(hres)) {
624             WARN("GetVarDesc failed\n");
625             continue;
626         }
627         ret->fields[i].vt = vardesc->elemdescVar.tdesc.vt;
628         ret->fields[i].varkind = vardesc->varkind;
629         ret->fields[i].offset = vardesc->u.oInst;
630         hres = ITypeInfo_GetDocumentation(pTypeInfo, vardesc->memid, &ret->fields[i].name,
631                 NULL, NULL, NULL);
632         if(FAILED(hres))
633             WARN("GetDocumentation failed: %08x\n", hres);
634         ITypeInfo_ReleaseVarDesc(pTypeInfo, vardesc);
635     }
636
637     *ppRecInfo = &ret->IRecordInfo_iface;
638
639     return S_OK;
640 }