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 #define WIN32_NO_STATUS
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
34 #include <wine/unicode.h>
35 #include <wine/debug.h>
37 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
47 IRecordInfo IRecordInfo_iface
;
59 static inline IRecordInfoImpl
*impl_from_IRecordInfo(IRecordInfo
*iface
)
61 return CONTAINING_RECORD(iface
, IRecordInfoImpl
, IRecordInfo_iface
);
64 static HRESULT
copy_to_variant(void *src
, VARIANT
*pvar
, enum VARENUM vt
)
66 TRACE("%p %p %d\n", src
, pvar
, vt
);
68 #define CASE_COPY(x) \
70 memcpy(&V_ ## x(pvar), src, sizeof(V_ ## x(pvar))); \
95 FIXME("Not supported type: %d\n", vt
);
104 static HRESULT
copy_from_variant(VARIANT
*src
, void *dest
, enum VARENUM vt
)
109 TRACE("(%p(%d) %p %d)\n", src
, V_VT(src
), dest
, vt
);
111 hres
= VariantChangeType(&var
, src
, 0, vt
);
115 #define CASE_COPY(x) \
117 memcpy(dest, &V_ ## x(&var), sizeof(V_ ## x(&var))); \
142 FIXME("Not supported type: %d\n", V_VT(&var
));
149 static HRESULT WINAPI
IRecordInfoImpl_QueryInterface(IRecordInfo
*iface
, REFIID riid
,
152 TRACE("(%p)->(%s %p)\n", iface
, debugstr_guid(riid
), ppvObject
);
154 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IRecordInfo
, riid
)) {
156 IRecordInfo_AddRef(iface
);
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
);
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
);
181 for(i
=0; i
<This
->n_vars
; i
++)
182 SysFreeString(This
->fields
[i
].name
);
183 HeapFree(GetProcessHeap(), 0, This
->name
);
184 HeapFree(GetProcessHeap(), 0, This
->fields
);
185 ITypeInfo_Release(This
->pTypeInfo
);
186 HeapFree(GetProcessHeap(), 0, This
);
191 static HRESULT WINAPI
IRecordInfoImpl_RecordInit(IRecordInfo
*iface
, PVOID pvNew
)
193 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
194 TRACE("(%p)->(%p)\n", This
, pvNew
);
199 memset(pvNew
, 0, This
->size
);
203 static HRESULT WINAPI
IRecordInfoImpl_RecordClear(IRecordInfo
*iface
, PVOID pvExisting
)
205 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
209 TRACE("(%p)->(%p)\n", This
, pvExisting
);
214 for(i
=0; i
<This
->n_vars
; i
++) {
215 if(This
->fields
[i
].varkind
!= VAR_PERINSTANCE
) {
216 ERR("varkind != VAR_PERINSTANCE\n");
219 var
= ((PBYTE
)pvExisting
)+This
->fields
[i
].offset
;
220 switch(This
->fields
[i
].vt
) {
222 SysFreeString(*(BSTR
*)var
);
248 SafeArrayDestroy(var
);
251 FIXME("Not supported vt = %d\n", This
->fields
[i
].vt
);
259 static HRESULT WINAPI
IRecordInfoImpl_RecordCopy(IRecordInfo
*iface
, PVOID pvExisting
,
262 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
264 TRACE("(%p)->(%p %p)\n", This
, pvExisting
, pvNew
);
266 if(!pvExisting
|| !pvNew
)
269 memcpy(pvExisting
, pvNew
, This
->size
);
273 static HRESULT WINAPI
IRecordInfoImpl_GetGuid(IRecordInfo
*iface
, GUID
*pguid
)
275 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
277 TRACE("(%p)->(%p)\n", This
, pguid
);
286 static HRESULT WINAPI
IRecordInfoImpl_GetName(IRecordInfo
*iface
, BSTR
*pbstrName
)
288 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
290 TRACE("(%p)->(%p)\n", This
, pbstrName
);
295 *pbstrName
= SysAllocString(This
->name
);
299 static HRESULT WINAPI
IRecordInfoImpl_GetSize(IRecordInfo
*iface
, ULONG
*pcbSize
)
301 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
303 TRACE("(%p)->(%p)\n", This
, pcbSize
);
308 *pcbSize
= This
->size
;
312 static HRESULT WINAPI
IRecordInfoImpl_GetTypeInfo(IRecordInfo
*iface
, ITypeInfo
**ppTypeInfo
)
314 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
316 TRACE("(%p)->(%p)\n", This
, ppTypeInfo
);
321 ITypeInfo_AddRef(This
->pTypeInfo
);
322 *ppTypeInfo
= This
->pTypeInfo
;
327 static HRESULT WINAPI
IRecordInfoImpl_GetField(IRecordInfo
*iface
, PVOID pvData
,
328 LPCOLESTR szFieldName
, VARIANT
*pvarField
)
330 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
333 TRACE("(%p)->(%p %s %p)\n", This
, pvData
, debugstr_w(szFieldName
), pvarField
);
335 if(!pvData
|| !szFieldName
|| !pvarField
)
338 for(i
=0; i
<This
->n_vars
; i
++)
339 if(!strcmpW(This
->fields
[i
].name
, szFieldName
))
341 if(i
== This
->n_vars
)
342 return TYPE_E_FIELDNOTFOUND
;
344 VariantClear(pvarField
);
345 return copy_to_variant(((PBYTE
)pvData
)+This
->fields
[i
].offset
, pvarField
,
349 static HRESULT WINAPI
IRecordInfoImpl_GetFieldNoCopy(IRecordInfo
*iface
, PVOID pvData
,
350 LPCOLESTR szFieldName
, VARIANT
*pvarField
, PVOID
*ppvDataCArray
)
352 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
355 TRACE("(%p)->(%p %s %p %p)\n", This
, pvData
, debugstr_w(szFieldName
), pvarField
, ppvDataCArray
);
357 if(!pvData
|| !szFieldName
|| !pvarField
)
360 for(i
=0; i
<This
->n_vars
; i
++)
361 if(!strcmpW(This
->fields
[i
].name
, szFieldName
))
363 if(i
== This
->n_vars
)
364 return TYPE_E_FIELDNOTFOUND
;
366 VariantClear(pvarField
);
367 V_VT(pvarField
) = VT_BYREF
|This
->fields
[i
].vt
;
368 V_BYREF(pvarField
) = ((PBYTE
)pvData
)+This
->fields
[i
].offset
;
369 *ppvDataCArray
= NULL
;
373 static HRESULT WINAPI
IRecordInfoImpl_PutField(IRecordInfo
*iface
, ULONG wFlags
, PVOID pvData
,
374 LPCOLESTR szFieldName
, VARIANT
*pvarField
)
376 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
379 TRACE("(%p)->(%08x %p %s %p)\n", This
, wFlags
, pvData
, debugstr_w(szFieldName
),
382 if(!pvData
|| !szFieldName
|| !pvarField
383 || (wFlags
!= INVOKE_PROPERTYPUTREF
&& wFlags
!= INVOKE_PROPERTYPUT
))
386 if(wFlags
== INVOKE_PROPERTYPUTREF
) {
387 FIXME("wFlag == INVOKE_PROPERTYPUTREF not supported\n");
391 for(i
=0; i
<This
->n_vars
; i
++)
392 if(!strcmpW(This
->fields
[i
].name
, szFieldName
))
394 if(i
== This
->n_vars
)
395 return TYPE_E_FIELDNOTFOUND
;
397 return copy_from_variant(pvarField
, ((PBYTE
)pvData
)+This
->fields
[i
].offset
,
401 static HRESULT WINAPI
IRecordInfoImpl_PutFieldNoCopy(IRecordInfo
*iface
, ULONG wFlags
,
402 PVOID pvData
, LPCOLESTR szFieldName
, VARIANT
*pvarField
)
404 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
407 FIXME("(%p)->(%08x %p %s %p) stub\n", This
, wFlags
, pvData
, debugstr_w(szFieldName
), pvarField
);
409 if(!pvData
|| !szFieldName
|| !pvarField
410 || (wFlags
!= INVOKE_PROPERTYPUTREF
&& wFlags
!= INVOKE_PROPERTYPUT
))
413 for(i
=0; i
<This
->n_vars
; i
++)
414 if(!strcmpW(This
->fields
[i
].name
, szFieldName
))
416 if(i
== This
->n_vars
)
417 return TYPE_E_FIELDNOTFOUND
;
422 static HRESULT WINAPI
IRecordInfoImpl_GetFieldNames(IRecordInfo
*iface
, ULONG
*pcNames
,
425 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
426 ULONG n
= This
->n_vars
, i
;
428 TRACE("(%p)->(%p %p)\n", This
, pcNames
, rgBstrNames
);
438 rgBstrNames
[i
] = SysAllocString(This
->fields
[i
].name
);
445 static BOOL WINAPI
IRecordInfoImpl_IsMatchingType(IRecordInfo
*iface
, IRecordInfo
*info2
)
447 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
450 TRACE( "(%p)->(%p)\n", This
, info2
);
452 IRecordInfo_GetGuid( info2
, &guid2
);
453 if (IsEqualGUID( &This
->guid
, &guid2
)) return TRUE
;
455 FIXME( "records have different guids (%s %s) but could still match\n",
456 debugstr_guid( &This
->guid
), debugstr_guid( &guid2
) );
461 static PVOID WINAPI
IRecordInfoImpl_RecordCreate(IRecordInfo
*iface
)
463 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
465 TRACE("(%p)\n", This
);
467 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->size
);
470 static HRESULT WINAPI
IRecordInfoImpl_RecordCreateCopy(IRecordInfo
*iface
, PVOID pvSource
,
473 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
475 TRACE("(%p)->(%p %p)\n", This
, pvSource
, ppvDest
);
477 if(!pvSource
|| !ppvDest
)
480 *ppvDest
= IRecordInfo_RecordCreate(iface
);
481 return IRecordInfo_RecordCopy(iface
, pvSource
, *ppvDest
);
484 static HRESULT WINAPI
IRecordInfoImpl_RecordDestroy(IRecordInfo
*iface
, PVOID pvRecord
)
486 IRecordInfoImpl
*This
= impl_from_IRecordInfo(iface
);
489 TRACE("(%p)->(%p)\n", This
, pvRecord
);
491 hres
= IRecordInfo_RecordClear(iface
, pvRecord
);
495 if(!HeapFree(GetProcessHeap(), 0, pvRecord
))
501 static const IRecordInfoVtbl IRecordInfoImplVtbl
= {
502 IRecordInfoImpl_QueryInterface
,
503 IRecordInfoImpl_AddRef
,
504 IRecordInfoImpl_Release
,
505 IRecordInfoImpl_RecordInit
,
506 IRecordInfoImpl_RecordClear
,
507 IRecordInfoImpl_RecordCopy
,
508 IRecordInfoImpl_GetGuid
,
509 IRecordInfoImpl_GetName
,
510 IRecordInfoImpl_GetSize
,
511 IRecordInfoImpl_GetTypeInfo
,
512 IRecordInfoImpl_GetField
,
513 IRecordInfoImpl_GetFieldNoCopy
,
514 IRecordInfoImpl_PutField
,
515 IRecordInfoImpl_PutFieldNoCopy
,
516 IRecordInfoImpl_GetFieldNames
,
517 IRecordInfoImpl_IsMatchingType
,
518 IRecordInfoImpl_RecordCreate
,
519 IRecordInfoImpl_RecordCreateCopy
,
520 IRecordInfoImpl_RecordDestroy
523 /******************************************************************************
524 * GetRecordInfoFromGuids [OLEAUT32.322]
528 * Failure: E_INVALIDARG, if any argument is invalid.
530 HRESULT WINAPI
GetRecordInfoFromGuids(REFGUID rGuidTypeLib
, ULONG uVerMajor
,
531 ULONG uVerMinor
, LCID lcid
, REFGUID rGuidTypeInfo
, IRecordInfo
** ppRecInfo
)
533 ITypeInfo
*pTypeInfo
;
537 TRACE("(%p,%d,%d,%d,%p,%p)\n", rGuidTypeLib
, uVerMajor
, uVerMinor
,
538 lcid
, rGuidTypeInfo
, ppRecInfo
);
540 hres
= LoadRegTypeLib(rGuidTypeLib
, uVerMajor
, uVerMinor
, lcid
, &pTypeLib
);
542 WARN("LoadRegTypeLib failed!\n");
546 hres
= ITypeLib_GetTypeInfoOfGuid(pTypeLib
, rGuidTypeInfo
, &pTypeInfo
);
547 ITypeLib_Release(pTypeLib
);
549 WARN("GetTypeInfoOfGuid failed!\n");
553 hres
= GetRecordInfoFromTypeInfo(pTypeInfo
, ppRecInfo
);
554 ITypeInfo_Release(pTypeInfo
);
558 /******************************************************************************
559 * GetRecordInfoFromTypeInfo [OLEAUT32.332]
561 HRESULT WINAPI
GetRecordInfoFromTypeInfo(ITypeInfo
* pTI
, IRecordInfo
** ppRecInfo
) {
564 IRecordInfoImpl
*ret
;
565 ITypeInfo
*pTypeInfo
;
569 TRACE("(%p %p)\n", pTI
, ppRecInfo
);
571 if(!pTI
|| !ppRecInfo
)
574 hres
= ITypeInfo_GetTypeAttr(pTI
, &typeattr
);
575 if(FAILED(hres
) || !typeattr
) {
576 WARN("GetTypeAttr failed: %08x\n", hres
);
580 if(typeattr
->typekind
== TKIND_ALIAS
) {
581 hres
= ITypeInfo_GetRefTypeInfo(pTI
, typeattr
->tdescAlias
.u
.hreftype
, &pTypeInfo
);
582 guid
= typeattr
->guid
;
583 ITypeInfo_ReleaseTypeAttr(pTI
, typeattr
);
585 WARN("GetRefTypeInfo failed: %08x\n", hres
);
588 ITypeInfo_GetTypeAttr(pTypeInfo
, &typeattr
);
591 ITypeInfo_AddRef(pTypeInfo
);
592 guid
= typeattr
->guid
;
595 if(typeattr
->typekind
!= TKIND_RECORD
) {
596 WARN("typekind != TKIND_RECORD\n");
597 ITypeInfo_ReleaseTypeAttr(pTypeInfo
, typeattr
);
598 ITypeInfo_Release(pTypeInfo
);
602 ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ret
));
603 ret
->IRecordInfo_iface
.lpVtbl
= &IRecordInfoImplVtbl
;
605 ret
->pTypeInfo
= pTypeInfo
;
606 ret
->n_vars
= typeattr
->cVars
;
607 ret
->size
= typeattr
->cbSizeInstance
;
608 ITypeInfo_ReleaseTypeAttr(pTypeInfo
, typeattr
);
612 /* NOTE: Windows implementation calls ITypeInfo::GetCantainingTypeLib and
613 * ITypeLib::GetLibAttr, but we currently don't need this.
616 hres
= ITypeInfo_GetDocumentation(pTypeInfo
, MEMBERID_NIL
, &ret
->name
, NULL
, NULL
, NULL
);
618 WARN("ITypeInfo::GetDocumentation failed\n");
622 ret
->fields
= HeapAlloc(GetProcessHeap(), 0, ret
->n_vars
*sizeof(fieldstr
));
623 for(i
= 0; i
<ret
->n_vars
; i
++) {
625 hres
= ITypeInfo_GetVarDesc(pTypeInfo
, i
, &vardesc
);
627 WARN("GetVarDesc failed\n");
630 ret
->fields
[i
].vt
= vardesc
->elemdescVar
.tdesc
.vt
;
631 ret
->fields
[i
].varkind
= vardesc
->varkind
;
632 ret
->fields
[i
].offset
= vardesc
->u
.oInst
;
633 hres
= ITypeInfo_GetDocumentation(pTypeInfo
, vardesc
->memid
, &ret
->fields
[i
].name
,
636 WARN("GetDocumentation failed: %08x\n", hres
);
637 ITypeInfo_ReleaseVarDesc(pTypeInfo
, vardesc
);
640 *ppRecInfo
= &ret
->IRecordInfo_iface
;