ole32: Use share modes when creating storage files.
[wine/multimedia.git] / dlls / oleaut32 / recinfo.c
blobd6da64abf1cee7e851ece49f2815f2132eb9270c
1 /*
2 * Copyright 2005 Jacek Caban
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.
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.
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
19 #include <stdarg.h>
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28 #include "oaidl.h"
29 #include "oleauto.h"
30 #include "variant.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(ole);
37 typedef struct {
38 enum VARENUM vt;
39 VARKIND varkind;
40 ULONG offset;
41 BSTR name;
42 } fieldstr;
44 typedef struct {
45 IRecordInfo IRecordInfo_iface;
46 LONG ref;
48 GUID guid;
49 UINT lib_index;
50 WORD n_vars;
51 ULONG size;
52 BSTR name;
53 fieldstr *fields;
54 ITypeInfo *pTypeInfo;
55 } IRecordInfoImpl;
57 static inline IRecordInfoImpl *impl_from_IRecordInfo(IRecordInfo *iface)
59 return CONTAINING_RECORD(iface, IRecordInfoImpl, IRecordInfo_iface);
62 static HRESULT copy_to_variant(void *src, VARIANT *pvar, enum VARENUM vt)
64 TRACE("%p %p %d\n", src, pvar, vt);
66 #define CASE_COPY(x) \
67 case VT_ ## x: \
68 memcpy(&V_ ## x(pvar), src, sizeof(V_ ## x(pvar))); \
69 break
71 switch(vt) {
72 CASE_COPY(I2);
73 CASE_COPY(I4);
74 CASE_COPY(R4);
75 CASE_COPY(R8);
76 CASE_COPY(CY);
77 CASE_COPY(DATE);
78 CASE_COPY(BSTR);
79 CASE_COPY(ERROR);
80 CASE_COPY(BOOL);
81 CASE_COPY(DECIMAL);
82 CASE_COPY(I1);
83 CASE_COPY(UI1);
84 CASE_COPY(UI2);
85 CASE_COPY(UI4);
86 CASE_COPY(I8);
87 CASE_COPY(UI8);
88 CASE_COPY(INT);
89 CASE_COPY(UINT);
90 CASE_COPY(INT_PTR);
91 CASE_COPY(UINT_PTR);
92 default:
93 FIXME("Not supported type: %d\n", vt);
94 return E_NOTIMPL;
96 #undef CASE_COPY
98 V_VT(pvar) = vt;
99 return S_OK;
102 static HRESULT copy_from_variant(VARIANT *src, void *dest, enum VARENUM vt)
104 VARIANT var;
105 HRESULT hres;
107 TRACE("(%p(%d) %p %d)\n", src, V_VT(src), dest, vt);
109 hres = VariantChangeType(&var, src, 0, vt);
110 if(FAILED(hres))
111 return hres;
113 #define CASE_COPY(x) \
114 case VT_ ## x: \
115 memcpy(dest, &V_ ## x(&var), sizeof(V_ ## x(&var))); \
116 break
118 switch(vt) {
119 CASE_COPY(I2);
120 CASE_COPY(I4);
121 CASE_COPY(R4);
122 CASE_COPY(R8);
123 CASE_COPY(CY);
124 CASE_COPY(DATE);
125 CASE_COPY(BSTR);
126 CASE_COPY(ERROR);
127 CASE_COPY(BOOL);
128 CASE_COPY(DECIMAL);
129 CASE_COPY(I1);
130 CASE_COPY(UI1);
131 CASE_COPY(UI2);
132 CASE_COPY(UI4);
133 CASE_COPY(I8);
134 CASE_COPY(UI8);
135 CASE_COPY(INT);
136 CASE_COPY(UINT);
137 CASE_COPY(INT_PTR);
138 CASE_COPY(UINT_PTR);
139 default:
140 FIXME("Not supported type: %d\n", V_VT(&var));
141 return E_NOTIMPL;
143 #undef CASE_COPY
144 return S_OK;
147 static HRESULT WINAPI IRecordInfoImpl_QueryInterface(IRecordInfo *iface, REFIID riid,
148 void **ppvObject)
150 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
152 *ppvObject = NULL;
154 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRecordInfo, riid)) {
155 *ppvObject = iface;
156 IRecordInfo_AddRef(iface);
157 return S_OK;
160 FIXME("Not supported interface: %s\n", debugstr_guid(riid));
161 return E_NOINTERFACE;
164 static ULONG WINAPI IRecordInfoImpl_AddRef(IRecordInfo *iface)
166 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
167 ULONG ref = InterlockedIncrement(&This->ref);
168 TRACE("(%p) -> %d\n", This, ref);
169 return ref;
172 static ULONG WINAPI IRecordInfoImpl_Release(IRecordInfo *iface)
174 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
175 ULONG ref = InterlockedDecrement(&This->ref);
177 TRACE("(%p) -> %d\n", This, ref);
179 if(!ref) {
180 int i;
181 for(i=0; i<This->n_vars; i++)
182 SysFreeString(This->fields[i].name);
183 SysFreeString(This->name);
184 HeapFree(GetProcessHeap(), 0, This->fields);
185 ITypeInfo_Release(This->pTypeInfo);
186 HeapFree(GetProcessHeap(), 0, This);
188 return ref;
191 static HRESULT WINAPI IRecordInfoImpl_RecordInit(IRecordInfo *iface, PVOID pvNew)
193 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
194 TRACE("(%p)->(%p)\n", This, pvNew);
196 if(!pvNew)
197 return E_INVALIDARG;
199 memset(pvNew, 0, This->size);
200 return S_OK;
203 static HRESULT WINAPI IRecordInfoImpl_RecordClear(IRecordInfo *iface, PVOID pvExisting)
205 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
206 int i;
207 PVOID var;
209 TRACE("(%p)->(%p)\n", This, pvExisting);
211 if(!pvExisting)
212 return E_INVALIDARG;
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;
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 case VT_HRESULT:
243 break;
244 case VT_INT_PTR:
245 case VT_UINT_PTR:
246 *(void**)var = NULL;
247 break;
248 case VT_SAFEARRAY:
249 SafeArrayDestroy(var);
250 break;
251 case VT_UNKNOWN:
252 case VT_DISPATCH:
254 IUnknown *unk = *(IUnknown**)var;
255 if (unk)
256 IUnknown_Release(unk);
257 *(void**)var = NULL;
258 break;
260 default:
261 FIXME("Not supported vt = %d\n", This->fields[i].vt);
262 break;
266 return S_OK;
269 static HRESULT WINAPI IRecordInfoImpl_RecordCopy(IRecordInfo *iface, void *src_rec, void *dest_rec)
271 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
272 HRESULT hr = S_OK;
273 int i;
275 TRACE("(%p)->(%p %p)\n", This, src_rec, dest_rec);
277 if(!src_rec || !dest_rec)
278 return E_INVALIDARG;
280 /* release already stored data */
281 IRecordInfo_RecordClear(iface, dest_rec);
283 for (i = 0; i < This->n_vars; i++)
285 void *src, *dest;
287 if (This->fields[i].varkind != VAR_PERINSTANCE) {
288 ERR("varkind != VAR_PERINSTANCE\n");
289 continue;
292 src = ((BYTE*)src_rec) + This->fields[i].offset;
293 dest = ((BYTE*)dest_rec) + This->fields[i].offset;
294 switch (This->fields[i].vt)
296 case VT_BSTR:
298 BSTR src_str = *(BSTR*)src;
300 if (src_str)
302 BSTR str = SysAllocString(*(BSTR*)src);
303 if (!str) hr = E_OUTOFMEMORY;
305 *(BSTR*)dest = str;
307 else
308 *(BSTR*)dest = NULL;
309 break;
311 case VT_UNKNOWN:
312 case VT_DISPATCH:
314 IUnknown *unk = *(IUnknown**)src;
315 *(IUnknown**)dest = unk;
316 if (unk) IUnknown_AddRef(unk);
317 break;
319 case VT_SAFEARRAY:
320 hr = SafeArrayCopy(src, dest);
321 break;
322 default:
324 /* copy directly for types that don't need deep copy */
325 int len = get_type_size(NULL, This->fields[i].vt);
326 memcpy(dest, src, len);
327 break;
331 if (FAILED(hr)) break;
334 if (FAILED(hr))
335 IRecordInfo_RecordClear(iface, dest_rec);
337 return hr;
340 static HRESULT WINAPI IRecordInfoImpl_GetGuid(IRecordInfo *iface, GUID *pguid)
342 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
344 TRACE("(%p)->(%p)\n", This, pguid);
346 if(!pguid)
347 return E_INVALIDARG;
349 *pguid = This->guid;
350 return S_OK;
353 static HRESULT WINAPI IRecordInfoImpl_GetName(IRecordInfo *iface, BSTR *pbstrName)
355 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
357 TRACE("(%p)->(%p)\n", This, pbstrName);
359 if(!pbstrName)
360 return E_INVALIDARG;
362 *pbstrName = SysAllocString(This->name);
363 return S_OK;
366 static HRESULT WINAPI IRecordInfoImpl_GetSize(IRecordInfo *iface, ULONG *pcbSize)
368 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
370 TRACE("(%p)->(%p)\n", This, pcbSize);
372 if(!pcbSize)
373 return E_INVALIDARG;
375 *pcbSize = This->size;
376 return S_OK;
379 static HRESULT WINAPI IRecordInfoImpl_GetTypeInfo(IRecordInfo *iface, ITypeInfo **ppTypeInfo)
381 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
383 TRACE("(%p)->(%p)\n", This, ppTypeInfo);
385 if(!ppTypeInfo)
386 return E_INVALIDARG;
388 ITypeInfo_AddRef(This->pTypeInfo);
389 *ppTypeInfo = This->pTypeInfo;
391 return S_OK;
394 static HRESULT WINAPI IRecordInfoImpl_GetField(IRecordInfo *iface, PVOID pvData,
395 LPCOLESTR szFieldName, VARIANT *pvarField)
397 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
398 int i;
400 TRACE("(%p)->(%p %s %p)\n", This, pvData, debugstr_w(szFieldName), pvarField);
402 if(!pvData || !szFieldName || !pvarField)
403 return E_INVALIDARG;
405 for(i=0; i<This->n_vars; i++)
406 if(!strcmpW(This->fields[i].name, szFieldName))
407 break;
408 if(i == This->n_vars)
409 return TYPE_E_FIELDNOTFOUND;
411 VariantClear(pvarField);
412 return copy_to_variant(((PBYTE)pvData)+This->fields[i].offset, pvarField,
413 This->fields[i].vt);
416 static HRESULT WINAPI IRecordInfoImpl_GetFieldNoCopy(IRecordInfo *iface, PVOID pvData,
417 LPCOLESTR szFieldName, VARIANT *pvarField, PVOID *ppvDataCArray)
419 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
420 int i;
422 TRACE("(%p)->(%p %s %p %p)\n", This, pvData, debugstr_w(szFieldName), pvarField, ppvDataCArray);
424 if(!pvData || !szFieldName || !pvarField)
425 return E_INVALIDARG;
427 for(i=0; i<This->n_vars; i++)
428 if(!strcmpW(This->fields[i].name, szFieldName))
429 break;
430 if(i == This->n_vars)
431 return TYPE_E_FIELDNOTFOUND;
433 VariantClear(pvarField);
434 V_VT(pvarField) = VT_BYREF|This->fields[i].vt;
435 V_BYREF(pvarField) = ((PBYTE)pvData)+This->fields[i].offset;
436 *ppvDataCArray = NULL;
437 return S_OK;
440 static HRESULT WINAPI IRecordInfoImpl_PutField(IRecordInfo *iface, ULONG wFlags, PVOID pvData,
441 LPCOLESTR szFieldName, VARIANT *pvarField)
443 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
444 int i;
446 TRACE("(%p)->(%08x %p %s %p)\n", This, wFlags, pvData, debugstr_w(szFieldName),
447 pvarField);
449 if(!pvData || !szFieldName || !pvarField
450 || (wFlags != INVOKE_PROPERTYPUTREF && wFlags != INVOKE_PROPERTYPUT))
451 return E_INVALIDARG;
453 if(wFlags == INVOKE_PROPERTYPUTREF) {
454 FIXME("wFlag == INVOKE_PROPERTYPUTREF not supported\n");
455 return E_NOTIMPL;
458 for(i=0; i<This->n_vars; i++)
459 if(!strcmpW(This->fields[i].name, szFieldName))
460 break;
461 if(i == This->n_vars)
462 return TYPE_E_FIELDNOTFOUND;
464 return copy_from_variant(pvarField, ((PBYTE)pvData)+This->fields[i].offset,
465 This->fields[i].vt);
468 static HRESULT WINAPI IRecordInfoImpl_PutFieldNoCopy(IRecordInfo *iface, ULONG wFlags,
469 PVOID pvData, LPCOLESTR szFieldName, VARIANT *pvarField)
471 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
472 int i;
474 FIXME("(%p)->(%08x %p %s %p) stub\n", This, wFlags, pvData, debugstr_w(szFieldName), pvarField);
476 if(!pvData || !szFieldName || !pvarField
477 || (wFlags != INVOKE_PROPERTYPUTREF && wFlags != INVOKE_PROPERTYPUT))
478 return E_INVALIDARG;
480 for(i=0; i<This->n_vars; i++)
481 if(!strcmpW(This->fields[i].name, szFieldName))
482 break;
483 if(i == This->n_vars)
484 return TYPE_E_FIELDNOTFOUND;
486 return E_NOTIMPL;
489 static HRESULT WINAPI IRecordInfoImpl_GetFieldNames(IRecordInfo *iface, ULONG *pcNames,
490 BSTR *rgBstrNames)
492 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
493 ULONG n = This->n_vars, i;
495 TRACE("(%p)->(%p %p)\n", This, pcNames, rgBstrNames);
497 if(!pcNames)
498 return E_INVALIDARG;
500 if(*pcNames < n)
501 n = *pcNames;
503 if(rgBstrNames) {
504 for(i=0; i<n; i++)
505 rgBstrNames[i] = SysAllocString(This->fields[i].name);
508 *pcNames = n;
509 return S_OK;
512 static BOOL WINAPI IRecordInfoImpl_IsMatchingType(IRecordInfo *iface, IRecordInfo *info2)
514 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
515 GUID guid2;
517 TRACE( "(%p)->(%p)\n", This, info2 );
519 IRecordInfo_GetGuid( info2, &guid2 );
520 if (IsEqualGUID( &This->guid, &guid2 )) return TRUE;
522 FIXME( "records have different guids (%s %s) but could still match\n",
523 debugstr_guid( &This->guid ), debugstr_guid( &guid2 ) );
525 return FALSE;
528 static PVOID WINAPI IRecordInfoImpl_RecordCreate(IRecordInfo *iface)
530 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
531 void *record;
533 TRACE("(%p)\n", This);
535 record = HeapAlloc(GetProcessHeap(), 0, This->size);
536 IRecordInfo_RecordInit(iface, record);
537 TRACE("created record at %p\n", record);
538 return record;
541 static HRESULT WINAPI IRecordInfoImpl_RecordCreateCopy(IRecordInfo *iface, PVOID pvSource,
542 PVOID *ppvDest)
544 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
546 TRACE("(%p)->(%p %p)\n", This, pvSource, ppvDest);
548 if(!pvSource || !ppvDest)
549 return E_INVALIDARG;
551 *ppvDest = IRecordInfo_RecordCreate(iface);
552 return IRecordInfo_RecordCopy(iface, pvSource, *ppvDest);
555 static HRESULT WINAPI IRecordInfoImpl_RecordDestroy(IRecordInfo *iface, PVOID pvRecord)
557 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
558 HRESULT hres;
560 TRACE("(%p)->(%p)\n", This, pvRecord);
562 hres = IRecordInfo_RecordClear(iface, pvRecord);
563 if(FAILED(hres))
564 return hres;
566 if(!HeapFree(GetProcessHeap(), 0, pvRecord))
567 return E_INVALIDARG;
569 return S_OK;
572 static const IRecordInfoVtbl IRecordInfoImplVtbl = {
573 IRecordInfoImpl_QueryInterface,
574 IRecordInfoImpl_AddRef,
575 IRecordInfoImpl_Release,
576 IRecordInfoImpl_RecordInit,
577 IRecordInfoImpl_RecordClear,
578 IRecordInfoImpl_RecordCopy,
579 IRecordInfoImpl_GetGuid,
580 IRecordInfoImpl_GetName,
581 IRecordInfoImpl_GetSize,
582 IRecordInfoImpl_GetTypeInfo,
583 IRecordInfoImpl_GetField,
584 IRecordInfoImpl_GetFieldNoCopy,
585 IRecordInfoImpl_PutField,
586 IRecordInfoImpl_PutFieldNoCopy,
587 IRecordInfoImpl_GetFieldNames,
588 IRecordInfoImpl_IsMatchingType,
589 IRecordInfoImpl_RecordCreate,
590 IRecordInfoImpl_RecordCreateCopy,
591 IRecordInfoImpl_RecordDestroy
594 /******************************************************************************
595 * GetRecordInfoFromGuids [OLEAUT32.322]
597 * RETURNS
598 * Success: S_OK
599 * Failure: E_INVALIDARG, if any argument is invalid.
601 HRESULT WINAPI GetRecordInfoFromGuids(REFGUID rGuidTypeLib, ULONG uVerMajor,
602 ULONG uVerMinor, LCID lcid, REFGUID rGuidTypeInfo, IRecordInfo** ppRecInfo)
604 ITypeInfo *pTypeInfo;
605 ITypeLib *pTypeLib;
606 HRESULT hres;
608 TRACE("(%p,%d,%d,%d,%s,%p)\n", rGuidTypeLib, uVerMajor, uVerMinor,
609 lcid, debugstr_guid(rGuidTypeInfo), ppRecInfo);
611 hres = LoadRegTypeLib(rGuidTypeLib, uVerMajor, uVerMinor, lcid, &pTypeLib);
612 if(FAILED(hres)) {
613 WARN("LoadRegTypeLib failed!\n");
614 return hres;
617 hres = ITypeLib_GetTypeInfoOfGuid(pTypeLib, rGuidTypeInfo, &pTypeInfo);
618 ITypeLib_Release(pTypeLib);
619 if(FAILED(hres)) {
620 WARN("GetTypeInfoOfGuid failed!\n");
621 return hres;
624 hres = GetRecordInfoFromTypeInfo(pTypeInfo, ppRecInfo);
625 ITypeInfo_Release(pTypeInfo);
626 return hres;
629 /******************************************************************************
630 * GetRecordInfoFromTypeInfo [OLEAUT32.332]
632 HRESULT WINAPI GetRecordInfoFromTypeInfo(ITypeInfo* pTI, IRecordInfo** ppRecInfo) {
633 HRESULT hres;
634 TYPEATTR *typeattr;
635 IRecordInfoImpl *ret;
636 ITypeInfo *pTypeInfo;
637 int i;
638 GUID guid;
640 TRACE("(%p %p)\n", pTI, ppRecInfo);
642 if(!pTI || !ppRecInfo)
643 return E_INVALIDARG;
645 hres = ITypeInfo_GetTypeAttr(pTI, &typeattr);
646 if(FAILED(hres) || !typeattr) {
647 WARN("GetTypeAttr failed: %08x\n", hres);
648 return hres;
651 if(typeattr->typekind == TKIND_ALIAS) {
652 hres = ITypeInfo_GetRefTypeInfo(pTI, typeattr->tdescAlias.u.hreftype, &pTypeInfo);
653 guid = typeattr->guid;
654 ITypeInfo_ReleaseTypeAttr(pTI, typeattr);
655 if(FAILED(hres)) {
656 WARN("GetRefTypeInfo failed: %08x\n", hres);
657 return hres;
659 ITypeInfo_GetTypeAttr(pTypeInfo, &typeattr);
660 }else {
661 pTypeInfo = pTI;
662 ITypeInfo_AddRef(pTypeInfo);
663 guid = typeattr->guid;
666 if(typeattr->typekind != TKIND_RECORD) {
667 WARN("typekind != TKIND_RECORD\n");
668 ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr);
669 ITypeInfo_Release(pTypeInfo);
670 return E_INVALIDARG;
673 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
674 ret->IRecordInfo_iface.lpVtbl = &IRecordInfoImplVtbl;
675 ret->ref = 1;
676 ret->pTypeInfo = pTypeInfo;
677 ret->n_vars = typeattr->cVars;
678 ret->size = typeattr->cbSizeInstance;
679 ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr);
681 ret->guid = guid;
683 /* NOTE: Windows implementation calls ITypeInfo::GetCantainingTypeLib and
684 * ITypeLib::GetLibAttr, but we currently don't need this.
687 hres = ITypeInfo_GetDocumentation(pTypeInfo, MEMBERID_NIL, &ret->name, NULL, NULL, NULL);
688 if(FAILED(hres)) {
689 WARN("ITypeInfo::GetDocumentation failed\n");
690 ret->name = NULL;
693 ret->fields = HeapAlloc(GetProcessHeap(), 0, ret->n_vars*sizeof(fieldstr));
694 for(i = 0; i<ret->n_vars; i++) {
695 VARDESC *vardesc;
696 hres = ITypeInfo_GetVarDesc(pTypeInfo, i, &vardesc);
697 if(FAILED(hres)) {
698 WARN("GetVarDesc failed\n");
699 continue;
701 ret->fields[i].vt = vardesc->elemdescVar.tdesc.vt;
702 ret->fields[i].varkind = vardesc->varkind;
703 ret->fields[i].offset = vardesc->u.oInst;
704 hres = ITypeInfo_GetDocumentation(pTypeInfo, vardesc->memid, &ret->fields[i].name,
705 NULL, NULL, NULL);
706 if(FAILED(hres))
707 WARN("GetDocumentation failed: %08x\n", hres);
708 TRACE("field=%s, offset=%d\n", debugstr_w(ret->fields[i].name), ret->fields[i].offset);
709 ITypeInfo_ReleaseVarDesc(pTypeInfo, vardesc);
712 *ppRecInfo = &ret->IRecordInfo_iface;
714 return S_OK;