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