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
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(ole);
44 IRecordInfo IRecordInfo_iface;
56 static inline IRecordInfoImpl *impl_from_IRecordInfo(IRecordInfo *iface)
58 return CONTAINING_RECORD(iface, IRecordInfoImpl, IRecordInfo_iface);
61 static HRESULT copy_to_variant(void *src, VARIANT *pvar, enum VARENUM vt)
63 TRACE("%p %p %d\n", src, pvar, vt);
65 #define CASE_COPY(x) \
67 memcpy(&V_ ## x(pvar), src, sizeof(V_ ## x(pvar))); \
92 FIXME("Not supported type: %d\n", vt);
101 static HRESULT copy_from_variant(VARIANT *src, void *dest, enum VARENUM vt)
106 TRACE("(%p(%d) %p %d)\n", src, V_VT(src), dest, vt);
108 hres = VariantChangeType(&var, src, 0, vt);
112 #define CASE_COPY(x) \
114 memcpy(dest, &V_ ## x(&var), sizeof(V_ ## x(&var))); \
139 FIXME("Not supported type: %d\n", V_VT(&var));
146 static HRESULT WINAPI IRecordInfoImpl_QueryInterface(IRecordInfo *iface, REFIID riid,
149 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
151 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRecordInfo, riid)) {
153 IRecordInfo_AddRef(iface);
157 FIXME("Not supported interface: %s\n", debugstr_guid(riid));
158 return E_NOINTERFACE;
161 static ULONG WINAPI IRecordInfoImpl_AddRef(IRecordInfo *iface)
163 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
164 ULONG ref = InterlockedIncrement(&This->ref);
165 TRACE("(%p) -> %d\n", This, ref);
169 static ULONG WINAPI IRecordInfoImpl_Release(IRecordInfo *iface)
171 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
172 ULONG ref = InterlockedDecrement(&This->ref);
174 TRACE("(%p) -> %d\n", This, ref);
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);
188 static HRESULT WINAPI IRecordInfoImpl_RecordInit(IRecordInfo *iface, PVOID pvNew)
190 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
191 TRACE("(%p)->(%p)\n", This, pvNew);
196 memset(pvNew, 0, This->size);
200 static HRESULT WINAPI IRecordInfoImpl_RecordClear(IRecordInfo *iface, PVOID pvExisting)
202 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
206 TRACE("(%p)->(%p)\n", This, pvExisting);
211 for(i=0; i<This->n_vars; i++) {
212 if(This->fields[i].varkind != VAR_PERINSTANCE) {
213 ERR("varkind != VAR_PERINSTANCE\n");
216 var = ((PBYTE)pvExisting)+This->fields[i].offset;
217 switch(This->fields[i].vt) {
219 SysFreeString(*(BSTR*)var);
245 SafeArrayDestroy(var);
248 FIXME("Not supported vt = %d\n", This->fields[i].vt);
256 static HRESULT WINAPI IRecordInfoImpl_RecordCopy(IRecordInfo *iface, PVOID pvExisting,
259 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
261 TRACE("(%p)->(%p %p)\n", This, pvExisting, pvNew);
263 if(!pvExisting || !pvNew)
266 memcpy(pvExisting, pvNew, This->size);
270 static HRESULT WINAPI IRecordInfoImpl_GetGuid(IRecordInfo *iface, GUID *pguid)
272 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
274 TRACE("(%p)->(%p)\n", This, pguid);
283 static HRESULT WINAPI IRecordInfoImpl_GetName(IRecordInfo *iface, BSTR *pbstrName)
285 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
287 TRACE("(%p)->(%p)\n", This, pbstrName);
292 *pbstrName = SysAllocString(This->name);
296 static HRESULT WINAPI IRecordInfoImpl_GetSize(IRecordInfo *iface, ULONG *pcbSize)
298 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
300 TRACE("(%p)->(%p)\n", This, pcbSize);
305 *pcbSize = This->size;
309 static HRESULT WINAPI IRecordInfoImpl_GetTypeInfo(IRecordInfo *iface, ITypeInfo **ppTypeInfo)
311 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
313 TRACE("(%p)->(%p)\n", This, ppTypeInfo);
318 ITypeInfo_AddRef(This->pTypeInfo);
319 *ppTypeInfo = This->pTypeInfo;
324 static HRESULT WINAPI IRecordInfoImpl_GetField(IRecordInfo *iface, PVOID pvData,
325 LPCOLESTR szFieldName, VARIANT *pvarField)
327 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
330 TRACE("(%p)->(%p %s %p)\n", This, pvData, debugstr_w(szFieldName), pvarField);
332 if(!pvData || !szFieldName || !pvarField)
335 for(i=0; i<This->n_vars; i++)
336 if(!strcmpW(This->fields[i].name, szFieldName))
338 if(i == This->n_vars)
339 return TYPE_E_FIELDNOTFOUND;
341 VariantClear(pvarField);
342 return copy_to_variant(((PBYTE)pvData)+This->fields[i].offset, pvarField,
346 static HRESULT WINAPI IRecordInfoImpl_GetFieldNoCopy(IRecordInfo *iface, PVOID pvData,
347 LPCOLESTR szFieldName, VARIANT *pvarField, PVOID *ppvDataCArray)
349 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
352 TRACE("(%p)->(%p %s %p %p)\n", This, pvData, debugstr_w(szFieldName), pvarField, ppvDataCArray);
354 if(!pvData || !szFieldName || !pvarField)
357 for(i=0; i<This->n_vars; i++)
358 if(!strcmpW(This->fields[i].name, szFieldName))
360 if(i == This->n_vars)
361 return TYPE_E_FIELDNOTFOUND;
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;
370 static HRESULT WINAPI IRecordInfoImpl_PutField(IRecordInfo *iface, ULONG wFlags, PVOID pvData,
371 LPCOLESTR szFieldName, VARIANT *pvarField)
373 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
376 TRACE("(%p)->(%08x %p %s %p)\n", This, wFlags, pvData, debugstr_w(szFieldName),
379 if(!pvData || !szFieldName || !pvarField
380 || (wFlags != INVOKE_PROPERTYPUTREF && wFlags != INVOKE_PROPERTYPUT))
383 if(wFlags == INVOKE_PROPERTYPUTREF) {
384 FIXME("wFlag == INVOKE_PROPERTYPUTREF not supported\n");
388 for(i=0; i<This->n_vars; i++)
389 if(!strcmpW(This->fields[i].name, szFieldName))
391 if(i == This->n_vars)
392 return TYPE_E_FIELDNOTFOUND;
394 return copy_from_variant(pvarField, ((PBYTE)pvData)+This->fields[i].offset,
398 static HRESULT WINAPI IRecordInfoImpl_PutFieldNoCopy(IRecordInfo *iface, ULONG wFlags,
399 PVOID pvData, LPCOLESTR szFieldName, VARIANT *pvarField)
401 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
404 FIXME("(%p)->(%08x %p %s %p) stub\n", This, wFlags, pvData, debugstr_w(szFieldName), pvarField);
406 if(!pvData || !szFieldName || !pvarField
407 || (wFlags != INVOKE_PROPERTYPUTREF && wFlags != INVOKE_PROPERTYPUT))
410 for(i=0; i<This->n_vars; i++)
411 if(!strcmpW(This->fields[i].name, szFieldName))
413 if(i == This->n_vars)
414 return TYPE_E_FIELDNOTFOUND;
419 static HRESULT WINAPI IRecordInfoImpl_GetFieldNames(IRecordInfo *iface, ULONG *pcNames,
422 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
423 ULONG n = This->n_vars, i;
425 TRACE("(%p)->(%p %p)\n", This, pcNames, rgBstrNames);
435 rgBstrNames[i] = SysAllocString(This->fields[i].name);
442 static BOOL WINAPI IRecordInfoImpl_IsMatchingType(IRecordInfo *iface, IRecordInfo *pRecordInfo)
444 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
446 FIXME("(%p)->(%p) stub\n", This, pRecordInfo);
451 static PVOID WINAPI IRecordInfoImpl_RecordCreate(IRecordInfo *iface)
453 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
455 TRACE("(%p)\n", This);
457 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->size);
460 static HRESULT WINAPI IRecordInfoImpl_RecordCreateCopy(IRecordInfo *iface, PVOID pvSource,
463 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
465 TRACE("(%p)->(%p %p)\n", This, pvSource, ppvDest);
467 if(!pvSource || !ppvDest)
470 *ppvDest = IRecordInfo_RecordCreate(iface);
471 return IRecordInfo_RecordCopy(iface, pvSource, *ppvDest);
474 static HRESULT WINAPI IRecordInfoImpl_RecordDestroy(IRecordInfo *iface, PVOID pvRecord)
476 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
479 TRACE("(%p)->(%p)\n", This, pvRecord);
481 hres = IRecordInfo_RecordClear(iface, pvRecord);
485 if(!HeapFree(GetProcessHeap(), 0, pvRecord))
491 static const IRecordInfoVtbl IRecordInfoImplVtbl = {
492 IRecordInfoImpl_QueryInterface,
493 IRecordInfoImpl_AddRef,
494 IRecordInfoImpl_Release,
495 IRecordInfoImpl_RecordInit,
496 IRecordInfoImpl_RecordClear,
497 IRecordInfoImpl_RecordCopy,
498 IRecordInfoImpl_GetGuid,
499 IRecordInfoImpl_GetName,
500 IRecordInfoImpl_GetSize,
501 IRecordInfoImpl_GetTypeInfo,
502 IRecordInfoImpl_GetField,
503 IRecordInfoImpl_GetFieldNoCopy,
504 IRecordInfoImpl_PutField,
505 IRecordInfoImpl_PutFieldNoCopy,
506 IRecordInfoImpl_GetFieldNames,
507 IRecordInfoImpl_IsMatchingType,
508 IRecordInfoImpl_RecordCreate,
509 IRecordInfoImpl_RecordCreateCopy,
510 IRecordInfoImpl_RecordDestroy
513 /******************************************************************************
514 * GetRecordInfoFromGuids [OLEAUT32.322]
518 * Failure: E_INVALIDARG, if any argument is invalid.
520 HRESULT WINAPI GetRecordInfoFromGuids(REFGUID rGuidTypeLib, ULONG uVerMajor,
521 ULONG uVerMinor, LCID lcid, REFGUID rGuidTypeInfo, IRecordInfo** ppRecInfo)
523 ITypeInfo *pTypeInfo;
527 TRACE("(%p,%d,%d,%d,%p,%p)\n", rGuidTypeLib, uVerMajor, uVerMinor,
528 lcid, rGuidTypeInfo, ppRecInfo);
530 hres = LoadRegTypeLib(rGuidTypeLib, uVerMajor, uVerMinor, lcid, &pTypeLib);
532 WARN("LoadRegTypeLib failed!\n");
536 hres = ITypeLib_GetTypeInfoOfGuid(pTypeLib, rGuidTypeInfo, &pTypeInfo);
537 ITypeLib_Release(pTypeLib);
539 WARN("GetTypeInfoOfGuid failed!\n");
543 hres = GetRecordInfoFromTypeInfo(pTypeInfo, ppRecInfo);
544 ITypeInfo_Release(pTypeInfo);
548 /******************************************************************************
549 * GetRecordInfoFromTypeInfo [OLEAUT32.332]
551 HRESULT WINAPI GetRecordInfoFromTypeInfo(ITypeInfo* pTI, IRecordInfo** ppRecInfo) {
554 IRecordInfoImpl *ret;
555 ITypeInfo *pTypeInfo;
559 TRACE("(%p %p)\n", pTI, ppRecInfo);
561 if(!pTI || !ppRecInfo)
564 hres = ITypeInfo_GetTypeAttr(pTI, &typeattr);
565 if(FAILED(hres) || !typeattr) {
566 WARN("GetTypeAttr failed: %08x\n", hres);
570 if(typeattr->typekind == TKIND_ALIAS) {
571 hres = ITypeInfo_GetRefTypeInfo(pTI, typeattr->tdescAlias.u.hreftype, &pTypeInfo);
572 guid = typeattr->guid;
573 ITypeInfo_ReleaseTypeAttr(pTI, typeattr);
575 WARN("GetRefTypeInfo failed: %08x\n", hres);
578 ITypeInfo_GetTypeAttr(pTypeInfo, &typeattr);
581 ITypeInfo_AddRef(pTypeInfo);
582 guid = typeattr->guid;
585 if(typeattr->typekind != TKIND_RECORD) {
586 WARN("typekind != TKIND_RECORD\n");
587 ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr);
588 ITypeInfo_Release(pTypeInfo);
592 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
593 ret->IRecordInfo_iface.lpVtbl = &IRecordInfoImplVtbl;
595 ret->pTypeInfo = pTypeInfo;
596 ret->n_vars = typeattr->cVars;
597 ret->size = typeattr->cbSizeInstance;
598 ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr);
602 /* NOTE: Windows implementation calls ITypeInfo::GetCantainingTypeLib and
603 * ITypeLib::GetLibAttr, but we currently don't need this.
606 hres = ITypeInfo_GetDocumentation(pTypeInfo, MEMBERID_NIL, &ret->name, NULL, NULL, NULL);
608 WARN("ITypeInfo::GetDocumentation failed\n");
612 ret->fields = HeapAlloc(GetProcessHeap(), 0, ret->n_vars*sizeof(VARDESC));
613 for(i = 0; i<ret->n_vars; i++) {
615 hres = ITypeInfo_GetVarDesc(pTypeInfo, i, &vardesc);
617 WARN("GetVarDesc failed\n");
620 ret->fields[i].vt = vardesc->elemdescVar.tdesc.vt;
621 ret->fields[i].varkind = vardesc->varkind;
622 ret->fields[i].offset = vardesc->u.oInst;
623 hres = ITypeInfo_GetDocumentation(pTypeInfo, vardesc->memid, &ret->fields[i].name,
626 WARN("GetDocumentation failed: %08x\n", hres);
627 ITypeInfo_ReleaseVarDesc(pTypeInfo, vardesc);
630 *ppRecInfo = &ret->IRecordInfo_iface;