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