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