1 /* 2 * Copyright 2005 Jacek Caban 3 * 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. 8 * 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. 13 * 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 17 */ 18 19 #include <stdarg.h> 20 21 #define COBJMACROS 22 #define NONAMELESSUNION 23 24 #include "windef.h" 25 #include "winbase.h" 26 #include "objbase.h" 27 #include "oaidl.h" 28 #include "oleauto.h" 29 #include "variant.h" 30 31 #include "wine/debug.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(ole); 34 35 typedef struct { 36 enum VARENUM vt; 37 VARKIND varkind; 38 ULONG offset; 39 BSTR name; 40 } fieldstr; 41 42 typedef struct { 43 IRecordInfo IRecordInfo_iface; 44 LONG ref; 45 46 GUID guid; 47 UINT lib_index; 48 WORD n_vars; 49 ULONG size; 50 BSTR name; 51 fieldstr *fields; 52 ITypeInfo *pTypeInfo; 53 } IRecordInfoImpl; 54 55 static inline IRecordInfoImpl *impl_from_IRecordInfo(IRecordInfo *iface) 56 { 57 return CONTAINING_RECORD(iface, IRecordInfoImpl, IRecordInfo_iface); 58 } 59 60 static HRESULT copy_to_variant(void *src, VARIANT *pvar, enum VARENUM vt) 61 { 62 TRACE("%p %p %d\n", src, pvar, vt); 63 64 #define CASE_COPY(x) \ 65 case VT_ ## x: \ 66 memcpy(&V_ ## x(pvar), src, sizeof(V_ ## x(pvar))); \ 67 break 68 69 switch(vt) { 70 CASE_COPY(I2); 71 CASE_COPY(I4); 72 CASE_COPY(R4); 73 CASE_COPY(R8); 74 CASE_COPY(CY); 75 CASE_COPY(DATE); 76 CASE_COPY(BSTR); 77 CASE_COPY(ERROR); 78 CASE_COPY(BOOL); 79 CASE_COPY(DECIMAL); 80 CASE_COPY(I1); 81 CASE_COPY(UI1); 82 CASE_COPY(UI2); 83 CASE_COPY(UI4); 84 CASE_COPY(I8); 85 CASE_COPY(UI8); 86 CASE_COPY(INT); 87 CASE_COPY(UINT); 88 CASE_COPY(INT_PTR); 89 CASE_COPY(UINT_PTR); 90 default: 91 FIXME("Not supported type: %d\n", vt); 92 return E_NOTIMPL; 93 }; 94 #undef CASE_COPY 95 96 V_VT(pvar) = vt; 97 return S_OK; 98 } 99 100 static HRESULT copy_from_variant(VARIANT *src, void *dest, enum VARENUM vt) 101 { 102 VARIANT var; 103 HRESULT hres; 104 105 TRACE("(%p(%d) %p %d)\n", src, V_VT(src), dest, vt); 106 107 hres = VariantChangeType(&var, src, 0, vt); 108 if(FAILED(hres)) 109 return hres; 110 111 #define CASE_COPY(x) \ 112 case VT_ ## x: \ 113 memcpy(dest, &V_ ## x(&var), sizeof(V_ ## x(&var))); \ 114 break 115 116 switch(vt) { 117 CASE_COPY(I2); 118 CASE_COPY(I4); 119 CASE_COPY(R4); 120 CASE_COPY(R8); 121 CASE_COPY(CY); 122 CASE_COPY(DATE); 123 CASE_COPY(BSTR); 124 CASE_COPY(ERROR); 125 CASE_COPY(BOOL); 126 CASE_COPY(DECIMAL); 127 CASE_COPY(I1); 128 CASE_COPY(UI1); 129 CASE_COPY(UI2); 130 CASE_COPY(UI4); 131 CASE_COPY(I8); 132 CASE_COPY(UI8); 133 CASE_COPY(INT); 134 CASE_COPY(UINT); 135 CASE_COPY(INT_PTR); 136 CASE_COPY(UINT_PTR); 137 default: 138 FIXME("Not supported type: %d\n", V_VT(&var)); 139 return E_NOTIMPL; 140 }; 141 #undef CASE_COPY 142 return S_OK; 143 } 144 145 static HRESULT WINAPI IRecordInfoImpl_QueryInterface(IRecordInfo *iface, REFIID riid, 146 void **ppvObject) 147 { 148 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject); 149 150 *ppvObject = NULL; 151 152 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRecordInfo, riid)) { 153 *ppvObject = iface; 154 IRecordInfo_AddRef(iface); 155 return S_OK; 156 } 157 158 FIXME("Not supported interface: %s\n", debugstr_guid(riid)); 159 return E_NOINTERFACE; 160 } 161 162 static ULONG WINAPI IRecordInfoImpl_AddRef(IRecordInfo *iface) 163 { 164 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 165 ULONG ref = InterlockedIncrement(&This->ref); 166 TRACE("(%p) -> %d\n", This, ref); 167 return ref; 168 } 169 170 static ULONG WINAPI IRecordInfoImpl_Release(IRecordInfo *iface) 171 { 172 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 173 ULONG ref = InterlockedDecrement(&This->ref); 174 175 TRACE("(%p) -> %d\n", This, ref); 176 177 if(!ref) { 178 int i; 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); 185 } 186 return ref; 187 } 188 189 static HRESULT WINAPI IRecordInfoImpl_RecordInit(IRecordInfo *iface, PVOID pvNew) 190 { 191 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 192 TRACE("(%p)->(%p)\n", This, pvNew); 193 194 if(!pvNew) 195 return E_INVALIDARG; 196 197 memset(pvNew, 0, This->size); 198 return S_OK; 199 } 200 201 static HRESULT WINAPI IRecordInfoImpl_RecordClear(IRecordInfo *iface, PVOID pvExisting) 202 { 203 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 204 int i; 205 PVOID var; 206 207 TRACE("(%p)->(%p)\n", This, pvExisting); 208 209 if(!pvExisting) 210 return E_INVALIDARG; 211 212 for(i=0; i<This->n_vars; i++) { 213 if(This->fields[i].varkind != VAR_PERINSTANCE) { 214 ERR("varkind != VAR_PERINSTANCE\n"); 215 continue; 216 } 217 var = ((PBYTE)pvExisting)+This->fields[i].offset; 218 switch(This->fields[i].vt) { 219 case VT_BSTR: 220 SysFreeString(*(BSTR*)var); 221 *(BSTR*)var = NULL; 222 break; 223 case VT_I2: 224 case VT_I4: 225 case VT_R4: 226 case VT_R8: 227 case VT_CY: 228 case VT_DATE: 229 case VT_ERROR: 230 case VT_BOOL: 231 case VT_DECIMAL: 232 case VT_I1: 233 case VT_UI1: 234 case VT_UI2: 235 case VT_UI4: 236 case VT_I8: 237 case VT_UI8: 238 case VT_INT: 239 case VT_UINT: 240 case VT_HRESULT: 241 break; 242 case VT_INT_PTR: 243 case VT_UINT_PTR: 244 *(void**)var = NULL; 245 break; 246 case VT_SAFEARRAY: 247 SafeArrayDestroy(var); 248 break; 249 case VT_UNKNOWN: 250 case VT_DISPATCH: 251 { 252 IUnknown *unk = *(IUnknown**)var; 253 if (unk) 254 IUnknown_Release(unk); 255 *(void**)var = NULL; 256 break; 257 } 258 default: 259 FIXME("Not supported vt = %d\n", This->fields[i].vt); 260 break; 261 } 262 } 263 264 return S_OK; 265 } 266 267 static HRESULT WINAPI IRecordInfoImpl_RecordCopy(IRecordInfo *iface, void *src_rec, void *dest_rec) 268 { 269 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 270 HRESULT hr = S_OK; 271 int i; 272 273 TRACE("(%p)->(%p %p)\n", This, src_rec, dest_rec); 274 275 if(!src_rec || !dest_rec) 276 return E_INVALIDARG; 277 278 /* release already stored data */ 279 IRecordInfo_RecordClear(iface, dest_rec); 280 281 for (i = 0; i < This->n_vars; i++) 282 { 283 void *src, *dest; 284 285 if (This->fields[i].varkind != VAR_PERINSTANCE) { 286 ERR("varkind != VAR_PERINSTANCE\n"); 287 continue; 288 } 289 290 src = ((BYTE*)src_rec) + This->fields[i].offset; 291 dest = ((BYTE*)dest_rec) + This->fields[i].offset; 292 switch (This->fields[i].vt) 293 { 294 case VT_BSTR: 295 { 296 BSTR src_str = *(BSTR*)src; 297 298 if (src_str) 299 { 300 BSTR str = SysAllocString(*(BSTR*)src); 301 if (!str) hr = E_OUTOFMEMORY; 302 303 *(BSTR*)dest = str; 304 } 305 else 306 *(BSTR*)dest = NULL; 307 break; 308 } 309 case VT_UNKNOWN: 310 case VT_DISPATCH: 311 { 312 IUnknown *unk = *(IUnknown**)src; 313 *(IUnknown**)dest = unk; 314 if (unk) IUnknown_AddRef(unk); 315 break; 316 } 317 case VT_SAFEARRAY: 318 hr = SafeArrayCopy(src, dest); 319 break; 320 default: 321 { 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); 325 break; 326 } 327 } 328 329 if (FAILED(hr)) break; 330 } 331 332 if (FAILED(hr)) 333 IRecordInfo_RecordClear(iface, dest_rec); 334 335 return hr; 336 } 337 338 static HRESULT WINAPI IRecordInfoImpl_GetGuid(IRecordInfo *iface, GUID *pguid) 339 { 340 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 341 342 TRACE("(%p)->(%p)\n", This, pguid); 343 344 if(!pguid) 345 return E_INVALIDARG; 346 347 *pguid = This->guid; 348 return S_OK; 349 } 350 351 static HRESULT WINAPI IRecordInfoImpl_GetName(IRecordInfo *iface, BSTR *pbstrName) 352 { 353 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 354 355 TRACE("(%p)->(%p)\n", This, pbstrName); 356 357 if(!pbstrName) 358 return E_INVALIDARG; 359 360 *pbstrName = SysAllocString(This->name); 361 return S_OK; 362 } 363 364 static HRESULT WINAPI IRecordInfoImpl_GetSize(IRecordInfo *iface, ULONG *pcbSize) 365 { 366 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 367 368 TRACE("(%p)->(%p)\n", This, pcbSize); 369 370 if(!pcbSize) 371 return E_INVALIDARG; 372 373 *pcbSize = This->size; 374 return S_OK; 375 } 376 377 static HRESULT WINAPI IRecordInfoImpl_GetTypeInfo(IRecordInfo *iface, ITypeInfo **ppTypeInfo) 378 { 379 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 380 381 TRACE("(%p)->(%p)\n", This, ppTypeInfo); 382 383 if(!ppTypeInfo) 384 return E_INVALIDARG; 385 386 ITypeInfo_AddRef(This->pTypeInfo); 387 *ppTypeInfo = This->pTypeInfo; 388 389 return S_OK; 390 } 391 392 static HRESULT WINAPI IRecordInfoImpl_GetField(IRecordInfo *iface, PVOID pvData, 393 LPCOLESTR szFieldName, VARIANT *pvarField) 394 { 395 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 396 int i; 397 398 TRACE("(%p)->(%p %s %p)\n", This, pvData, debugstr_w(szFieldName), pvarField); 399 400 if(!pvData || !szFieldName || !pvarField) 401 return E_INVALIDARG; 402 403 for(i=0; i<This->n_vars; i++) 404 if(!wcscmp(This->fields[i].name, szFieldName)) 405 break; 406 if(i == This->n_vars) 407 return TYPE_E_FIELDNOTFOUND; 408 409 VariantClear(pvarField); 410 return copy_to_variant(((PBYTE)pvData)+This->fields[i].offset, pvarField, 411 This->fields[i].vt); 412 } 413 414 static HRESULT WINAPI IRecordInfoImpl_GetFieldNoCopy(IRecordInfo *iface, PVOID pvData, 415 LPCOLESTR szFieldName, VARIANT *pvarField, PVOID *ppvDataCArray) 416 { 417 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 418 int i; 419 420 TRACE("(%p)->(%p %s %p %p)\n", This, pvData, debugstr_w(szFieldName), pvarField, ppvDataCArray); 421 422 if(!pvData || !szFieldName || !pvarField) 423 return E_INVALIDARG; 424 425 for(i=0; i<This->n_vars; i++) 426 if(!wcscmp(This->fields[i].name, szFieldName)) 427 break; 428 if(i == This->n_vars) 429 return TYPE_E_FIELDNOTFOUND; 430 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; 435 return S_OK; 436 } 437 438 static HRESULT WINAPI IRecordInfoImpl_PutField(IRecordInfo *iface, ULONG wFlags, PVOID pvData, 439 LPCOLESTR szFieldName, VARIANT *pvarField) 440 { 441 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 442 int i; 443 444 TRACE("(%p)->(%08x %p %s %p)\n", This, wFlags, pvData, debugstr_w(szFieldName), 445 pvarField); 446 447 if(!pvData || !szFieldName || !pvarField 448 || (wFlags != INVOKE_PROPERTYPUTREF && wFlags != INVOKE_PROPERTYPUT)) 449 return E_INVALIDARG; 450 451 if(wFlags == INVOKE_PROPERTYPUTREF) { 452 FIXME("wFlag == INVOKE_PROPERTYPUTREF not supported\n"); 453 return E_NOTIMPL; 454 } 455 456 for(i=0; i<This->n_vars; i++) 457 if(!wcscmp(This->fields[i].name, szFieldName)) 458 break; 459 if(i == This->n_vars) 460 return TYPE_E_FIELDNOTFOUND; 461 462 return copy_from_variant(pvarField, ((PBYTE)pvData)+This->fields[i].offset, 463 This->fields[i].vt); 464 } 465 466 static HRESULT WINAPI IRecordInfoImpl_PutFieldNoCopy(IRecordInfo *iface, ULONG wFlags, 467 PVOID pvData, LPCOLESTR szFieldName, VARIANT *pvarField) 468 { 469 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 470 int i; 471 472 FIXME("(%p)->(%08x %p %s %p) stub\n", This, wFlags, pvData, debugstr_w(szFieldName), pvarField); 473 474 if(!pvData || !szFieldName || !pvarField 475 || (wFlags != INVOKE_PROPERTYPUTREF && wFlags != INVOKE_PROPERTYPUT)) 476 return E_INVALIDARG; 477 478 for(i=0; i<This->n_vars; i++) 479 if(!wcscmp(This->fields[i].name, szFieldName)) 480 break; 481 if(i == This->n_vars) 482 return TYPE_E_FIELDNOTFOUND; 483 484 return E_NOTIMPL; 485 } 486 487 static HRESULT WINAPI IRecordInfoImpl_GetFieldNames(IRecordInfo *iface, ULONG *pcNames, 488 BSTR *rgBstrNames) 489 { 490 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 491 ULONG n = This->n_vars, i; 492 493 TRACE("(%p)->(%p %p)\n", This, pcNames, rgBstrNames); 494 495 if(!pcNames) 496 return E_INVALIDARG; 497 498 if(*pcNames < n) 499 n = *pcNames; 500 501 if(rgBstrNames) { 502 for(i=0; i<n; i++) 503 rgBstrNames[i] = SysAllocString(This->fields[i].name); 504 } 505 506 *pcNames = n; 507 return S_OK; 508 } 509 510 static BOOL WINAPI IRecordInfoImpl_IsMatchingType(IRecordInfo *iface, IRecordInfo *info2) 511 { 512 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 513 GUID guid2; 514 515 TRACE( "(%p)->(%p)\n", This, info2 ); 516 517 IRecordInfo_GetGuid( info2, &guid2 ); 518 return IsEqualGUID( &This->guid, &guid2 ); 519 } 520 521 static PVOID WINAPI IRecordInfoImpl_RecordCreate(IRecordInfo *iface) 522 { 523 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 524 void *record; 525 526 TRACE("(%p)\n", This); 527 528 record = HeapAlloc(GetProcessHeap(), 0, This->size); 529 IRecordInfo_RecordInit(iface, record); 530 TRACE("created record at %p\n", record); 531 return record; 532 } 533 534 static HRESULT WINAPI IRecordInfoImpl_RecordCreateCopy(IRecordInfo *iface, PVOID pvSource, 535 PVOID *ppvDest) 536 { 537 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 538 539 TRACE("(%p)->(%p %p)\n", This, pvSource, ppvDest); 540 541 if(!pvSource || !ppvDest) 542 return E_INVALIDARG; 543 544 *ppvDest = IRecordInfo_RecordCreate(iface); 545 return IRecordInfo_RecordCopy(iface, pvSource, *ppvDest); 546 } 547 548 static HRESULT WINAPI IRecordInfoImpl_RecordDestroy(IRecordInfo *iface, PVOID pvRecord) 549 { 550 IRecordInfoImpl *This = impl_from_IRecordInfo(iface); 551 HRESULT hres; 552 553 TRACE("(%p)->(%p)\n", This, pvRecord); 554 555 hres = IRecordInfo_RecordClear(iface, pvRecord); 556 if(FAILED(hres)) 557 return hres; 558 559 if(!HeapFree(GetProcessHeap(), 0, pvRecord)) 560 return E_INVALIDARG; 561 562 return S_OK; 563 } 564 565 static const IRecordInfoVtbl IRecordInfoImplVtbl = { 566 IRecordInfoImpl_QueryInterface, 567 IRecordInfoImpl_AddRef, 568 IRecordInfoImpl_Release, 569 IRecordInfoImpl_RecordInit, 570 IRecordInfoImpl_RecordClear, 571 IRecordInfoImpl_RecordCopy, 572 IRecordInfoImpl_GetGuid, 573 IRecordInfoImpl_GetName, 574 IRecordInfoImpl_GetSize, 575 IRecordInfoImpl_GetTypeInfo, 576 IRecordInfoImpl_GetField, 577 IRecordInfoImpl_GetFieldNoCopy, 578 IRecordInfoImpl_PutField, 579 IRecordInfoImpl_PutFieldNoCopy, 580 IRecordInfoImpl_GetFieldNames, 581 IRecordInfoImpl_IsMatchingType, 582 IRecordInfoImpl_RecordCreate, 583 IRecordInfoImpl_RecordCreateCopy, 584 IRecordInfoImpl_RecordDestroy 585 }; 586 587 /****************************************************************************** 588 * GetRecordInfoFromGuids [OLEAUT32.322] 589 * 590 * RETURNS 591 * Success: S_OK 592 * Failure: E_INVALIDARG, if any argument is invalid. 593 */ 594 HRESULT WINAPI GetRecordInfoFromGuids(REFGUID rGuidTypeLib, ULONG uVerMajor, 595 ULONG uVerMinor, LCID lcid, REFGUID rGuidTypeInfo, IRecordInfo** ppRecInfo) 596 { 597 ITypeInfo *pTypeInfo; 598 ITypeLib *pTypeLib; 599 HRESULT hres; 600 601 TRACE("(%p,%d,%d,%d,%s,%p)\n", rGuidTypeLib, uVerMajor, uVerMinor, 602 lcid, debugstr_guid(rGuidTypeInfo), ppRecInfo); 603 604 hres = LoadRegTypeLib(rGuidTypeLib, uVerMajor, uVerMinor, lcid, &pTypeLib); 605 if(FAILED(hres)) { 606 WARN("LoadRegTypeLib failed!\n"); 607 return hres; 608 } 609 610 hres = ITypeLib_GetTypeInfoOfGuid(pTypeLib, rGuidTypeInfo, &pTypeInfo); 611 ITypeLib_Release(pTypeLib); 612 if(FAILED(hres)) { 613 WARN("GetTypeInfoOfGuid failed!\n"); 614 return hres; 615 } 616 617 hres = GetRecordInfoFromTypeInfo(pTypeInfo, ppRecInfo); 618 ITypeInfo_Release(pTypeInfo); 619 return hres; 620 } 621 622 /****************************************************************************** 623 * GetRecordInfoFromTypeInfo [OLEAUT32.332] 624 */ 625 HRESULT WINAPI GetRecordInfoFromTypeInfo(ITypeInfo* pTI, IRecordInfo** ppRecInfo) { 626 HRESULT hres; 627 TYPEATTR *typeattr; 628 IRecordInfoImpl *ret; 629 ITypeInfo *pTypeInfo; 630 int i; 631 GUID guid; 632 633 TRACE("(%p %p)\n", pTI, ppRecInfo); 634 635 if(!pTI || !ppRecInfo) 636 return E_INVALIDARG; 637 638 hres = ITypeInfo_GetTypeAttr(pTI, &typeattr); 639 if(FAILED(hres) || !typeattr) { 640 WARN("GetTypeAttr failed: %08x\n", hres); 641 return hres; 642 } 643 644 if(typeattr->typekind == TKIND_ALIAS) { 645 hres = ITypeInfo_GetRefTypeInfo(pTI, typeattr->tdescAlias.u.hreftype, &pTypeInfo); 646 guid = typeattr->guid; 647 ITypeInfo_ReleaseTypeAttr(pTI, typeattr); 648 if(FAILED(hres)) { 649 WARN("GetRefTypeInfo failed: %08x\n", hres); 650 return hres; 651 } 652 hres = ITypeInfo_GetTypeAttr(pTypeInfo, &typeattr); 653 if(FAILED(hres)) { 654 ITypeInfo_Release(pTypeInfo); 655 WARN("GetTypeAttr failed for referenced type: %08x\n", hres); 656 return hres; 657 } 658 }else { 659 pTypeInfo = pTI; 660 ITypeInfo_AddRef(pTypeInfo); 661 guid = typeattr->guid; 662 } 663 664 if(typeattr->typekind != TKIND_RECORD) { 665 WARN("typekind != TKIND_RECORD\n"); 666 ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr); 667 ITypeInfo_Release(pTypeInfo); 668 return E_INVALIDARG; 669 } 670 671 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret)); 672 ret->IRecordInfo_iface.lpVtbl = &IRecordInfoImplVtbl; 673 ret->ref = 1; 674 ret->pTypeInfo = pTypeInfo; 675 ret->n_vars = typeattr->cVars; 676 ret->size = typeattr->cbSizeInstance; 677 ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr); 678 679 ret->guid = guid; 680 681 /* NOTE: Windows implementation calls ITypeInfo::GetCantainingTypeLib and 682 * ITypeLib::GetLibAttr, but we currently don't need this. 683 */ 684 685 hres = ITypeInfo_GetDocumentation(pTypeInfo, MEMBERID_NIL, &ret->name, NULL, NULL, NULL); 686 if(FAILED(hres)) { 687 WARN("ITypeInfo::GetDocumentation failed\n"); 688 ret->name = NULL; 689 } 690 691 ret->fields = HeapAlloc(GetProcessHeap(), 0, ret->n_vars*sizeof(fieldstr)); 692 for(i = 0; i<ret->n_vars; i++) { 693 VARDESC *vardesc; 694 hres = ITypeInfo_GetVarDesc(pTypeInfo, i, &vardesc); 695 if(FAILED(hres)) { 696 WARN("GetVarDesc failed\n"); 697 continue; 698 } 699 ret->fields[i].vt = vardesc->elemdescVar.tdesc.vt; 700 ret->fields[i].varkind = vardesc->varkind; 701 ret->fields[i].offset = vardesc->u.oInst; 702 hres = ITypeInfo_GetDocumentation(pTypeInfo, vardesc->memid, &ret->fields[i].name, 703 NULL, NULL, NULL); 704 if(FAILED(hres)) 705 WARN("GetDocumentation failed: %08x\n", hres); 706 TRACE("field=%s, offset=%d\n", debugstr_w(ret->fields[i].name), ret->fields[i].offset); 707 ITypeInfo_ReleaseVarDesc(pTypeInfo, vardesc); 708 } 709 710 *ppRecInfo = &ret->IRecordInfo_iface; 711 712 return S_OK; 713 } 714