1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2002, 2005 Mike McCormack for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "msipriv.h" 22 23 #include <stdio.h> 24 #include <propvarutil.h> 25 26 WINE_DEFAULT_DEBUG_CHANNEL(msi); 27 28 #include <pshpack1.h> 29 30 typedef struct { 31 WORD wByteOrder; 32 WORD wFormat; 33 DWORD dwOSVer; 34 CLSID clsID; 35 DWORD reserved; 36 } PROPERTYSETHEADER; 37 38 typedef struct { 39 FMTID fmtid; 40 DWORD dwOffset; 41 } FORMATIDOFFSET; 42 43 typedef struct { 44 DWORD cbSection; 45 DWORD cProperties; 46 } PROPERTYSECTIONHEADER; 47 48 typedef struct { 49 DWORD propid; 50 DWORD dwOffset; 51 } PROPERTYIDOFFSET; 52 53 typedef struct { 54 DWORD type; 55 union { 56 INT i4; 57 SHORT i2; 58 FILETIME ft; 59 struct { 60 DWORD len; 61 BYTE str[1]; 62 } str; 63 } u; 64 } PROPERTY_DATA; 65 66 #include <poppack.h> 67 68 static HRESULT (WINAPI *pPropVariantChangeType) 69 (PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc, 70 PROPVAR_CHANGE_FLAGS flags, VARTYPE vt); 71 72 #define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER)) 73 74 static void free_prop( PROPVARIANT *prop ) 75 { 76 if (prop->vt == VT_LPSTR ) 77 msi_free( prop->u.pszVal ); 78 prop->vt = VT_EMPTY; 79 } 80 81 static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg ) 82 { 83 MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg; 84 DWORD i; 85 86 for( i = 0; i < MSI_MAX_PROPS; i++ ) 87 free_prop( &si->property[i] ); 88 IStorage_Release( si->storage ); 89 } 90 91 static UINT get_type( UINT uiProperty ) 92 { 93 switch( uiProperty ) 94 { 95 case PID_CODEPAGE: 96 return VT_I2; 97 98 case PID_SUBJECT: 99 case PID_AUTHOR: 100 case PID_KEYWORDS: 101 case PID_COMMENTS: 102 case PID_TEMPLATE: 103 case PID_LASTAUTHOR: 104 case PID_REVNUMBER: 105 case PID_APPNAME: 106 case PID_TITLE: 107 return VT_LPSTR; 108 109 case PID_LASTPRINTED: 110 case PID_CREATE_DTM: 111 case PID_LASTSAVE_DTM: 112 return VT_FILETIME; 113 114 case PID_WORDCOUNT: 115 case PID_CHARCOUNT: 116 case PID_SECURITY: 117 case PID_PAGECOUNT: 118 return VT_I4; 119 } 120 return VT_EMPTY; 121 } 122 123 static UINT get_property_count( const PROPVARIANT *property ) 124 { 125 UINT i, n = 0; 126 127 if( !property ) 128 return n; 129 for( i = 0; i < MSI_MAX_PROPS; i++ ) 130 if( property[i].vt != VT_EMPTY ) 131 n++; 132 return n; 133 } 134 135 static UINT propvar_changetype(PROPVARIANT *changed, PROPVARIANT *property, VARTYPE vt) 136 { 137 HRESULT hr; 138 HMODULE propsys = LoadLibraryA("propsys.dll"); 139 pPropVariantChangeType = (void *)GetProcAddress(propsys, "PropVariantChangeType"); 140 141 if (!pPropVariantChangeType) 142 { 143 ERR("PropVariantChangeType function missing!\n"); 144 return ERROR_FUNCTION_FAILED; 145 } 146 147 hr = pPropVariantChangeType(changed, property, 0, vt); 148 return (hr == S_OK) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED; 149 } 150 151 /* FIXME: doesn't deal with endian conversion */ 152 static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz ) 153 { 154 UINT type; 155 DWORD i, size; 156 PROPERTY_DATA *propdata; 157 PROPVARIANT property, *ptr; 158 PROPVARIANT changed; 159 PROPERTYIDOFFSET *idofs; 160 PROPERTYSECTIONHEADER *section_hdr; 161 162 section_hdr = (PROPERTYSECTIONHEADER*) &data[0]; 163 idofs = (PROPERTYIDOFFSET*) &data[SECT_HDR_SIZE]; 164 165 /* now set all the properties */ 166 for( i = 0; i < section_hdr->cProperties; i++ ) 167 { 168 if( idofs[i].propid >= MSI_MAX_PROPS ) 169 { 170 ERR("Unknown property ID %d\n", idofs[i].propid ); 171 break; 172 } 173 174 type = get_type( idofs[i].propid ); 175 if( type == VT_EMPTY ) 176 { 177 ERR("propid %d has unknown type\n", idofs[i].propid); 178 break; 179 } 180 181 propdata = (PROPERTY_DATA*) &data[ idofs[i].dwOffset ]; 182 183 /* check we don't run off the end of the data */ 184 size = sz - idofs[i].dwOffset - sizeof(DWORD); 185 if( sizeof(DWORD) > size || 186 ( propdata->type == VT_FILETIME && sizeof(FILETIME) > size ) || 187 ( propdata->type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) ) 188 { 189 ERR("not enough data\n"); 190 break; 191 } 192 193 property.vt = propdata->type; 194 if( propdata->type == VT_LPSTR ) 195 { 196 LPSTR str = msi_alloc( propdata->u.str.len ); 197 memcpy( str, propdata->u.str.str, propdata->u.str.len ); 198 str[ propdata->u.str.len - 1 ] = 0; 199 property.u.pszVal = str; 200 } 201 else if( propdata->type == VT_FILETIME ) 202 property.u.filetime = propdata->u.ft; 203 else if( propdata->type == VT_I2 ) 204 property.u.iVal = propdata->u.i2; 205 else if( propdata->type == VT_I4 ) 206 property.u.lVal = propdata->u.i4; 207 208 /* check the type is the same as we expect */ 209 if( type != propdata->type ) 210 { 211 propvar_changetype(&changed, &property, type); 212 ptr = &changed; 213 } 214 else 215 ptr = &property; 216 217 prop[ idofs[i].propid ] = *ptr; 218 } 219 } 220 221 static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm ) 222 { 223 PROPERTYSETHEADER set_hdr; 224 FORMATIDOFFSET format_hdr; 225 PROPERTYSECTIONHEADER section_hdr; 226 LPBYTE data = NULL; 227 LARGE_INTEGER ofs; 228 ULONG count, sz; 229 HRESULT r; 230 231 TRACE("%p %p\n", si, stm); 232 233 /* read the header */ 234 sz = sizeof set_hdr; 235 r = IStream_Read( stm, &set_hdr, sz, &count ); 236 if( FAILED(r) || count != sz ) 237 return ERROR_FUNCTION_FAILED; 238 239 if( set_hdr.wByteOrder != 0xfffe ) 240 { 241 ERR("property set not big-endian %04X\n", set_hdr.wByteOrder); 242 return ERROR_FUNCTION_FAILED; 243 } 244 245 sz = sizeof format_hdr; 246 r = IStream_Read( stm, &format_hdr, sz, &count ); 247 if( FAILED(r) || count != sz ) 248 return ERROR_FUNCTION_FAILED; 249 250 /* check the format id is correct */ 251 if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) ) 252 return ERROR_FUNCTION_FAILED; 253 254 /* seek to the location of the section */ 255 ofs.QuadPart = format_hdr.dwOffset; 256 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL ); 257 if( FAILED(r) ) 258 return ERROR_FUNCTION_FAILED; 259 260 /* read the section itself */ 261 sz = SECT_HDR_SIZE; 262 r = IStream_Read( stm, §ion_hdr, sz, &count ); 263 if( FAILED(r) || count != sz ) 264 return ERROR_FUNCTION_FAILED; 265 266 if( section_hdr.cProperties > MSI_MAX_PROPS ) 267 { 268 ERR("too many properties %d\n", section_hdr.cProperties); 269 return ERROR_FUNCTION_FAILED; 270 } 271 272 data = msi_alloc( section_hdr.cbSection); 273 if( !data ) 274 return ERROR_FUNCTION_FAILED; 275 276 memcpy( data, §ion_hdr, SECT_HDR_SIZE ); 277 278 /* read all the data in one go */ 279 sz = section_hdr.cbSection - SECT_HDR_SIZE; 280 r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count ); 281 if( SUCCEEDED(r) && count == sz ) 282 read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE ); 283 else 284 ERR("failed to read properties %d %d\n", count, sz); 285 286 msi_free( data ); 287 return ERROR_SUCCESS; 288 } 289 290 static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val ) 291 { 292 if( data ) 293 { 294 data[ofs++] = val&0xff; 295 data[ofs++] = (val>>8)&0xff; 296 data[ofs++] = (val>>16)&0xff; 297 data[ofs++] = (val>>24)&0xff; 298 } 299 return 4; 300 } 301 302 static DWORD write_filetime( LPBYTE data, DWORD ofs, const FILETIME *ft ) 303 { 304 write_dword( data, ofs, ft->dwLowDateTime ); 305 write_dword( data, ofs + 4, ft->dwHighDateTime ); 306 return 8; 307 } 308 309 static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str ) 310 { 311 DWORD len = lstrlenA( str ) + 1; 312 write_dword( data, ofs, len ); 313 if( data ) 314 memcpy( &data[ofs + 4], str, len ); 315 return (7 + len) & ~3; 316 } 317 318 static UINT write_property_to_data( const PROPVARIANT *prop, LPBYTE data ) 319 { 320 DWORD sz = 0; 321 322 if( prop->vt == VT_EMPTY ) 323 return sz; 324 325 /* add the type */ 326 sz += write_dword( data, sz, prop->vt ); 327 switch( prop->vt ) 328 { 329 case VT_I2: 330 sz += write_dword( data, sz, prop->u.iVal ); 331 break; 332 case VT_I4: 333 sz += write_dword( data, sz, prop->u.lVal ); 334 break; 335 case VT_FILETIME: 336 sz += write_filetime( data, sz, &prop->u.filetime ); 337 break; 338 case VT_LPSTR: 339 sz += write_string( data, sz, prop->u.pszVal ); 340 break; 341 } 342 return sz; 343 } 344 345 static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm ) 346 { 347 UINT ret = ERROR_FUNCTION_FAILED; 348 PROPERTYSETHEADER set_hdr; 349 FORMATIDOFFSET format_hdr; 350 PROPERTYSECTIONHEADER section_hdr; 351 PROPERTYIDOFFSET idofs[MSI_MAX_PROPS]; 352 LPBYTE data = NULL; 353 ULONG count, sz; 354 HRESULT r; 355 int i; 356 357 /* write the header */ 358 sz = sizeof set_hdr; 359 memset( &set_hdr, 0, sz ); 360 set_hdr.wByteOrder = 0xfffe; 361 set_hdr.wFormat = 0; 362 set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */ 363 /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */ 364 set_hdr.reserved = 1; 365 r = IStream_Write( stm, &set_hdr, sz, &count ); 366 if( FAILED(r) || count != sz ) 367 return ret; 368 369 /* write the format header */ 370 sz = sizeof format_hdr; 371 format_hdr.fmtid = FMTID_SummaryInformation; 372 format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr; 373 r = IStream_Write( stm, &format_hdr, sz, &count ); 374 if( FAILED(r) || count != sz ) 375 return ret; 376 377 /* add up how much space the data will take and calculate the offsets */ 378 section_hdr.cbSection = sizeof section_hdr; 379 section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]); 380 section_hdr.cProperties = 0; 381 for( i = 0; i < MSI_MAX_PROPS; i++ ) 382 { 383 sz = write_property_to_data( &si->property[i], NULL ); 384 if( !sz ) 385 continue; 386 idofs[ section_hdr.cProperties ].propid = i; 387 idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection; 388 section_hdr.cProperties++; 389 section_hdr.cbSection += sz; 390 } 391 392 data = msi_alloc_zero( section_hdr.cbSection ); 393 394 sz = 0; 395 memcpy( &data[sz], §ion_hdr, sizeof section_hdr ); 396 sz += sizeof section_hdr; 397 398 memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] ); 399 sz += section_hdr.cProperties * sizeof idofs[0]; 400 401 /* write out the data */ 402 for( i = 0; i < MSI_MAX_PROPS; i++ ) 403 sz += write_property_to_data( &si->property[i], &data[sz] ); 404 405 r = IStream_Write( stm, data, sz, &count ); 406 msi_free( data ); 407 if( FAILED(r) || count != sz ) 408 return ret; 409 410 return ERROR_SUCCESS; 411 } 412 413 static MSISUMMARYINFO *create_suminfo( IStorage *stg, UINT update_count ) 414 { 415 MSISUMMARYINFO *si; 416 417 if (!(si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, sizeof(MSISUMMARYINFO), MSI_CloseSummaryInfo ))) 418 return NULL; 419 420 si->update_count = update_count; 421 IStorage_AddRef( stg ); 422 si->storage = stg; 423 424 return si; 425 } 426 427 UINT msi_get_suminfo( IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **ret ) 428 { 429 IStream *stm; 430 MSISUMMARYINFO *si; 431 HRESULT hr; 432 UINT r; 433 434 TRACE("%p, %u\n", stg, uiUpdateCount); 435 436 if (!(si = create_suminfo( stg, uiUpdateCount ))) return ERROR_OUTOFMEMORY; 437 438 hr = IStorage_OpenStream( si->storage, szSumInfo, 0, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stm ); 439 if (FAILED( hr )) 440 { 441 msiobj_release( &si->hdr ); 442 return ERROR_FUNCTION_FAILED; 443 } 444 445 r = load_summary_info( si, stm ); 446 IStream_Release( stm ); 447 if (r != ERROR_SUCCESS) 448 { 449 msiobj_release( &si->hdr ); 450 return r; 451 } 452 453 *ret = si; 454 return ERROR_SUCCESS; 455 } 456 457 UINT msi_get_db_suminfo( MSIDATABASE *db, UINT uiUpdateCount, MSISUMMARYINFO **ret ) 458 { 459 IStream *stm; 460 MSISUMMARYINFO *si; 461 UINT r; 462 463 if (!(si = create_suminfo( db->storage, uiUpdateCount ))) return ERROR_OUTOFMEMORY; 464 465 r = msi_get_stream( db, szSumInfo, &stm ); 466 if (r != ERROR_SUCCESS) 467 { 468 msiobj_release( &si->hdr ); 469 return r; 470 } 471 472 r = load_summary_info( si, stm ); 473 IStream_Release( stm ); 474 if (r != ERROR_SUCCESS) 475 { 476 msiobj_release( &si->hdr ); 477 return r; 478 } 479 480 *ret = si; 481 return ERROR_SUCCESS; 482 } 483 484 UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, 485 LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle ) 486 { 487 MSISUMMARYINFO *si; 488 MSIDATABASE *db; 489 UINT ret; 490 491 TRACE("%d %s %d %p\n", hDatabase, debugstr_w(szDatabase), 492 uiUpdateCount, pHandle); 493 494 if( !pHandle ) 495 return ERROR_INVALID_PARAMETER; 496 497 if( szDatabase && szDatabase[0] ) 498 { 499 LPCWSTR persist = uiUpdateCount ? MSIDBOPEN_TRANSACT : MSIDBOPEN_READONLY; 500 501 ret = MSI_OpenDatabaseW( szDatabase, persist, &db ); 502 if( ret != ERROR_SUCCESS ) 503 return ret; 504 } 505 else 506 { 507 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE ); 508 if( !db ) 509 { 510 HRESULT hr; 511 IWineMsiRemoteDatabase *remote_database; 512 513 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hDatabase ); 514 if ( !remote_database ) 515 return ERROR_INVALID_HANDLE; 516 517 hr = IWineMsiRemoteDatabase_GetSummaryInformation( remote_database, 518 uiUpdateCount, pHandle ); 519 IWineMsiRemoteDatabase_Release( remote_database ); 520 521 if (FAILED(hr)) 522 { 523 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) 524 return HRESULT_CODE(hr); 525 526 return ERROR_FUNCTION_FAILED; 527 } 528 529 return ERROR_SUCCESS; 530 } 531 } 532 533 ret = msi_get_suminfo( db->storage, uiUpdateCount, &si ); 534 if (ret != ERROR_SUCCESS) 535 ret = msi_get_db_suminfo( db, uiUpdateCount, &si ); 536 if (ret != ERROR_SUCCESS) 537 { 538 if ((si = create_suminfo( db->storage, uiUpdateCount ))) 539 ret = ERROR_SUCCESS; 540 } 541 542 if (ret == ERROR_SUCCESS) 543 { 544 *pHandle = alloc_msihandle( &si->hdr ); 545 if( *pHandle ) 546 ret = ERROR_SUCCESS; 547 else 548 ret = ERROR_NOT_ENOUGH_MEMORY; 549 msiobj_release( &si->hdr ); 550 } 551 552 msiobj_release( &db->hdr ); 553 return ret; 554 } 555 556 UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase, 557 LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle) 558 { 559 LPWSTR szwDatabase = NULL; 560 UINT ret; 561 562 TRACE("%d %s %d %p\n", hDatabase, debugstr_a(szDatabase), 563 uiUpdateCount, pHandle); 564 565 if( szDatabase ) 566 { 567 szwDatabase = strdupAtoW( szDatabase ); 568 if( !szwDatabase ) 569 return ERROR_FUNCTION_FAILED; 570 } 571 572 ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle); 573 574 msi_free( szwDatabase ); 575 576 return ret; 577 } 578 579 UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, PUINT pCount) 580 { 581 MSISUMMARYINFO *si; 582 583 TRACE("%d %p\n", hSummaryInfo, pCount); 584 585 si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO ); 586 if( !si ) 587 return ERROR_INVALID_HANDLE; 588 589 if( pCount ) 590 *pCount = get_property_count( si->property ); 591 msiobj_release( &si->hdr ); 592 593 return ERROR_SUCCESS; 594 } 595 596 static UINT get_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT *puiDataType, INT *piValue, 597 FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf) 598 { 599 PROPVARIANT *prop; 600 UINT ret = ERROR_SUCCESS; 601 602 prop = &si->property[uiProperty]; 603 604 if( puiDataType ) 605 *puiDataType = prop->vt; 606 607 switch( prop->vt ) 608 { 609 case VT_I2: 610 if( piValue ) 611 *piValue = prop->u.iVal; 612 break; 613 case VT_I4: 614 if( piValue ) 615 *piValue = prop->u.lVal; 616 break; 617 case VT_LPSTR: 618 if( pcchValueBuf ) 619 { 620 DWORD len = 0; 621 622 if( str->unicode ) 623 { 624 len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, NULL, 0 ) - 1; 625 MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, str->str.w, *pcchValueBuf ); 626 } 627 else 628 { 629 len = lstrlenA( prop->u.pszVal ); 630 if( str->str.a ) 631 lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf ); 632 } 633 if (len >= *pcchValueBuf) 634 ret = ERROR_MORE_DATA; 635 *pcchValueBuf = len; 636 } 637 break; 638 case VT_FILETIME: 639 if( pftValue ) 640 *pftValue = prop->u.filetime; 641 break; 642 case VT_EMPTY: 643 break; 644 default: 645 FIXME("Unknown property variant type\n"); 646 break; 647 } 648 return ret; 649 } 650 651 LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) 652 { 653 PROPVARIANT *prop; 654 655 if ( uiProperty >= MSI_MAX_PROPS ) 656 return NULL; 657 prop = &si->property[uiProperty]; 658 if( prop->vt != VT_LPSTR ) 659 return NULL; 660 return strdupAtoW( prop->u.pszVal ); 661 } 662 663 INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) 664 { 665 PROPVARIANT *prop; 666 667 if ( uiProperty >= MSI_MAX_PROPS ) 668 return -1; 669 prop = &si->property[uiProperty]; 670 if( prop->vt != VT_I4 ) 671 return -1; 672 return prop->u.lVal; 673 } 674 675 LPWSTR msi_get_suminfo_product( IStorage *stg ) 676 { 677 MSISUMMARYINFO *si; 678 LPWSTR prod; 679 UINT r; 680 681 r = msi_get_suminfo( stg, 0, &si ); 682 if (r != ERROR_SUCCESS) 683 { 684 ERR("no summary information!\n"); 685 return NULL; 686 } 687 prod = msi_suminfo_dup_string( si, PID_REVNUMBER ); 688 msiobj_release( &si->hdr ); 689 return prod; 690 } 691 692 UINT WINAPI MsiSummaryInfoGetPropertyA( 693 MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue, 694 FILETIME *pftValue, LPSTR szValueBuf, LPDWORD pcchValueBuf) 695 { 696 MSISUMMARYINFO *si; 697 awstring str; 698 UINT r; 699 700 TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType, 701 piValue, pftValue, szValueBuf, pcchValueBuf ); 702 703 if (uiProperty >= MSI_MAX_PROPS) 704 { 705 if (puiDataType) *puiDataType = VT_EMPTY; 706 return ERROR_UNKNOWN_PROPERTY; 707 } 708 709 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 710 return ERROR_INVALID_HANDLE; 711 712 str.unicode = FALSE; 713 str.str.a = szValueBuf; 714 715 r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf ); 716 msiobj_release( &si->hdr ); 717 return r; 718 } 719 720 UINT WINAPI MsiSummaryInfoGetPropertyW( 721 MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue, 722 FILETIME *pftValue, LPWSTR szValueBuf, LPDWORD pcchValueBuf) 723 { 724 MSISUMMARYINFO *si; 725 awstring str; 726 UINT r; 727 728 TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType, 729 piValue, pftValue, szValueBuf, pcchValueBuf ); 730 731 if (uiProperty >= MSI_MAX_PROPS) 732 { 733 if (puiDataType) *puiDataType = VT_EMPTY; 734 return ERROR_UNKNOWN_PROPERTY; 735 } 736 737 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 738 return ERROR_INVALID_HANDLE; 739 740 str.unicode = TRUE; 741 str.str.w = szValueBuf; 742 743 r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf ); 744 msiobj_release( &si->hdr ); 745 return r; 746 } 747 748 static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type, 749 INT iValue, FILETIME *pftValue, awcstring *str ) 750 { 751 PROPVARIANT *prop; 752 UINT len; 753 754 TRACE("%p, %u, %u, %d, %p, %p\n", si, uiProperty, type, iValue, pftValue, str ); 755 756 prop = &si->property[uiProperty]; 757 758 if( prop->vt == VT_EMPTY ) 759 { 760 if( !si->update_count ) 761 return ERROR_FUNCTION_FAILED; 762 763 si->update_count--; 764 } 765 else if( prop->vt != type ) 766 return ERROR_SUCCESS; 767 768 free_prop( prop ); 769 prop->vt = type; 770 switch( type ) 771 { 772 case VT_I4: 773 prop->u.lVal = iValue; 774 break; 775 case VT_I2: 776 prop->u.iVal = iValue; 777 break; 778 case VT_FILETIME: 779 prop->u.filetime = *pftValue; 780 break; 781 case VT_LPSTR: 782 if( str->unicode ) 783 { 784 len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1, 785 NULL, 0, NULL, NULL ); 786 prop->u.pszVal = msi_alloc( len ); 787 WideCharToMultiByte( CP_ACP, 0, str->str.w, -1, 788 prop->u.pszVal, len, NULL, NULL ); 789 } 790 else 791 { 792 len = lstrlenA( str->str.a ) + 1; 793 prop->u.pszVal = msi_alloc( len ); 794 lstrcpyA( prop->u.pszVal, str->str.a ); 795 } 796 break; 797 } 798 799 return ERROR_SUCCESS; 800 } 801 802 UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, 803 INT iValue, FILETIME *pftValue, LPCWSTR szValue ) 804 { 805 awcstring str; 806 MSISUMMARYINFO *si; 807 UINT type, ret; 808 809 TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue, 810 debugstr_w(szValue) ); 811 812 type = get_type( uiProperty ); 813 if( type == VT_EMPTY || type != uiDataType ) 814 return ERROR_DATATYPE_MISMATCH; 815 816 if( uiDataType == VT_LPSTR && !szValue ) 817 return ERROR_INVALID_PARAMETER; 818 819 if( uiDataType == VT_FILETIME && !pftValue ) 820 return ERROR_INVALID_PARAMETER; 821 822 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 823 return ERROR_INVALID_HANDLE; 824 825 str.unicode = TRUE; 826 str.str.w = szValue; 827 828 ret = set_prop( si, uiProperty, type, iValue, pftValue, &str ); 829 msiobj_release( &si->hdr ); 830 return ret; 831 } 832 833 UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, 834 INT iValue, FILETIME *pftValue, LPCSTR szValue ) 835 { 836 awcstring str; 837 MSISUMMARYINFO *si; 838 UINT type, ret; 839 840 TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue, 841 debugstr_a(szValue) ); 842 843 type = get_type( uiProperty ); 844 if( type == VT_EMPTY || type != uiDataType ) 845 return ERROR_DATATYPE_MISMATCH; 846 847 if( uiDataType == VT_LPSTR && !szValue ) 848 return ERROR_INVALID_PARAMETER; 849 850 if( uiDataType == VT_FILETIME && !pftValue ) 851 return ERROR_INVALID_PARAMETER; 852 853 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 854 return ERROR_INVALID_HANDLE; 855 856 str.unicode = FALSE; 857 str.str.a = szValue; 858 859 ret = set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str ); 860 msiobj_release( &si->hdr ); 861 return ret; 862 } 863 864 static UINT suminfo_persist( MSISUMMARYINFO *si ) 865 { 866 UINT ret = ERROR_FUNCTION_FAILED; 867 IStream *stm = NULL; 868 DWORD grfMode; 869 HRESULT r; 870 871 grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE; 872 r = IStorage_CreateStream( si->storage, szSumInfo, grfMode, 0, 0, &stm ); 873 if( SUCCEEDED(r) ) 874 { 875 ret = save_summary_info( si, stm ); 876 IStream_Release( stm ); 877 } 878 return ret; 879 } 880 881 static void parse_filetime( LPCWSTR str, FILETIME *ft ) 882 { 883 SYSTEMTIME lt, utc; 884 const WCHAR *p = str; 885 WCHAR *end; 886 887 memset( <, 0, sizeof(lt) ); 888 889 /* YYYY/MM/DD hh:mm:ss */ 890 891 while (isspaceW( *p )) p++; 892 893 lt.wYear = strtolW( p, &end, 10 ); 894 if (*end != '/') return; 895 p = end + 1; 896 897 lt.wMonth = strtolW( p, &end, 10 ); 898 if (*end != '/') return; 899 p = end + 1; 900 901 lt.wDay = strtolW( p, &end, 10 ); 902 if (*end != ' ') return; 903 p = end + 1; 904 905 while (isspaceW( *p )) p++; 906 907 lt.wHour = strtolW( p, &end, 10 ); 908 if (*end != ':') return; 909 p = end + 1; 910 911 lt.wMinute = strtolW( p, &end, 10 ); 912 if (*end != ':') return; 913 p = end + 1; 914 915 lt.wSecond = strtolW( p, &end, 10 ); 916 917 TzSpecificLocalTimeToSystemTime( NULL, <, &utc ); 918 SystemTimeToFileTime( &utc, ft ); 919 } 920 921 static UINT parse_prop( LPCWSTR prop, LPCWSTR value, UINT *pid, INT *int_value, 922 FILETIME *ft_value, awcstring *str_value ) 923 { 924 *pid = atoiW( prop ); 925 switch (*pid) 926 { 927 case PID_CODEPAGE: 928 case PID_WORDCOUNT: 929 case PID_CHARCOUNT: 930 case PID_SECURITY: 931 case PID_PAGECOUNT: 932 *int_value = atoiW( value ); 933 break; 934 935 case PID_LASTPRINTED: 936 case PID_CREATE_DTM: 937 case PID_LASTSAVE_DTM: 938 parse_filetime( value, ft_value ); 939 break; 940 941 case PID_SUBJECT: 942 case PID_AUTHOR: 943 case PID_KEYWORDS: 944 case PID_COMMENTS: 945 case PID_TEMPLATE: 946 case PID_LASTAUTHOR: 947 case PID_REVNUMBER: 948 case PID_APPNAME: 949 case PID_TITLE: 950 str_value->str.w = value; 951 str_value->unicode = TRUE; 952 break; 953 954 default: 955 WARN("unhandled prop id %u\n", *pid); 956 return ERROR_FUNCTION_FAILED; 957 } 958 959 return ERROR_SUCCESS; 960 } 961 962 UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ) 963 { 964 UINT r; 965 int i, j; 966 MSISUMMARYINFO *si; 967 968 r = msi_get_suminfo( db->storage, num_records * (num_columns / 2), &si ); 969 if (r != ERROR_SUCCESS) 970 { 971 if (!(si = create_suminfo( db->storage, num_records * (num_columns / 2) ))) 972 return ERROR_OUTOFMEMORY; 973 r = ERROR_SUCCESS; 974 } 975 976 for (i = 0; i < num_records; i++) 977 { 978 for (j = 0; j < num_columns; j += 2) 979 { 980 UINT pid; 981 INT int_value = 0; 982 FILETIME ft_value; 983 awcstring str_value; 984 985 r = parse_prop( records[i][j], records[i][j + 1], &pid, &int_value, &ft_value, &str_value ); 986 if (r != ERROR_SUCCESS) 987 goto end; 988 989 r = set_prop( si, pid, get_type(pid), int_value, &ft_value, &str_value ); 990 if (r != ERROR_SUCCESS) 991 goto end; 992 } 993 } 994 995 end: 996 if (r == ERROR_SUCCESS) 997 r = suminfo_persist( si ); 998 999 msiobj_release( &si->hdr ); 1000 return r; 1001 } 1002 1003 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle ) 1004 { 1005 MSISUMMARYINFO *si; 1006 UINT ret; 1007 1008 TRACE("%d\n", handle ); 1009 1010 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ); 1011 if( !si ) 1012 return ERROR_INVALID_HANDLE; 1013 1014 ret = suminfo_persist( si ); 1015 1016 msiobj_release( &si->hdr ); 1017 return ret; 1018 } 1019 1020 UINT WINAPI MsiCreateTransformSummaryInfoA( MSIHANDLE db, MSIHANDLE db_ref, LPCSTR transform, int error, int validation ) 1021 { 1022 UINT r; 1023 WCHAR *transformW = NULL; 1024 1025 TRACE("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_a(transform), error, validation); 1026 1027 if (transform && !(transformW = strdupAtoW( transform ))) 1028 return ERROR_OUTOFMEMORY; 1029 1030 r = MsiCreateTransformSummaryInfoW( db, db_ref, transformW, error, validation ); 1031 msi_free( transformW ); 1032 return r; 1033 } 1034 1035 UINT WINAPI MsiCreateTransformSummaryInfoW( MSIHANDLE db, MSIHANDLE db_ref, LPCWSTR transform, int error, int validation ) 1036 { 1037 FIXME("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_w(transform), error, validation); 1038 return ERROR_FUNCTION_FAILED; 1039 } 1040 1041 UINT msi_load_suminfo_properties( MSIPACKAGE *package ) 1042 { 1043 static const WCHAR packagecodeW[] = {'P','a','c','k','a','g','e','C','o','d','e',0}; 1044 MSISUMMARYINFO *si; 1045 WCHAR *package_code; 1046 UINT r, len; 1047 awstring str; 1048 INT count; 1049 1050 r = msi_get_suminfo( package->db->storage, 0, &si ); 1051 if (r != ERROR_SUCCESS) 1052 { 1053 r = msi_get_db_suminfo( package->db, 0, &si ); 1054 if (r != ERROR_SUCCESS) 1055 { 1056 ERR("Unable to open summary information stream %u\n", r); 1057 return r; 1058 } 1059 } 1060 1061 str.unicode = TRUE; 1062 str.str.w = NULL; 1063 len = 0; 1064 r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len ); 1065 if (r != ERROR_MORE_DATA) 1066 { 1067 WARN("Unable to query revision number %u\n", r); 1068 msiobj_release( &si->hdr ); 1069 return ERROR_FUNCTION_FAILED; 1070 } 1071 1072 len++; 1073 if (!(package_code = msi_alloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; 1074 str.str.w = package_code; 1075 1076 r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len ); 1077 if (r != ERROR_SUCCESS) 1078 { 1079 msi_free( package_code ); 1080 msiobj_release( &si->hdr ); 1081 return r; 1082 } 1083 1084 r = msi_set_property( package->db, packagecodeW, package_code, len ); 1085 msi_free( package_code ); 1086 1087 count = 0; 1088 get_prop( si, PID_WORDCOUNT, NULL, &count, NULL, NULL, NULL ); 1089 package->WordCount = count; 1090 1091 msiobj_release( &si->hdr ); 1092 return r; 1093 } 1094