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 const IRecordInfoVtbl *lpVtbl;
56 static HRESULT copy_to_variant(void *src, VARIANT *pvar, enum VARENUM vt)
58 TRACE("%p %p %d\n", src, pvar, vt);
60 #define CASE_COPY(x) \
62 memcpy(&V_ ## x(pvar), src, sizeof(V_ ## x(pvar))); \
87 FIXME("Not supported type: %d\n", vt);
96 static HRESULT copy_from_variant(VARIANT *src, void *dest, enum VARENUM vt)
101 TRACE("(%p(%d) %p %d)\n", src, V_VT(src), dest, vt);
103 hres = VariantChangeType(&var, src, 0, vt);
107 #define CASE_COPY(x) \
109 memcpy(dest, &V_ ## x(&var), sizeof(V_ ## x(&var))); \
134 FIXME("Not supported type: %d\n", V_VT(&var));
141 static HRESULT WINAPI IRecordInfoImpl_QueryInterface(IRecordInfo *iface, REFIID riid,
144 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
146 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRecordInfo, riid)) {
148 IRecordInfo_AddRef(iface);
152 FIXME("Not supported interface: %s\n", debugstr_guid(riid));
153 return E_NOINTERFACE;
156 static ULONG WINAPI IRecordInfoImpl_AddRef(IRecordInfo *iface)
158 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
159 ULONG ref = InterlockedIncrement(&This->ref);
160 TRACE("(%p) -> %d\n", This, ref);
164 static ULONG WINAPI IRecordInfoImpl_Release(IRecordInfo *iface)
166 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
167 ULONG ref = InterlockedDecrement(&This->ref);
169 TRACE("(%p) -> %d\n", This, ref);
173 for(i=0; i<This->n_vars; i++)
174 SysFreeString(This->fields[i].name);
175 HeapFree(GetProcessHeap(), 0, This->name);
176 HeapFree(GetProcessHeap(), 0, This->fields);
177 ITypeInfo_Release(This->pTypeInfo);
178 HeapFree(GetProcessHeap(), 0, This);
183 static HRESULT WINAPI IRecordInfoImpl_RecordInit(IRecordInfo *iface, PVOID pvNew)
185 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
186 TRACE("(%p)->(%p)\n", This, pvNew);
191 memset(pvNew, 0, This->size);
195 static HRESULT WINAPI IRecordInfoImpl_RecordClear(IRecordInfo *iface, PVOID pvExisting)
197 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
201 TRACE("(%p)->(%p)\n", This, pvExisting);
206 for(i=0; i<This->n_vars; i++) {
207 if(This->fields[i].varkind != VAR_PERINSTANCE) {
208 ERR("varkind != VAR_PERINSTANCE\n");
211 var = ((PBYTE)pvExisting)+This->fields[i].offset;
212 switch(This->fields[i].vt) {
214 SysFreeString(*(BSTR*)var);
240 SafeArrayDestroy(var);
243 FIXME("Not supported vt = %d\n", This->fields[i].vt);
251 static HRESULT WINAPI IRecordInfoImpl_RecordCopy(IRecordInfo *iface, PVOID pvExisting,
254 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
256 TRACE("(%p)->(%p %p)\n", This, pvExisting, pvNew);
258 if(!pvExisting || !pvNew)
261 memcpy(pvExisting, pvNew, This->size);
265 static HRESULT WINAPI IRecordInfoImpl_GetGuid(IRecordInfo *iface, GUID *pguid)
267 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
269 TRACE("(%p)->(%p)\n", This, pguid);
278 static HRESULT WINAPI IRecordInfoImpl_GetName(IRecordInfo *iface, BSTR *pbstrName)
280 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
282 TRACE("(%p)->(%p)\n", This, pbstrName);
287 *pbstrName = SysAllocString(This->name);
291 static HRESULT WINAPI IRecordInfoImpl_GetSize(IRecordInfo *iface, ULONG *pcbSize)
293 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
295 TRACE("(%p)->(%p)\n", This, pcbSize);
300 *pcbSize = This->size;
304 static HRESULT WINAPI IRecordInfoImpl_GetTypeInfo(IRecordInfo *iface, ITypeInfo **ppTypeInfo)
306 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
308 TRACE("(%p)->(%p)\n", This, ppTypeInfo);
313 ITypeInfo_AddRef(This->pTypeInfo);
314 *ppTypeInfo = This->pTypeInfo;
319 static HRESULT WINAPI IRecordInfoImpl_GetField(IRecordInfo *iface, PVOID pvData,
320 LPCOLESTR szFieldName, VARIANT *pvarField)
322 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
325 TRACE("(%p)->(%p %s %p)\n", This, pvData, debugstr_w(szFieldName), pvarField);
327 if(!pvData || !szFieldName || !pvarField)
330 for(i=0; i<This->n_vars; i++)
331 if(!strcmpW(This->fields[i].name, szFieldName))
333 if(i == This->n_vars)
334 return TYPE_E_FIELDNOTFOUND;
336 VariantClear(pvarField);
337 return copy_to_variant(((PBYTE)pvData)+This->fields[i].offset, pvarField,
341 static HRESULT WINAPI IRecordInfoImpl_GetFieldNoCopy(IRecordInfo *iface, PVOID pvData,
342 LPCOLESTR szFieldName, VARIANT *pvarField, PVOID *ppvDataCArray)
344 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
347 TRACE("(%p)->(%p %s %p %p)\n", This, pvData, debugstr_w(szFieldName), pvarField, ppvDataCArray);
349 if(!pvData || !szFieldName || !pvarField)
352 for(i=0; i<This->n_vars; i++)
353 if(!strcmpW(This->fields[i].name, szFieldName))
355 if(i == This->n_vars)
356 return TYPE_E_FIELDNOTFOUND;
358 VariantClear(pvarField);
359 V_VT(pvarField) = VT_BYREF|This->fields[i].vt;
360 V_BYREF(pvarField) = ((PBYTE)pvData)+This->fields[i].offset;
361 *ppvDataCArray = NULL;
365 static HRESULT WINAPI IRecordInfoImpl_PutField(IRecordInfo *iface, ULONG wFlags, PVOID pvData,
366 LPCOLESTR szFieldName, VARIANT *pvarField)
368 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
371 TRACE("(%p)->(%08x %p %s %p)\n", This, wFlags, pvData, debugstr_w(szFieldName),
374 if(!pvData || !szFieldName || !pvarField
375 || (wFlags != INVOKE_PROPERTYPUTREF && wFlags != INVOKE_PROPERTYPUT))
378 if(wFlags == INVOKE_PROPERTYPUTREF) {
379 FIXME("wFlag == INVOKE_PROPERTYPUTREF not supported\n");
383 for(i=0; i<This->n_vars; i++)
384 if(!strcmpW(This->fields[i].name, szFieldName))
386 if(i == This->n_vars)
387 return TYPE_E_FIELDNOTFOUND;
389 return copy_from_variant(pvarField, ((PBYTE)pvData)+This->fields[i].offset,
393 static HRESULT WINAPI IRecordInfoImpl_PutFieldNoCopy(IRecordInfo *iface, ULONG wFlags,
394 PVOID pvData, LPCOLESTR szFieldName, VARIANT *pvarField)
396 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
399 FIXME("(%p)->(%08x %p %s %p) stub\n", This, wFlags, pvData, debugstr_w(szFieldName), pvarField);
401 if(!pvData || !szFieldName || !pvarField
402 || (wFlags != INVOKE_PROPERTYPUTREF && wFlags != INVOKE_PROPERTYPUT))
405 for(i=0; i<This->n_vars; i++)
406 if(!strcmpW(This->fields[i].name, szFieldName))
408 if(i == This->n_vars)
409 return TYPE_E_FIELDNOTFOUND;
414 static HRESULT WINAPI IRecordInfoImpl_GetFieldNames(IRecordInfo *iface, ULONG *pcNames,
417 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
418 ULONG n = This->n_vars, i;
420 TRACE("(%p)->(%p %p)\n", This, pcNames, rgBstrNames);
430 rgBstrNames[i] = SysAllocString(This->fields[i].name);
437 static BOOL WINAPI IRecordInfoImpl_IsMatchingType(IRecordInfo *iface, IRecordInfo *pRecordInfo)
439 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
441 FIXME("(%p)->(%p) stub\n", This, pRecordInfo);
446 static PVOID WINAPI IRecordInfoImpl_RecordCreate(IRecordInfo *iface)
448 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
450 TRACE("(%p)\n", This);
452 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->size);
455 static HRESULT WINAPI IRecordInfoImpl_RecordCreateCopy(IRecordInfo *iface, PVOID pvSource,
458 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
460 TRACE("(%p)->(%p %p)\n", This, pvSource, ppvDest);
462 if(!pvSource || !ppvDest)
465 *ppvDest = IRecordInfo_RecordCreate(iface);
466 return IRecordInfo_RecordCopy(iface, pvSource, *ppvDest);
469 static HRESULT WINAPI IRecordInfoImpl_RecordDestroy(IRecordInfo *iface, PVOID pvRecord)
471 IRecordInfoImpl *This = (IRecordInfoImpl*)iface;
474 TRACE("(%p)->(%p)\n", This, pvRecord);
476 hres = IRecordInfo_RecordClear(iface, pvRecord);
480 if(!HeapFree(GetProcessHeap(), 0, pvRecord))
486 static const IRecordInfoVtbl IRecordInfoImplVtbl = {
487 IRecordInfoImpl_QueryInterface,
488 IRecordInfoImpl_AddRef,
489 IRecordInfoImpl_Release,
490 IRecordInfoImpl_RecordInit,
491 IRecordInfoImpl_RecordClear,
492 IRecordInfoImpl_RecordCopy,
493 IRecordInfoImpl_GetGuid,
494 IRecordInfoImpl_GetName,
495 IRecordInfoImpl_GetSize,
496 IRecordInfoImpl_GetTypeInfo,
497 IRecordInfoImpl_GetField,
498 IRecordInfoImpl_GetFieldNoCopy,
499 IRecordInfoImpl_PutField,
500 IRecordInfoImpl_PutFieldNoCopy,
501 IRecordInfoImpl_GetFieldNames,
502 IRecordInfoImpl_IsMatchingType,
503 IRecordInfoImpl_RecordCreate,
504 IRecordInfoImpl_RecordCreateCopy,
505 IRecordInfoImpl_RecordDestroy
508 /******************************************************************************
509 * GetRecordInfoFromGuids [OLEAUT32.322]
513 * Failure: E_INVALIDARG, if any argument is invalid.
515 HRESULT WINAPI GetRecordInfoFromGuids(REFGUID rGuidTypeLib, ULONG uVerMajor,
516 ULONG uVerMinor, LCID lcid, REFGUID rGuidTypeInfo, IRecordInfo** ppRecInfo)
518 ITypeInfo *pTypeInfo;
522 TRACE("(%p,%d,%d,%d,%p,%p)\n", rGuidTypeLib, uVerMajor, uVerMinor,
523 lcid, rGuidTypeInfo, ppRecInfo);
525 hres = LoadRegTypeLib(rGuidTypeLib, uVerMajor, uVerMinor, lcid, &pTypeLib);
527 WARN("LoadRegTypeLib failed!\n");
531 hres = ITypeLib_GetTypeInfoOfGuid(pTypeLib, rGuidTypeInfo, &pTypeInfo);
532 ITypeLib_Release(pTypeLib);
534 WARN("GetTypeInfoOfGuid failed!\n");
538 hres = GetRecordInfoFromTypeInfo(pTypeInfo, ppRecInfo);
539 ITypeInfo_Release(pTypeInfo);
543 /******************************************************************************
544 * GetRecordInfoFromTypeInfo [OLEAUT32.332]
546 HRESULT WINAPI GetRecordInfoFromTypeInfo(ITypeInfo* pTI, IRecordInfo** ppRecInfo) {
549 IRecordInfoImpl *ret;
550 ITypeInfo *pTypeInfo;
554 TRACE("(%p %p)\n", pTI, ppRecInfo);
556 if(!pTI || !ppRecInfo)
559 hres = ITypeInfo_GetTypeAttr(pTI, &typeattr);
560 if(FAILED(hres) || !typeattr) {
561 WARN("GetTypeAttr failed: %08x\n", hres);
565 if(typeattr->typekind == TKIND_ALIAS) {
566 hres = ITypeInfo_GetRefTypeInfo(pTI, typeattr->tdescAlias.u.hreftype, &pTypeInfo);
567 guid = typeattr->guid;
568 ITypeInfo_ReleaseTypeAttr(pTI, typeattr);
570 WARN("GetRefTypeInfo failed: %08x\n", hres);
573 ITypeInfo_GetTypeAttr(pTypeInfo, &typeattr);
576 ITypeInfo_AddRef(pTypeInfo);
577 guid = typeattr->guid;
580 if(typeattr->typekind != TKIND_RECORD) {
581 WARN("typekind != TKIND_RECORD\n");
582 ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr);
583 ITypeInfo_Release(pTypeInfo);
587 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
588 ret->lpVtbl = &IRecordInfoImplVtbl;
590 ret->pTypeInfo = pTypeInfo;
591 ret->n_vars = typeattr->cVars;
592 ret->size = typeattr->cbSizeInstance;
593 ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr);
597 /* NOTE: Windows implementation calls ITypeInfo::GetCantainingTypeLib and
598 * ITypeLib::GetLibAttr, but we currently don't need this.
601 hres = ITypeInfo_GetDocumentation(pTypeInfo, MEMBERID_NIL, &ret->name, NULL, NULL, NULL);
603 WARN("ITypeInfo::GetDocumentation failed\n");
607 ret->fields = HeapAlloc(GetProcessHeap(), 0, ret->n_vars*sizeof(VARDESC));
608 for(i = 0; i<ret->n_vars; i++) {
610 hres = ITypeInfo_GetVarDesc(pTypeInfo, i, &vardesc);
612 WARN("GetVarDesc failed\n");
615 ret->fields[i].vt = vardesc->elemdescVar.tdesc.vt;
616 ret->fields[i].varkind = vardesc->varkind;
617 ret->fields[i].offset = vardesc->u.oInst;
618 hres = ITypeInfo_GetDocumentation(pTypeInfo, vardesc->memid, &ret->fields[i].name,
621 WARN("GetDocumentation failed: %08x\n", hres);
622 ITypeInfo_ReleaseVarDesc(pTypeInfo, vardesc);
625 *ppRecInfo = (IRecordInfo*)ret;