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
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
43 IRecordInfo IRecordInfo_iface
;
55 static inline IRecordInfoImpl
*impl_from_IRecordInfo(IRecordInfo
*iface
)
57 return CONTAINING_RECORD(iface
, IRecordInfoImpl
, IRecordInfo_iface
);
60 static HRESULT
copy_to_variant(void *src
, VARIANT
*pvar
, enum VARENUM vt
)
62 TRACE("%p %p %d\n", src
, pvar
, vt
);
64 #define CASE_COPY(x) \
66 memcpy(&V_ ## x(pvar), src, sizeof(V_ ## x(pvar))); \
91 FIXME("Not supported type: %d\n", vt
);
100 static HRESULT
copy_from_variant(VARIANT
*src
, void *dest
, enum VARENUM vt
)
105 TRACE("(%p(%d) %p %d)\n", src
, V_VT(src
), dest
, vt
);
107 hres
= VariantChangeType(&var
, src
, 0, vt
);
111 #define CASE_COPY(x) \
113 memcpy(dest, &V_ ## x(&var), sizeof(V_ ## x(&var))); \
138 FIXME("Not supported type: %d\n", V_VT(&var
));
145 static HRESULT WINAPI
IRecordInfoImpl_QueryInterface(IRecordInfo
*iface
, REFIID riid
,
148 TRACE("(%p)->(%s %p)\n", iface
, debugstr_guid(riid
), ppvObject
);
152 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IRecordInfo
, riid
)) {
154 IRecordInfo_AddRef(iface
);
158 FIXME("Not supported interface: %s\n", debugstr_guid(riid
));
159 return E_NOINTERFACE
;
162 static ULONG WINAPI
IRecordInfoImpl_AddRef(IRecordInfo
*iface
)
164 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
165 ULONG ref
= InterlockedIncrement(&This
->ref
);
166 TRACE("%p, refcount %lu.\n", iface
, ref
);
170 static ULONG WINAPI
IRecordInfoImpl_Release(IRecordInfo
*iface
)
172 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
173 ULONG ref
= InterlockedDecrement(&This
->ref
);
175 TRACE("%p, refcount %lu.\n", iface
, ref
);
179 for(i
=0; i
<This
->n_vars
; i
++)
180 SysFreeString(This
->fields
[i
].name
);
181 SysFreeString(This
->name
);
182 HeapFree(GetProcessHeap(), 0, This
->fields
);
183 ITypeInfo_Release(This
->pTypeInfo
);
184 HeapFree(GetProcessHeap(), 0, This
);
189 static HRESULT WINAPI
IRecordInfoImpl_RecordInit(IRecordInfo
*iface
, PVOID pvNew
)
191 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
192 TRACE("(%p)->(%p)\n", This
, pvNew
);
197 memset(pvNew
, 0, This
->size
);
201 static HRESULT WINAPI
IRecordInfoImpl_RecordClear(IRecordInfo
*iface
, PVOID pvExisting
)
203 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
207 TRACE("(%p)->(%p)\n", This
, pvExisting
);
212 for(i
=0; i
<This
->n_vars
; i
++) {
213 if(This
->fields
[i
].varkind
!= VAR_PERINSTANCE
) {
214 ERR("varkind != VAR_PERINSTANCE\n");
217 var
= ((PBYTE
)pvExisting
)+This
->fields
[i
].offset
;
218 switch(This
->fields
[i
].vt
) {
220 SysFreeString(*(BSTR
*)var
);
247 SafeArrayDestroy(var
);
252 IUnknown
*unk
= *(IUnknown
**)var
;
254 IUnknown_Release(unk
);
259 FIXME("Not supported vt = %d\n", This
->fields
[i
].vt
);
267 static HRESULT WINAPI
IRecordInfoImpl_RecordCopy(IRecordInfo
*iface
, void *src_rec
, void *dest_rec
)
269 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
273 TRACE("(%p)->(%p %p)\n", This
, src_rec
, dest_rec
);
275 if(!src_rec
|| !dest_rec
)
278 /* release already stored data */
279 IRecordInfo_RecordClear(iface
, dest_rec
);
281 for (i
= 0; i
< This
->n_vars
; i
++)
285 if (This
->fields
[i
].varkind
!= VAR_PERINSTANCE
) {
286 ERR("varkind != VAR_PERINSTANCE\n");
290 src
= ((BYTE
*)src_rec
) + This
->fields
[i
].offset
;
291 dest
= ((BYTE
*)dest_rec
) + This
->fields
[i
].offset
;
292 switch (This
->fields
[i
].vt
)
296 BSTR src_str
= *(BSTR
*)src
;
300 BSTR str
= SysAllocString(*(BSTR
*)src
);
301 if (!str
) hr
= E_OUTOFMEMORY
;
312 IUnknown
*unk
= *(IUnknown
**)src
;
313 *(IUnknown
**)dest
= unk
;
314 if (unk
) IUnknown_AddRef(unk
);
318 hr
= SafeArrayCopy(src
, dest
);
322 /* copy directly for types that don't need deep copy */
323 int len
= get_type_size(NULL
, This
->fields
[i
].vt
);
324 memcpy(dest
, src
, len
);
329 if (FAILED(hr
)) break;
333 IRecordInfo_RecordClear(iface
, dest_rec
);
338 static HRESULT WINAPI
IRecordInfoImpl_GetGuid(IRecordInfo
*iface
, GUID
*pguid
)
340 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
342 TRACE("(%p)->(%p)\n", This
, pguid
);
351 static HRESULT WINAPI
IRecordInfoImpl_GetName(IRecordInfo
*iface
, BSTR
*pbstrName
)
353 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
355 TRACE("(%p)->(%p)\n", This
, pbstrName
);
360 *pbstrName
= SysAllocString(This
->name
);
364 static HRESULT WINAPI
IRecordInfoImpl_GetSize(IRecordInfo
*iface
, ULONG
*pcbSize
)
366 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
368 TRACE("(%p)->(%p)\n", This
, pcbSize
);
373 *pcbSize
= This
->size
;
377 static HRESULT WINAPI
IRecordInfoImpl_GetTypeInfo(IRecordInfo
*iface
, ITypeInfo
**ppTypeInfo
)
379 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
381 TRACE("(%p)->(%p)\n", This
, ppTypeInfo
);
386 ITypeInfo_AddRef(This
->pTypeInfo
);
387 *ppTypeInfo
= This
->pTypeInfo
;
392 static HRESULT WINAPI
IRecordInfoImpl_GetField(IRecordInfo
*iface
, PVOID pvData
,
393 LPCOLESTR szFieldName
, VARIANT
*pvarField
)
395 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
398 TRACE("(%p)->(%p %s %p)\n", This
, pvData
, debugstr_w(szFieldName
), pvarField
);
400 if(!pvData
|| !szFieldName
|| !pvarField
)
403 for(i
=0; i
<This
->n_vars
; i
++)
404 if(!wcscmp(This
->fields
[i
].name
, szFieldName
))
406 if(i
== This
->n_vars
)
407 return TYPE_E_FIELDNOTFOUND
;
409 VariantClear(pvarField
);
410 return copy_to_variant(((PBYTE
)pvData
)+This
->fields
[i
].offset
, pvarField
,
414 static HRESULT WINAPI
IRecordInfoImpl_GetFieldNoCopy(IRecordInfo
*iface
, PVOID pvData
,
415 LPCOLESTR szFieldName
, VARIANT
*pvarField
, PVOID
*ppvDataCArray
)
417 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
420 TRACE("(%p)->(%p %s %p %p)\n", This
, pvData
, debugstr_w(szFieldName
), pvarField
, ppvDataCArray
);
422 if(!pvData
|| !szFieldName
|| !pvarField
)
425 for(i
=0; i
<This
->n_vars
; i
++)
426 if(!wcscmp(This
->fields
[i
].name
, szFieldName
))
428 if(i
== This
->n_vars
)
429 return TYPE_E_FIELDNOTFOUND
;
431 VariantClear(pvarField
);
432 V_VT(pvarField
) = VT_BYREF
|This
->fields
[i
].vt
;
433 V_BYREF(pvarField
) = ((PBYTE
)pvData
)+This
->fields
[i
].offset
;
434 *ppvDataCArray
= NULL
;
438 static HRESULT WINAPI
IRecordInfoImpl_PutField(IRecordInfo
*iface
, ULONG wFlags
, PVOID pvData
,
439 LPCOLESTR szFieldName
, VARIANT
*pvarField
)
441 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
444 TRACE("%p, %#lx, %p, %s, %p.\n", iface
, wFlags
, pvData
, debugstr_w(szFieldName
), pvarField
);
446 if(!pvData
|| !szFieldName
|| !pvarField
447 || (wFlags
!= INVOKE_PROPERTYPUTREF
&& wFlags
!= INVOKE_PROPERTYPUT
))
450 if(wFlags
== INVOKE_PROPERTYPUTREF
) {
451 FIXME("wFlag == INVOKE_PROPERTYPUTREF not supported\n");
455 for(i
=0; i
<This
->n_vars
; i
++)
456 if(!wcscmp(This
->fields
[i
].name
, szFieldName
))
458 if(i
== This
->n_vars
)
459 return TYPE_E_FIELDNOTFOUND
;
461 return copy_from_variant(pvarField
, ((PBYTE
)pvData
)+This
->fields
[i
].offset
,
465 static HRESULT WINAPI
IRecordInfoImpl_PutFieldNoCopy(IRecordInfo
*iface
, ULONG wFlags
,
466 PVOID pvData
, LPCOLESTR szFieldName
, VARIANT
*pvarField
)
468 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
471 FIXME("%p, %#lx, %p, %s, %p stub\n", iface
, wFlags
, pvData
, debugstr_w(szFieldName
), pvarField
);
473 if(!pvData
|| !szFieldName
|| !pvarField
474 || (wFlags
!= INVOKE_PROPERTYPUTREF
&& wFlags
!= INVOKE_PROPERTYPUT
))
477 for(i
=0; i
<This
->n_vars
; i
++)
478 if(!wcscmp(This
->fields
[i
].name
, szFieldName
))
480 if(i
== This
->n_vars
)
481 return TYPE_E_FIELDNOTFOUND
;
486 static HRESULT WINAPI
IRecordInfoImpl_GetFieldNames(IRecordInfo
*iface
, ULONG
*pcNames
,
489 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
490 ULONG n
= This
->n_vars
, i
;
492 TRACE("(%p)->(%p %p)\n", This
, pcNames
, rgBstrNames
);
502 rgBstrNames
[i
] = SysAllocString(This
->fields
[i
].name
);
509 static BOOL WINAPI
IRecordInfoImpl_IsMatchingType(IRecordInfo
*iface
, IRecordInfo
*info2
)
511 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
514 TRACE( "(%p)->(%p)\n", This
, info2
);
516 IRecordInfo_GetGuid( info2
, &guid2
);
517 return IsEqualGUID( &This
->guid
, &guid2
);
520 static PVOID WINAPI
IRecordInfoImpl_RecordCreate(IRecordInfo
*iface
)
522 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
525 TRACE("(%p)\n", This
);
527 record
= HeapAlloc(GetProcessHeap(), 0, This
->size
);
528 IRecordInfo_RecordInit(iface
, record
);
529 TRACE("created record at %p\n", record
);
533 static HRESULT WINAPI
IRecordInfoImpl_RecordCreateCopy(IRecordInfo
*iface
, PVOID pvSource
,
536 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
538 TRACE("(%p)->(%p %p)\n", This
, pvSource
, ppvDest
);
540 if(!pvSource
|| !ppvDest
)
543 *ppvDest
= IRecordInfo_RecordCreate(iface
);
544 return IRecordInfo_RecordCopy(iface
, pvSource
, *ppvDest
);
547 static HRESULT WINAPI
IRecordInfoImpl_RecordDestroy(IRecordInfo
*iface
, PVOID pvRecord
)
549 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
552 TRACE("(%p)->(%p)\n", This
, pvRecord
);
554 hres
= IRecordInfo_RecordClear(iface
, pvRecord
);
558 if(!HeapFree(GetProcessHeap(), 0, pvRecord
))
564 static const IRecordInfoVtbl IRecordInfoImplVtbl
= {
565 IRecordInfoImpl_QueryInterface
,
566 IRecordInfoImpl_AddRef
,
567 IRecordInfoImpl_Release
,
568 IRecordInfoImpl_RecordInit
,
569 IRecordInfoImpl_RecordClear
,
570 IRecordInfoImpl_RecordCopy
,
571 IRecordInfoImpl_GetGuid
,
572 IRecordInfoImpl_GetName
,
573 IRecordInfoImpl_GetSize
,
574 IRecordInfoImpl_GetTypeInfo
,
575 IRecordInfoImpl_GetField
,
576 IRecordInfoImpl_GetFieldNoCopy
,
577 IRecordInfoImpl_PutField
,
578 IRecordInfoImpl_PutFieldNoCopy
,
579 IRecordInfoImpl_GetFieldNames
,
580 IRecordInfoImpl_IsMatchingType
,
581 IRecordInfoImpl_RecordCreate
,
582 IRecordInfoImpl_RecordCreateCopy
,
583 IRecordInfoImpl_RecordDestroy
586 /******************************************************************************
587 * GetRecordInfoFromGuids [OLEAUT32.322]
591 * Failure: E_INVALIDARG, if any argument is invalid.
593 HRESULT WINAPI
GetRecordInfoFromGuids(REFGUID rGuidTypeLib
, ULONG uVerMajor
,
594 ULONG uVerMinor
, LCID lcid
, REFGUID rGuidTypeInfo
, IRecordInfo
** ppRecInfo
)
596 ITypeInfo
*pTypeInfo
;
600 TRACE("%p, %lu, %lu, %#lx, %s, %p.\n", rGuidTypeLib
, uVerMajor
, uVerMinor
,
601 lcid
, debugstr_guid(rGuidTypeInfo
), ppRecInfo
);
603 hres
= LoadRegTypeLib(rGuidTypeLib
, uVerMajor
, uVerMinor
, lcid
, &pTypeLib
);
605 WARN("LoadRegTypeLib failed!\n");
609 hres
= ITypeLib_GetTypeInfoOfGuid(pTypeLib
, rGuidTypeInfo
, &pTypeInfo
);
610 ITypeLib_Release(pTypeLib
);
612 WARN("GetTypeInfoOfGuid failed!\n");
616 hres
= GetRecordInfoFromTypeInfo(pTypeInfo
, ppRecInfo
);
617 ITypeInfo_Release(pTypeInfo
);
621 /******************************************************************************
622 * GetRecordInfoFromTypeInfo [OLEAUT32.332]
624 HRESULT WINAPI
GetRecordInfoFromTypeInfo(ITypeInfo
* pTI
, IRecordInfo
** ppRecInfo
) {
627 IRecordInfoImpl
*ret
;
628 ITypeInfo
*pTypeInfo
;
632 TRACE("(%p %p)\n", pTI
, ppRecInfo
);
634 if(!pTI
|| !ppRecInfo
)
637 hres
= ITypeInfo_GetTypeAttr(pTI
, &typeattr
);
638 if(FAILED(hres
) || !typeattr
) {
639 WARN("GetTypeAttr failed: %#lx.\n", hres
);
643 if(typeattr
->typekind
== TKIND_ALIAS
) {
644 hres
= ITypeInfo_GetRefTypeInfo(pTI
, typeattr
->tdescAlias
.u
.hreftype
, &pTypeInfo
);
645 guid
= typeattr
->guid
;
646 ITypeInfo_ReleaseTypeAttr(pTI
, typeattr
);
648 WARN("GetRefTypeInfo failed: %#lx.\n", hres
);
651 hres
= ITypeInfo_GetTypeAttr(pTypeInfo
, &typeattr
);
653 ITypeInfo_Release(pTypeInfo
);
654 WARN("GetTypeAttr failed for referenced type: %#lx.\n", hres
);
659 ITypeInfo_AddRef(pTypeInfo
);
660 guid
= typeattr
->guid
;
663 if(typeattr
->typekind
!= TKIND_RECORD
) {
664 WARN("typekind != TKIND_RECORD\n");
665 ITypeInfo_ReleaseTypeAttr(pTypeInfo
, typeattr
);
666 ITypeInfo_Release(pTypeInfo
);
670 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ret
));
671 ret
->IRecordInfo_iface
.lpVtbl
= &IRecordInfoImplVtbl
;
673 ret
->pTypeInfo
= pTypeInfo
;
674 ret
->n_vars
= typeattr
->cVars
;
675 ret
->size
= typeattr
->cbSizeInstance
;
676 ITypeInfo_ReleaseTypeAttr(pTypeInfo
, typeattr
);
680 /* NOTE: Windows implementation calls ITypeInfo::GetCantainingTypeLib and
681 * ITypeLib::GetLibAttr, but we currently don't need this.
684 hres
= ITypeInfo_GetDocumentation(pTypeInfo
, MEMBERID_NIL
, &ret
->name
, NULL
, NULL
, NULL
);
686 WARN("ITypeInfo::GetDocumentation failed\n");
690 ret
->fields
= HeapAlloc(GetProcessHeap(), 0, ret
->n_vars
*sizeof(fieldstr
));
691 for(i
= 0; i
<ret
->n_vars
; i
++) {
693 hres
= ITypeInfo_GetVarDesc(pTypeInfo
, i
, &vardesc
);
695 WARN("GetVarDesc failed\n");
698 ret
->fields
[i
].vt
= vardesc
->elemdescVar
.tdesc
.vt
;
699 ret
->fields
[i
].varkind
= vardesc
->varkind
;
700 ret
->fields
[i
].offset
= vardesc
->u
.oInst
;
701 hres
= ITypeInfo_GetDocumentation(pTypeInfo
, vardesc
->memid
, &ret
->fields
[i
].name
,
704 WARN("GetDocumentation failed: %#lx.\n", hres
);
705 TRACE("field=%s, offset=%ld\n", debugstr_w(ret
->fields
[i
].name
), ret
->fields
[i
].offset
);
706 ITypeInfo_ReleaseVarDesc(pTypeInfo
, vardesc
);
709 *ppRecInfo
= &ret
->IRecordInfo_iface
;