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