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 *info2)
444 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
447 TRACE( "(%p)->(%p)\n", This, info2 );
449 IRecordInfo_GetGuid( info2, &guid2 );
450 if (IsEqualGUID( &This->guid, &guid2 )) return TRUE;
452 FIXME( "records have different guids (%s %s) but could still match\n",
453 debugstr_guid( &This->guid ), debugstr_guid( &guid2 ) );
458 static PVOID WINAPI IRecordInfoImpl_RecordCreate(IRecordInfo *iface)
460 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
462 TRACE("(%p)\n", This);
464 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->size);
467 static HRESULT WINAPI IRecordInfoImpl_RecordCreateCopy(IRecordInfo *iface, PVOID pvSource,
470 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
472 TRACE("(%p)->(%p %p)\n", This, pvSource, ppvDest);
474 if(!pvSource || !ppvDest)
477 *ppvDest = IRecordInfo_RecordCreate(iface);
478 return IRecordInfo_RecordCopy(iface, pvSource, *ppvDest);
481 static HRESULT WINAPI IRecordInfoImpl_RecordDestroy(IRecordInfo *iface, PVOID pvRecord)
483 IRecordInfoImpl *This = impl_from_IRecordInfo(iface);
486 TRACE("(%p)->(%p)\n", This, pvRecord);
488 hres = IRecordInfo_RecordClear(iface, pvRecord);
492 if(!HeapFree(GetProcessHeap(), 0, pvRecord))
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
520 /******************************************************************************
521 * GetRecordInfoFromGuids [OLEAUT32.322]
525 * Failure: E_INVALIDARG, if any argument is invalid.
527 HRESULT WINAPI GetRecordInfoFromGuids(REFGUID rGuidTypeLib, ULONG uVerMajor,
528 ULONG uVerMinor, LCID lcid, REFGUID rGuidTypeInfo, IRecordInfo** ppRecInfo)
530 ITypeInfo *pTypeInfo;
534 TRACE("(%p,%d,%d,%d,%p,%p)\n", rGuidTypeLib, uVerMajor, uVerMinor,
535 lcid, rGuidTypeInfo, ppRecInfo);
537 hres = LoadRegTypeLib(rGuidTypeLib, uVerMajor, uVerMinor, lcid, &pTypeLib);
539 WARN("LoadRegTypeLib failed!\n");
543 hres = ITypeLib_GetTypeInfoOfGuid(pTypeLib, rGuidTypeInfo, &pTypeInfo);
544 ITypeLib_Release(pTypeLib);
546 WARN("GetTypeInfoOfGuid failed!\n");
550 hres = GetRecordInfoFromTypeInfo(pTypeInfo, ppRecInfo);
551 ITypeInfo_Release(pTypeInfo);
555 /******************************************************************************
556 * GetRecordInfoFromTypeInfo [OLEAUT32.332]
558 HRESULT WINAPI GetRecordInfoFromTypeInfo(ITypeInfo* pTI, IRecordInfo** ppRecInfo) {
561 IRecordInfoImpl *ret;
562 ITypeInfo *pTypeInfo;
566 TRACE("(%p %p)\n", pTI, ppRecInfo);
568 if(!pTI || !ppRecInfo)
571 hres = ITypeInfo_GetTypeAttr(pTI, &typeattr);
572 if(FAILED(hres) || !typeattr) {
573 WARN("GetTypeAttr failed: %08x\n", hres);
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);
582 WARN("GetRefTypeInfo failed: %08x\n", hres);
585 ITypeInfo_GetTypeAttr(pTypeInfo, &typeattr);
588 ITypeInfo_AddRef(pTypeInfo);
589 guid = typeattr->guid;
592 if(typeattr->typekind != TKIND_RECORD) {
593 WARN("typekind != TKIND_RECORD\n");
594 ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr);
595 ITypeInfo_Release(pTypeInfo);
599 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
600 ret->IRecordInfo_iface.lpVtbl = &IRecordInfoImplVtbl;
602 ret->pTypeInfo = pTypeInfo;
603 ret->n_vars = typeattr->cVars;
604 ret->size = typeattr->cbSizeInstance;
605 ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr);
609 /* NOTE: Windows implementation calls ITypeInfo::GetCantainingTypeLib and
610 * ITypeLib::GetLibAttr, but we currently don't need this.
613 hres = ITypeInfo_GetDocumentation(pTypeInfo, MEMBERID_NIL, &ret->name, NULL, NULL, NULL);
615 WARN("ITypeInfo::GetDocumentation failed\n");
619 ret->fields = HeapAlloc(GetProcessHeap(), 0, ret->n_vars*sizeof(fieldstr));
620 for(i = 0; i<ret->n_vars; i++) {
622 hres = ITypeInfo_GetVarDesc(pTypeInfo, i, &vardesc);
624 WARN("GetVarDesc failed\n");
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,
633 WARN("GetDocumentation failed: %08x\n", hres);
634 ITypeInfo_ReleaseVarDesc(pTypeInfo, vardesc);
637 *ppRecInfo = &ret->IRecordInfo_iface;