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 <stdarg.h> 22 23 #define COBJMACROS 24 25 #include "stdio.h" 26 #include "windef.h" 27 #include "winbase.h" 28 #include "winreg.h" 29 #include "winnls.h" 30 #include "shlwapi.h" 31 #include "wine/debug.h" 32 #include "wine/exception.h" 33 #include "msi.h" 34 #include "msiquery.h" 35 #include "msidefs.h" 36 #include "objidl.h" 37 #include "propvarutil.h" 38 39 #include "msipriv.h" 40 #include "winemsi_s.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(msi); 43 44 #include "pshpack1.h" 45 46 struct property_set_header 47 { 48 WORD wByteOrder; 49 WORD wFormat; 50 DWORD dwOSVer; 51 CLSID clsID; 52 DWORD reserved; 53 }; 54 55 struct format_id_offset 56 { 57 FMTID fmtid; 58 DWORD dwOffset; 59 }; 60 61 struct property_section_header 62 { 63 DWORD cbSection; 64 DWORD cProperties; 65 }; 66 67 struct property_id_offset 68 { 69 DWORD propid; 70 DWORD dwOffset; 71 }; 72 73 struct property_data 74 { 75 DWORD type; 76 union { 77 INT i4; 78 SHORT i2; 79 FILETIME ft; 80 struct { 81 DWORD len; 82 BYTE str[1]; 83 } str; 84 } u; 85 }; 86 87 #include "poppack.h" 88 89 static HRESULT (WINAPI *pPropVariantChangeType) 90 (PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc, 91 PROPVAR_CHANGE_FLAGS flags, VARTYPE vt); 92 93 #define SECT_HDR_SIZE (sizeof(struct property_section_header)) 94 95 static void free_prop( PROPVARIANT *prop ) 96 { 97 if (prop->vt == VT_LPSTR ) 98 free( prop->pszVal ); 99 prop->vt = VT_EMPTY; 100 } 101 102 static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg ) 103 { 104 MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg; 105 DWORD i; 106 107 for( i = 0; i < MSI_MAX_PROPS; i++ ) 108 free_prop( &si->property[i] ); 109 IStorage_Release( si->storage ); 110 } 111 112 #ifdef __REACTOS__ 113 #define PID_DICTIONARY_MSI 0 114 #define PID_CODEPAGE_MSI 1 115 #define PID_SECURITY_MSI 19 116 #endif 117 118 static UINT get_type( UINT uiProperty ) 119 { 120 switch( uiProperty ) 121 { 122 #ifdef __REACTOS__ 123 case PID_CODEPAGE_MSI: 124 #else 125 case PID_CODEPAGE: 126 #endif 127 return VT_I2; 128 129 case PID_SUBJECT: 130 case PID_AUTHOR: 131 case PID_KEYWORDS: 132 case PID_COMMENTS: 133 case PID_TEMPLATE: 134 case PID_LASTAUTHOR: 135 case PID_REVNUMBER: 136 case PID_APPNAME: 137 case PID_TITLE: 138 return VT_LPSTR; 139 140 case PID_LASTPRINTED: 141 case PID_CREATE_DTM: 142 case PID_LASTSAVE_DTM: 143 return VT_FILETIME; 144 145 case PID_WORDCOUNT: 146 case PID_CHARCOUNT: 147 #ifdef __REACTOS__ 148 case PID_SECURITY_MSI: 149 #else 150 case PID_SECURITY: 151 #endif 152 case PID_PAGECOUNT: 153 return VT_I4; 154 } 155 return VT_EMPTY; 156 } 157 158 static UINT get_property_count( const PROPVARIANT *property ) 159 { 160 UINT i, n = 0; 161 162 if( !property ) 163 return n; 164 for( i = 0; i < MSI_MAX_PROPS; i++ ) 165 if( property[i].vt != VT_EMPTY ) 166 n++; 167 return n; 168 } 169 170 static UINT propvar_changetype(PROPVARIANT *changed, PROPVARIANT *property, VARTYPE vt) 171 { 172 HRESULT hr; 173 HMODULE propsys = LoadLibraryA("propsys.dll"); 174 pPropVariantChangeType = (void *)GetProcAddress(propsys, "PropVariantChangeType"); 175 176 if (!pPropVariantChangeType) 177 { 178 ERR("PropVariantChangeType function missing!\n"); 179 return ERROR_FUNCTION_FAILED; 180 } 181 182 hr = pPropVariantChangeType(changed, property, 0, vt); 183 return (hr == S_OK) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED; 184 } 185 186 /* FIXME: doesn't deal with endian conversion */ 187 static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz ) 188 { 189 UINT type; 190 DWORD i, size; 191 struct property_data *propdata; 192 PROPVARIANT property, *ptr; 193 PROPVARIANT changed; 194 struct property_id_offset *idofs; 195 struct property_section_header *section_hdr; 196 197 section_hdr = (struct property_section_header *) &data[0]; 198 idofs = (struct property_id_offset *)&data[SECT_HDR_SIZE]; 199 200 /* now set all the properties */ 201 for( i = 0; i < section_hdr->cProperties; i++ ) 202 { 203 if( idofs[i].propid >= MSI_MAX_PROPS ) 204 { 205 ERR( "unknown property ID %lu\n", idofs[i].propid ); 206 break; 207 } 208 209 type = get_type( idofs[i].propid ); 210 if( type == VT_EMPTY ) 211 { 212 ERR( "propid %lu has unknown type\n", idofs[i].propid ); 213 break; 214 } 215 216 propdata = (struct property_data *)&data[ idofs[i].dwOffset ]; 217 218 /* check we don't run off the end of the data */ 219 size = sz - idofs[i].dwOffset - sizeof(DWORD); 220 if( sizeof(DWORD) > size || 221 ( propdata->type == VT_FILETIME && sizeof(FILETIME) > size ) || 222 ( propdata->type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) ) 223 { 224 ERR("not enough data\n"); 225 break; 226 } 227 228 property.vt = propdata->type; 229 if( propdata->type == VT_LPSTR ) 230 { 231 char *str = malloc( propdata->u.str.len ); 232 memcpy( str, propdata->u.str.str, propdata->u.str.len ); 233 str[ propdata->u.str.len - 1 ] = 0; 234 property.pszVal = str; 235 } 236 else if( propdata->type == VT_FILETIME ) 237 property.filetime = propdata->u.ft; 238 else if( propdata->type == VT_I2 ) 239 property.iVal = propdata->u.i2; 240 else if( propdata->type == VT_I4 ) 241 property.lVal = propdata->u.i4; 242 243 /* check the type is the same as we expect */ 244 if( type != propdata->type ) 245 { 246 propvar_changetype(&changed, &property, type); 247 ptr = &changed; 248 } 249 else 250 ptr = &property; 251 252 prop[ idofs[i].propid ] = *ptr; 253 } 254 } 255 256 static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm ) 257 { 258 struct property_set_header set_hdr; 259 struct format_id_offset format_hdr; 260 struct property_section_header section_hdr; 261 LPBYTE data = NULL; 262 LARGE_INTEGER ofs; 263 ULONG count, sz; 264 HRESULT r; 265 266 TRACE("%p %p\n", si, stm); 267 268 /* read the header */ 269 sz = sizeof set_hdr; 270 r = IStream_Read( stm, &set_hdr, sz, &count ); 271 if( FAILED(r) || count != sz ) 272 return ERROR_FUNCTION_FAILED; 273 274 if( set_hdr.wByteOrder != 0xfffe ) 275 { 276 ERR("property set not big-endian %04X\n", set_hdr.wByteOrder); 277 return ERROR_FUNCTION_FAILED; 278 } 279 280 sz = sizeof format_hdr; 281 r = IStream_Read( stm, &format_hdr, sz, &count ); 282 if( FAILED(r) || count != sz ) 283 return ERROR_FUNCTION_FAILED; 284 285 /* check the format id is correct */ 286 if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) ) 287 return ERROR_FUNCTION_FAILED; 288 289 /* seek to the location of the section */ 290 ofs.QuadPart = format_hdr.dwOffset; 291 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL ); 292 if( FAILED(r) ) 293 return ERROR_FUNCTION_FAILED; 294 295 /* read the section itself */ 296 sz = SECT_HDR_SIZE; 297 r = IStream_Read( stm, §ion_hdr, sz, &count ); 298 if( FAILED(r) || count != sz ) 299 return ERROR_FUNCTION_FAILED; 300 301 if( section_hdr.cProperties > MSI_MAX_PROPS ) 302 { 303 ERR( "too many properties %lu\n", section_hdr.cProperties ); 304 return ERROR_FUNCTION_FAILED; 305 } 306 307 data = malloc( section_hdr.cbSection ); 308 if( !data ) 309 return ERROR_FUNCTION_FAILED; 310 311 memcpy( data, §ion_hdr, SECT_HDR_SIZE ); 312 313 /* read all the data in one go */ 314 sz = section_hdr.cbSection - SECT_HDR_SIZE; 315 r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count ); 316 if( SUCCEEDED(r) && count == sz ) 317 read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE ); 318 else 319 ERR( "failed to read properties %lu %lu\n", count, sz ); 320 321 free( data ); 322 return ERROR_SUCCESS; 323 } 324 325 static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val ) 326 { 327 if( data ) 328 { 329 data[ofs++] = val&0xff; 330 data[ofs++] = (val>>8)&0xff; 331 data[ofs++] = (val>>16)&0xff; 332 data[ofs++] = (val>>24)&0xff; 333 } 334 return 4; 335 } 336 337 static DWORD write_filetime( LPBYTE data, DWORD ofs, const FILETIME *ft ) 338 { 339 write_dword( data, ofs, ft->dwLowDateTime ); 340 write_dword( data, ofs + 4, ft->dwHighDateTime ); 341 return 8; 342 } 343 344 static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str ) 345 { 346 DWORD len = lstrlenA( str ) + 1; 347 write_dword( data, ofs, len ); 348 if( data ) 349 memcpy( &data[ofs + 4], str, len ); 350 return (7 + len) & ~3; 351 } 352 353 static UINT write_property_to_data( const PROPVARIANT *prop, LPBYTE data ) 354 { 355 DWORD sz = 0; 356 357 if( prop->vt == VT_EMPTY ) 358 return sz; 359 360 /* add the type */ 361 sz += write_dword( data, sz, prop->vt ); 362 switch( prop->vt ) 363 { 364 case VT_I2: 365 sz += write_dword( data, sz, prop->iVal ); 366 break; 367 case VT_I4: 368 sz += write_dword( data, sz, prop->lVal ); 369 break; 370 case VT_FILETIME: 371 sz += write_filetime( data, sz, &prop->filetime ); 372 break; 373 case VT_LPSTR: 374 sz += write_string( data, sz, prop->pszVal ); 375 break; 376 } 377 return sz; 378 } 379 380 static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm ) 381 { 382 UINT ret = ERROR_FUNCTION_FAILED; 383 struct property_set_header set_hdr; 384 struct format_id_offset format_hdr; 385 struct property_section_header section_hdr; 386 struct property_id_offset idofs[MSI_MAX_PROPS]; 387 LPBYTE data = NULL; 388 ULONG count, sz; 389 HRESULT r; 390 int i; 391 392 /* write the header */ 393 sz = sizeof set_hdr; 394 memset( &set_hdr, 0, sz ); 395 set_hdr.wByteOrder = 0xfffe; 396 set_hdr.wFormat = 0; 397 set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */ 398 /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */ 399 set_hdr.reserved = 1; 400 r = IStream_Write( stm, &set_hdr, sz, &count ); 401 if( FAILED(r) || count != sz ) 402 return ret; 403 404 /* write the format header */ 405 sz = sizeof format_hdr; 406 format_hdr.fmtid = FMTID_SummaryInformation; 407 format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr; 408 r = IStream_Write( stm, &format_hdr, sz, &count ); 409 if( FAILED(r) || count != sz ) 410 return ret; 411 412 /* add up how much space the data will take and calculate the offsets */ 413 section_hdr.cbSection = sizeof section_hdr; 414 section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]); 415 section_hdr.cProperties = 0; 416 for( i = 0; i < MSI_MAX_PROPS; i++ ) 417 { 418 sz = write_property_to_data( &si->property[i], NULL ); 419 if( !sz ) 420 continue; 421 idofs[ section_hdr.cProperties ].propid = i; 422 idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection; 423 section_hdr.cProperties++; 424 section_hdr.cbSection += sz; 425 } 426 427 data = calloc( 1, section_hdr.cbSection ); 428 429 sz = 0; 430 memcpy( &data[sz], §ion_hdr, sizeof section_hdr ); 431 sz += sizeof section_hdr; 432 433 memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] ); 434 sz += section_hdr.cProperties * sizeof idofs[0]; 435 436 /* write out the data */ 437 for( i = 0; i < MSI_MAX_PROPS; i++ ) 438 sz += write_property_to_data( &si->property[i], &data[sz] ); 439 440 r = IStream_Write( stm, data, sz, &count ); 441 free( data ); 442 if( FAILED(r) || count != sz ) 443 return ret; 444 445 return ERROR_SUCCESS; 446 } 447 448 static MSISUMMARYINFO *create_suminfo( IStorage *stg, UINT update_count ) 449 { 450 MSISUMMARYINFO *si; 451 452 if (!(si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, sizeof(MSISUMMARYINFO), MSI_CloseSummaryInfo ))) 453 return NULL; 454 455 si->update_count = update_count; 456 IStorage_AddRef( stg ); 457 si->storage = stg; 458 459 return si; 460 } 461 462 UINT msi_get_suminfo( IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **ret ) 463 { 464 IStream *stm; 465 MSISUMMARYINFO *si; 466 HRESULT hr; 467 UINT r; 468 469 TRACE("%p, %u\n", stg, uiUpdateCount); 470 471 if (!(si = create_suminfo( stg, uiUpdateCount ))) return ERROR_OUTOFMEMORY; 472 473 hr = IStorage_OpenStream( si->storage, L"\5SummaryInformation", 0, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stm ); 474 if (FAILED( hr )) 475 { 476 msiobj_release( &si->hdr ); 477 return ERROR_FUNCTION_FAILED; 478 } 479 480 r = load_summary_info( si, stm ); 481 IStream_Release( stm ); 482 if (r != ERROR_SUCCESS) 483 { 484 msiobj_release( &si->hdr ); 485 return r; 486 } 487 488 *ret = si; 489 return ERROR_SUCCESS; 490 } 491 492 UINT msi_get_db_suminfo( MSIDATABASE *db, UINT uiUpdateCount, MSISUMMARYINFO **ret ) 493 { 494 IStream *stm; 495 MSISUMMARYINFO *si; 496 UINT r; 497 498 if (!(si = create_suminfo( db->storage, uiUpdateCount ))) return ERROR_OUTOFMEMORY; 499 500 r = msi_get_stream( db, L"\5SummaryInformation", &stm ); 501 if (r != ERROR_SUCCESS) 502 { 503 msiobj_release( &si->hdr ); 504 return r; 505 } 506 507 r = load_summary_info( si, stm ); 508 IStream_Release( stm ); 509 if (r != ERROR_SUCCESS) 510 { 511 msiobj_release( &si->hdr ); 512 return r; 513 } 514 515 *ret = si; 516 return ERROR_SUCCESS; 517 } 518 519 UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, const WCHAR *szDatabase, UINT uiUpdateCount, 520 MSIHANDLE *pHandle ) 521 { 522 MSISUMMARYINFO *si; 523 MSIDATABASE *db; 524 UINT ret; 525 526 TRACE( "%lu, %s, %u, %p\n", hDatabase, debugstr_w(szDatabase), uiUpdateCount, pHandle ); 527 528 if( !pHandle ) 529 return ERROR_INVALID_PARAMETER; 530 531 if( szDatabase && szDatabase[0] ) 532 { 533 LPCWSTR persist = uiUpdateCount ? MSIDBOPEN_TRANSACT : MSIDBOPEN_READONLY; 534 535 ret = MSI_OpenDatabaseW( szDatabase, persist, &db ); 536 if( ret != ERROR_SUCCESS ) 537 return ret; 538 } 539 else 540 { 541 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE ); 542 if( !db ) 543 { 544 MSIHANDLE remote, remote_suminfo; 545 546 if (!(remote = msi_get_remote(hDatabase))) 547 return ERROR_INVALID_HANDLE; 548 549 __TRY 550 { 551 ret = remote_DatabaseGetSummaryInformation(remote, uiUpdateCount, &remote_suminfo); 552 } 553 __EXCEPT(rpc_filter) 554 { 555 ret = GetExceptionCode(); 556 } 557 __ENDTRY 558 559 if (!ret) 560 *pHandle = alloc_msi_remote_handle(remote_suminfo); 561 562 return ret; 563 } 564 } 565 566 ret = msi_get_suminfo( db->storage, uiUpdateCount, &si ); 567 if (ret != ERROR_SUCCESS) 568 ret = msi_get_db_suminfo( db, uiUpdateCount, &si ); 569 if (ret != ERROR_SUCCESS) 570 { 571 if ((si = create_suminfo( db->storage, uiUpdateCount ))) 572 ret = ERROR_SUCCESS; 573 } 574 575 if (ret == ERROR_SUCCESS) 576 { 577 *pHandle = alloc_msihandle( &si->hdr ); 578 if( *pHandle ) 579 ret = ERROR_SUCCESS; 580 else 581 ret = ERROR_NOT_ENOUGH_MEMORY; 582 msiobj_release( &si->hdr ); 583 } 584 585 msiobj_release( &db->hdr ); 586 return ret; 587 } 588 589 UINT WINAPI MsiGetSummaryInformationA( MSIHANDLE hDatabase, const char *szDatabase, UINT uiUpdateCount, 590 MSIHANDLE *pHandle ) 591 { 592 WCHAR *szwDatabase = NULL; 593 UINT ret; 594 595 TRACE( "%lu, %s, %u, %p\n", hDatabase, debugstr_a(szDatabase), uiUpdateCount, pHandle ); 596 597 if( szDatabase ) 598 { 599 szwDatabase = strdupAtoW( szDatabase ); 600 if( !szwDatabase ) 601 return ERROR_FUNCTION_FAILED; 602 } 603 604 ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle); 605 606 free( szwDatabase ); 607 608 return ret; 609 } 610 611 UINT WINAPI MsiSummaryInfoGetPropertyCount( MSIHANDLE hSummaryInfo, UINT *pCount ) 612 { 613 MSISUMMARYINFO *si; 614 615 TRACE( "%lu, %p\n", hSummaryInfo, pCount ); 616 617 si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO ); 618 if( !si ) 619 { 620 MSIHANDLE remote; 621 UINT ret; 622 623 if (!(remote = msi_get_remote( hSummaryInfo ))) 624 return ERROR_INVALID_HANDLE; 625 626 __TRY 627 { 628 ret = remote_SummaryInfoGetPropertyCount( remote, pCount ); 629 } 630 __EXCEPT(rpc_filter) 631 { 632 ret = GetExceptionCode(); 633 } 634 __ENDTRY 635 636 return ret; 637 } 638 639 if( pCount ) 640 *pCount = get_property_count( si->property ); 641 msiobj_release( &si->hdr ); 642 643 return ERROR_SUCCESS; 644 } 645 646 static UINT get_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT *puiDataType, INT *piValue, 647 FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf) 648 { 649 PROPVARIANT *prop; 650 UINT ret = ERROR_SUCCESS; 651 652 prop = &si->property[uiProperty]; 653 654 if( puiDataType ) 655 *puiDataType = prop->vt; 656 657 switch( prop->vt ) 658 { 659 case VT_I2: 660 if( piValue ) 661 *piValue = prop->iVal; 662 break; 663 case VT_I4: 664 if( piValue ) 665 *piValue = prop->lVal; 666 break; 667 case VT_LPSTR: 668 if( pcchValueBuf ) 669 { 670 DWORD len = 0; 671 672 if( str->unicode ) 673 { 674 len = MultiByteToWideChar( CP_ACP, 0, prop->pszVal, -1, NULL, 0 ) - 1; 675 MultiByteToWideChar( CP_ACP, 0, prop->pszVal, -1, str->str.w, *pcchValueBuf ); 676 } 677 else 678 { 679 len = lstrlenA( prop->pszVal ); 680 if( str->str.a ) 681 lstrcpynA(str->str.a, prop->pszVal, *pcchValueBuf ); 682 } 683 if (len >= *pcchValueBuf) 684 ret = ERROR_MORE_DATA; 685 *pcchValueBuf = len; 686 } 687 break; 688 case VT_FILETIME: 689 if( pftValue ) 690 *pftValue = prop->filetime; 691 break; 692 case VT_EMPTY: 693 break; 694 default: 695 FIXME("Unknown property variant type\n"); 696 break; 697 } 698 return ret; 699 } 700 701 LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) 702 { 703 PROPVARIANT *prop; 704 705 if ( uiProperty >= MSI_MAX_PROPS ) 706 return NULL; 707 prop = &si->property[uiProperty]; 708 if( prop->vt != VT_LPSTR ) 709 return NULL; 710 return strdupAtoW( prop->pszVal ); 711 } 712 713 INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) 714 { 715 PROPVARIANT *prop; 716 717 if ( uiProperty >= MSI_MAX_PROPS ) 718 return -1; 719 prop = &si->property[uiProperty]; 720 if( prop->vt != VT_I4 ) 721 return -1; 722 return prop->lVal; 723 } 724 725 LPWSTR msi_get_suminfo_product( IStorage *stg ) 726 { 727 MSISUMMARYINFO *si; 728 LPWSTR prod; 729 UINT r; 730 731 r = msi_get_suminfo( stg, 0, &si ); 732 if (r != ERROR_SUCCESS) 733 { 734 ERR("no summary information!\n"); 735 return NULL; 736 } 737 prod = msi_suminfo_dup_string( si, PID_REVNUMBER ); 738 msiobj_release( &si->hdr ); 739 return prod; 740 } 741 742 UINT WINAPI MsiSummaryInfoGetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue, 743 FILETIME *pftValue, char *szValueBuf, DWORD *pcchValueBuf ) 744 { 745 MSISUMMARYINFO *si; 746 awstring str; 747 UINT r; 748 749 TRACE( "%lu, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType, piValue, pftValue, szValueBuf, 750 pcchValueBuf ); 751 752 if (uiProperty >= MSI_MAX_PROPS) 753 { 754 if (puiDataType) *puiDataType = VT_EMPTY; 755 return ERROR_UNKNOWN_PROPERTY; 756 } 757 758 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 759 { 760 MSIHANDLE remote; 761 WCHAR *buf = NULL; 762 763 if (!(remote = msi_get_remote( handle ))) 764 return ERROR_INVALID_HANDLE; 765 766 __TRY 767 { 768 r = remote_SummaryInfoGetProperty( remote, uiProperty, puiDataType, piValue, pftValue, &buf ); 769 } 770 __EXCEPT(rpc_filter) 771 { 772 r = GetExceptionCode(); 773 } 774 __ENDTRY 775 776 if (!r && buf) 777 { 778 r = msi_strncpyWtoA( buf, -1, szValueBuf, pcchValueBuf, TRUE ); 779 } 780 781 midl_user_free( buf ); 782 return r; 783 } 784 785 str.unicode = FALSE; 786 str.str.a = szValueBuf; 787 788 r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf ); 789 msiobj_release( &si->hdr ); 790 return r; 791 } 792 793 UINT WINAPI MsiSummaryInfoGetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue, 794 FILETIME *pftValue, WCHAR *szValueBuf, DWORD *pcchValueBuf ) 795 { 796 MSISUMMARYINFO *si; 797 awstring str; 798 UINT r; 799 800 TRACE( "%lu, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType, piValue, pftValue, szValueBuf, 801 pcchValueBuf ); 802 803 if (uiProperty >= MSI_MAX_PROPS) 804 { 805 if (puiDataType) *puiDataType = VT_EMPTY; 806 return ERROR_UNKNOWN_PROPERTY; 807 } 808 809 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 810 { 811 MSIHANDLE remote; 812 WCHAR *buf = NULL; 813 814 if (!(remote = msi_get_remote( handle ))) 815 return ERROR_INVALID_HANDLE; 816 817 __TRY 818 { 819 r = remote_SummaryInfoGetProperty( remote, uiProperty, puiDataType, piValue, pftValue, &buf ); 820 } 821 __EXCEPT(rpc_filter) 822 { 823 r = GetExceptionCode(); 824 } 825 __ENDTRY 826 827 if (!r && buf) 828 r = msi_strncpyW( buf, -1, szValueBuf, pcchValueBuf ); 829 830 midl_user_free( buf ); 831 return r; 832 } 833 834 str.unicode = TRUE; 835 str.str.w = szValueBuf; 836 837 r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf ); 838 msiobj_release( &si->hdr ); 839 return r; 840 } 841 842 static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type, 843 INT iValue, FILETIME *pftValue, awcstring *str ) 844 { 845 PROPVARIANT *prop; 846 UINT len; 847 848 TRACE("%p, %u, %u, %d, %p, %p\n", si, uiProperty, type, iValue, pftValue, str ); 849 850 prop = &si->property[uiProperty]; 851 852 if( prop->vt == VT_EMPTY ) 853 { 854 if( !si->update_count ) 855 return ERROR_FUNCTION_FAILED; 856 857 si->update_count--; 858 } 859 else if( prop->vt != type ) 860 return ERROR_SUCCESS; 861 862 free_prop( prop ); 863 prop->vt = type; 864 switch( type ) 865 { 866 case VT_I4: 867 prop->lVal = iValue; 868 break; 869 case VT_I2: 870 prop->iVal = iValue; 871 break; 872 case VT_FILETIME: 873 prop->filetime = *pftValue; 874 break; 875 case VT_LPSTR: 876 if( str->unicode ) 877 { 878 len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1, 879 NULL, 0, NULL, NULL ); 880 prop->pszVal = malloc( len ); 881 WideCharToMultiByte( CP_ACP, 0, str->str.w, -1, 882 prop->pszVal, len, NULL, NULL ); 883 } 884 else 885 { 886 len = lstrlenA( str->str.a ) + 1; 887 prop->pszVal = malloc( len ); 888 lstrcpyA( prop->pszVal, str->str.a ); 889 } 890 break; 891 } 892 893 return ERROR_SUCCESS; 894 } 895 896 static UINT suminfo_set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT uiDataType, INT iValue, FILETIME *pftValue, 897 awcstring *str ) 898 { 899 UINT type = get_type( uiProperty ); 900 if( type == VT_EMPTY || type != uiDataType ) 901 return ERROR_DATATYPE_MISMATCH; 902 903 if( uiDataType == VT_LPSTR && !str->str.a ) 904 return ERROR_INVALID_PARAMETER; 905 906 if( uiDataType == VT_FILETIME && !pftValue ) 907 return ERROR_INVALID_PARAMETER; 908 909 return set_prop( si, uiProperty, type, iValue, pftValue, str ); 910 } 911 912 UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, INT iValue, 913 FILETIME *pftValue, const WCHAR *szValue ) 914 { 915 awcstring str; 916 MSISUMMARYINFO *si; 917 UINT ret; 918 919 TRACE( "%lu, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue, debugstr_w(szValue) ); 920 921 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 922 { 923 MSIHANDLE remote; 924 925 if ((remote = msi_get_remote( handle ))) 926 { 927 WARN("MsiSummaryInfoSetProperty not allowed during a custom action!\n"); 928 return ERROR_FUNCTION_FAILED; 929 } 930 931 return ERROR_INVALID_HANDLE; 932 } 933 934 str.unicode = TRUE; 935 str.str.w = szValue; 936 937 ret = suminfo_set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str ); 938 msiobj_release( &si->hdr ); 939 return ret; 940 } 941 942 UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, INT iValue, 943 FILETIME *pftValue, const char *szValue ) 944 { 945 awcstring str; 946 MSISUMMARYINFO *si; 947 UINT ret; 948 949 TRACE( "%lu, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue, debugstr_a(szValue) ); 950 951 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 952 { 953 MSIHANDLE remote; 954 955 if ((remote = msi_get_remote( handle ))) 956 { 957 WARN("MsiSummaryInfoSetProperty not allowed during a custom action!\n"); 958 return ERROR_FUNCTION_FAILED; 959 } 960 961 return ERROR_INVALID_HANDLE; 962 } 963 964 str.unicode = FALSE; 965 str.str.a = szValue; 966 967 ret = suminfo_set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str ); 968 msiobj_release( &si->hdr ); 969 return ret; 970 } 971 972 static UINT suminfo_persist( MSISUMMARYINFO *si ) 973 { 974 UINT ret = ERROR_FUNCTION_FAILED; 975 IStream *stm = NULL; 976 DWORD grfMode; 977 HRESULT r; 978 979 grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE; 980 r = IStorage_CreateStream( si->storage, L"\5SummaryInformation", grfMode, 0, 0, &stm ); 981 if( SUCCEEDED(r) ) 982 { 983 ret = save_summary_info( si, stm ); 984 IStream_Release( stm ); 985 } 986 return ret; 987 } 988 989 static void parse_filetime( LPCWSTR str, FILETIME *ft ) 990 { 991 SYSTEMTIME lt, utc; 992 const WCHAR *p = str; 993 WCHAR *end; 994 995 memset( <, 0, sizeof(lt) ); 996 997 /* YYYY/MM/DD hh:mm:ss */ 998 999 while (iswspace( *p )) p++; 1000 1001 lt.wYear = wcstol( p, &end, 10 ); 1002 if (*end != '/') return; 1003 p = end + 1; 1004 1005 lt.wMonth = wcstol( p, &end, 10 ); 1006 if (*end != '/') return; 1007 p = end + 1; 1008 1009 lt.wDay = wcstol( p, &end, 10 ); 1010 if (*end != ' ') return; 1011 p = end + 1; 1012 1013 while (iswspace( *p )) p++; 1014 1015 lt.wHour = wcstol( p, &end, 10 ); 1016 if (*end != ':') return; 1017 p = end + 1; 1018 1019 lt.wMinute = wcstol( p, &end, 10 ); 1020 if (*end != ':') return; 1021 p = end + 1; 1022 1023 lt.wSecond = wcstol( p, &end, 10 ); 1024 1025 TzSpecificLocalTimeToSystemTime( NULL, <, &utc ); 1026 SystemTimeToFileTime( &utc, ft ); 1027 } 1028 1029 static UINT parse_prop( LPCWSTR prop, LPCWSTR value, UINT *pid, INT *int_value, 1030 FILETIME *ft_value, awcstring *str_value ) 1031 { 1032 *pid = wcstol( prop, NULL, 10); 1033 switch (*pid) 1034 { 1035 #ifdef __REACTOS__ 1036 case PID_CODEPAGE_MSI: 1037 #else 1038 case PID_CODEPAGE: 1039 #endif 1040 case PID_WORDCOUNT: 1041 case PID_CHARCOUNT: 1042 #ifdef __REACTOS__ 1043 case PID_SECURITY_MSI: 1044 #else 1045 case PID_SECURITY: 1046 #endif 1047 case PID_PAGECOUNT: 1048 *int_value = wcstol( value, NULL, 10); 1049 break; 1050 1051 case PID_LASTPRINTED: 1052 case PID_CREATE_DTM: 1053 case PID_LASTSAVE_DTM: 1054 parse_filetime( value, ft_value ); 1055 break; 1056 1057 case PID_SUBJECT: 1058 case PID_AUTHOR: 1059 case PID_KEYWORDS: 1060 case PID_COMMENTS: 1061 case PID_TEMPLATE: 1062 case PID_LASTAUTHOR: 1063 case PID_REVNUMBER: 1064 case PID_APPNAME: 1065 case PID_TITLE: 1066 str_value->str.w = value; 1067 str_value->unicode = TRUE; 1068 break; 1069 1070 default: 1071 WARN("unhandled prop id %u\n", *pid); 1072 return ERROR_FUNCTION_FAILED; 1073 } 1074 1075 return ERROR_SUCCESS; 1076 } 1077 1078 UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ) 1079 { 1080 UINT r; 1081 int i, j; 1082 MSISUMMARYINFO *si; 1083 1084 r = msi_get_suminfo( db->storage, num_records * (num_columns / 2), &si ); 1085 if (r != ERROR_SUCCESS) 1086 { 1087 if (!(si = create_suminfo( db->storage, num_records * (num_columns / 2) ))) 1088 return ERROR_OUTOFMEMORY; 1089 r = ERROR_SUCCESS; 1090 } 1091 1092 for (i = 0; i < num_records; i++) 1093 { 1094 for (j = 0; j < num_columns; j += 2) 1095 { 1096 UINT pid; 1097 INT int_value = 0; 1098 FILETIME ft_value; 1099 awcstring str_value; 1100 1101 r = parse_prop( records[i][j], records[i][j + 1], &pid, &int_value, &ft_value, &str_value ); 1102 if (r != ERROR_SUCCESS) 1103 goto end; 1104 1105 r = set_prop( si, pid, get_type(pid), int_value, &ft_value, &str_value ); 1106 if (r != ERROR_SUCCESS) 1107 goto end; 1108 } 1109 } 1110 1111 end: 1112 if (r == ERROR_SUCCESS) 1113 r = suminfo_persist( si ); 1114 1115 msiobj_release( &si->hdr ); 1116 return r; 1117 } 1118 1119 static UINT save_prop( MSISUMMARYINFO *si, HANDLE handle, UINT row ) 1120 { 1121 static const char fmt_systemtime[] = "%04u/%02u/%02u %02u:%02u:%02u"; 1122 char data[36]; /* largest string: YYYY/MM/DD hh:mm:ss */ 1123 static const char fmt_begin[] = "%u\t"; 1124 static const char data_end[] = "\r\n"; 1125 static const char fmt_int[] = "%u"; 1126 UINT r, data_type; 1127 SYSTEMTIME system_time; 1128 FILETIME file_time; 1129 INT int_value; 1130 awstring str; 1131 DWORD len, sz; 1132 1133 str.unicode = FALSE; 1134 str.str.a = NULL; 1135 len = 0; 1136 r = get_prop( si, row, &data_type, &int_value, &file_time, &str, &len ); 1137 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) 1138 return r; 1139 if (data_type == VT_EMPTY) 1140 return ERROR_SUCCESS; /* property not set */ 1141 sz = sprintf( data, fmt_begin, row ); 1142 if (!WriteFile( handle, data, sz, &sz, NULL )) 1143 return ERROR_WRITE_FAULT; 1144 1145 switch( data_type ) 1146 { 1147 case VT_I2: 1148 case VT_I4: 1149 sz = sprintf( data, fmt_int, int_value ); 1150 if (!WriteFile( handle, data, sz, &sz, NULL )) 1151 return ERROR_WRITE_FAULT; 1152 break; 1153 case VT_LPSTR: 1154 len++; 1155 if (!(str.str.a = malloc( len ))) 1156 return ERROR_OUTOFMEMORY; 1157 r = get_prop( si, row, NULL, NULL, NULL, &str, &len ); 1158 if (r != ERROR_SUCCESS) 1159 { 1160 free( str.str.a ); 1161 return r; 1162 } 1163 sz = len; 1164 if (!WriteFile( handle, str.str.a, sz, &sz, NULL )) 1165 { 1166 free( str.str.a ); 1167 return ERROR_WRITE_FAULT; 1168 } 1169 free( str.str.a ); 1170 break; 1171 case VT_FILETIME: 1172 if (!FileTimeToSystemTime( &file_time, &system_time )) 1173 return ERROR_FUNCTION_FAILED; 1174 sz = sprintf( data, fmt_systemtime, system_time.wYear, system_time.wMonth, 1175 system_time.wDay, system_time.wHour, system_time.wMinute, 1176 system_time.wSecond ); 1177 if (!WriteFile( handle, data, sz, &sz, NULL )) 1178 return ERROR_WRITE_FAULT; 1179 break; 1180 case VT_EMPTY: 1181 /* cannot reach here, property not set */ 1182 break; 1183 default: 1184 FIXME( "Unknown property variant type\n" ); 1185 return ERROR_FUNCTION_FAILED; 1186 } 1187 1188 sz = ARRAY_SIZE(data_end) - 1; 1189 if (!WriteFile( handle, data_end, sz, &sz, NULL )) 1190 return ERROR_WRITE_FAULT; 1191 1192 return ERROR_SUCCESS; 1193 } 1194 1195 UINT msi_export_suminfo( MSIDATABASE *db, HANDLE handle ) 1196 { 1197 UINT i, r, num_rows; 1198 MSISUMMARYINFO *si; 1199 1200 r = msi_get_suminfo( db->storage, 0, &si ); 1201 if (r != ERROR_SUCCESS) 1202 r = msi_get_db_suminfo( db, 0, &si ); 1203 if (r != ERROR_SUCCESS) 1204 return r; 1205 1206 num_rows = get_property_count( si->property ); 1207 if (!num_rows) 1208 { 1209 msiobj_release( &si->hdr ); 1210 return ERROR_FUNCTION_FAILED; 1211 } 1212 1213 for (i = 0; i < num_rows; i++) 1214 { 1215 r = save_prop( si, handle, i ); 1216 if (r != ERROR_SUCCESS) 1217 { 1218 msiobj_release( &si->hdr ); 1219 return r; 1220 } 1221 } 1222 1223 msiobj_release( &si->hdr ); 1224 return ERROR_SUCCESS; 1225 } 1226 1227 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle ) 1228 { 1229 MSISUMMARYINFO *si; 1230 UINT ret; 1231 1232 TRACE( "%lu\n", handle ); 1233 1234 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ); 1235 if( !si ) 1236 return ERROR_INVALID_HANDLE; 1237 1238 ret = suminfo_persist( si ); 1239 1240 msiobj_release( &si->hdr ); 1241 return ret; 1242 } 1243 1244 UINT WINAPI MsiCreateTransformSummaryInfoA( MSIHANDLE db, MSIHANDLE db_ref, const char *transform, int error, 1245 int validation ) 1246 { 1247 UINT r; 1248 WCHAR *transformW = NULL; 1249 1250 TRACE( "%lu, %lu, %s, %d, %d\n", db, db_ref, debugstr_a(transform), error, validation ); 1251 1252 if (transform && !(transformW = strdupAtoW( transform ))) 1253 return ERROR_OUTOFMEMORY; 1254 1255 r = MsiCreateTransformSummaryInfoW( db, db_ref, transformW, error, validation ); 1256 free( transformW ); 1257 return r; 1258 } 1259 1260 UINT WINAPI MsiCreateTransformSummaryInfoW( MSIHANDLE db, MSIHANDLE db_ref, const WCHAR *transform, int error, 1261 int validation ) 1262 { 1263 FIXME( "%lu, %lu, %s, %d, %d\n", db, db_ref, debugstr_w(transform), error, validation ); 1264 return ERROR_FUNCTION_FAILED; 1265 } 1266 1267 UINT msi_load_suminfo_properties( MSIPACKAGE *package ) 1268 { 1269 MSISUMMARYINFO *si; 1270 WCHAR *package_code; 1271 UINT r; 1272 DWORD len; 1273 awstring str; 1274 INT count; 1275 1276 r = msi_get_suminfo( package->db->storage, 0, &si ); 1277 if (r != ERROR_SUCCESS) 1278 { 1279 r = msi_get_db_suminfo( package->db, 0, &si ); 1280 if (r != ERROR_SUCCESS) 1281 { 1282 ERR("Unable to open summary information stream %u\n", r); 1283 return r; 1284 } 1285 } 1286 1287 str.unicode = TRUE; 1288 str.str.w = NULL; 1289 len = 0; 1290 r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len ); 1291 if (r != ERROR_MORE_DATA) 1292 { 1293 WARN("Unable to query revision number %u\n", r); 1294 msiobj_release( &si->hdr ); 1295 return ERROR_FUNCTION_FAILED; 1296 } 1297 1298 len++; 1299 if (!(package_code = malloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; 1300 str.str.w = package_code; 1301 1302 r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len ); 1303 if (r != ERROR_SUCCESS) 1304 { 1305 free( package_code ); 1306 msiobj_release( &si->hdr ); 1307 return r; 1308 } 1309 1310 r = msi_set_property( package->db, L"PackageCode", package_code, len ); 1311 free( package_code ); 1312 1313 count = 0; 1314 get_prop( si, PID_WORDCOUNT, NULL, &count, NULL, NULL, NULL ); 1315 package->WordCount = count; 1316 1317 msiobj_release( &si->hdr ); 1318 return r; 1319 } 1320 1321 UINT __cdecl s_remote_SummaryInfoGetPropertyCount( MSIHANDLE suminfo, UINT *count ) 1322 { 1323 return MsiSummaryInfoGetPropertyCount( suminfo, count ); 1324 } 1325 1326 UINT __cdecl s_remote_SummaryInfoGetProperty( MSIHANDLE suminfo, UINT property, UINT *type, 1327 INT *value, FILETIME *ft, LPWSTR *buf ) 1328 { 1329 WCHAR empty[1]; 1330 DWORD size = 0; 1331 UINT r; 1332 1333 r = MsiSummaryInfoGetPropertyW( suminfo, property, type, value, ft, empty, &size ); 1334 if (r == ERROR_MORE_DATA) 1335 { 1336 size++; 1337 *buf = midl_user_allocate( size * sizeof(WCHAR) ); 1338 if (!*buf) return ERROR_OUTOFMEMORY; 1339 r = MsiSummaryInfoGetPropertyW( suminfo, property, type, value, ft, *buf, &size ); 1340 } 1341 return r; 1342 } 1343