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 #define NONAMELESSUNION 25 26 #include "stdio.h" 27 #include "windef.h" 28 #include "winbase.h" 29 #include "winreg.h" 30 #include "winnls.h" 31 #include "shlwapi.h" 32 #include "wine/debug.h" 33 #include "wine/unicode.h" 34 #include "msi.h" 35 #include "msiquery.h" 36 #include "msidefs.h" 37 #include "msipriv.h" 38 #include "objidl.h" 39 #include "propvarutil.h" 40 #include "msiserver.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->u.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 %d\n", idofs[i].propid ); 201 break; 202 } 203 204 type = get_type( idofs[i].propid ); 205 if( type == VT_EMPTY ) 206 { 207 ERR("propid %d 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.u.pszVal = str; 230 } 231 else if( propdata->type == VT_FILETIME ) 232 property.u.filetime = propdata->u.ft; 233 else if( propdata->type == VT_I2 ) 234 property.u.iVal = propdata->u.i2; 235 else if( propdata->type == VT_I4 ) 236 property.u.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 %d\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 %d %d\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->u.iVal ); 361 break; 362 case VT_I4: 363 sz += write_dword( data, sz, prop->u.lVal ); 364 break; 365 case VT_FILETIME: 366 sz += write_filetime( data, sz, &prop->u.filetime ); 367 break; 368 case VT_LPSTR: 369 sz += write_string( data, sz, prop->u.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, szSumInfo, 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, szSumInfo, &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, 515 LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle ) 516 { 517 MSISUMMARYINFO *si; 518 MSIDATABASE *db; 519 UINT ret; 520 521 TRACE("%d %s %d %p\n", hDatabase, debugstr_w(szDatabase), 522 uiUpdateCount, pHandle); 523 524 if( !pHandle ) 525 return ERROR_INVALID_PARAMETER; 526 527 if( szDatabase && szDatabase[0] ) 528 { 529 LPCWSTR persist = uiUpdateCount ? MSIDBOPEN_TRANSACT : MSIDBOPEN_READONLY; 530 531 ret = MSI_OpenDatabaseW( szDatabase, persist, &db ); 532 if( ret != ERROR_SUCCESS ) 533 return ret; 534 } 535 else 536 { 537 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE ); 538 if( !db ) 539 { 540 HRESULT hr; 541 IWineMsiRemoteDatabase *remote_database; 542 543 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hDatabase ); 544 if ( !remote_database ) 545 return ERROR_INVALID_HANDLE; 546 547 hr = IWineMsiRemoteDatabase_GetSummaryInformation( remote_database, 548 uiUpdateCount, pHandle ); 549 IWineMsiRemoteDatabase_Release( remote_database ); 550 551 if (FAILED(hr)) 552 { 553 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) 554 return HRESULT_CODE(hr); 555 556 return ERROR_FUNCTION_FAILED; 557 } 558 559 return ERROR_SUCCESS; 560 } 561 } 562 563 ret = msi_get_suminfo( db->storage, uiUpdateCount, &si ); 564 if (ret != ERROR_SUCCESS) 565 ret = msi_get_db_suminfo( db, uiUpdateCount, &si ); 566 if (ret != ERROR_SUCCESS) 567 { 568 if ((si = create_suminfo( db->storage, uiUpdateCount ))) 569 ret = ERROR_SUCCESS; 570 } 571 572 if (ret == ERROR_SUCCESS) 573 { 574 *pHandle = alloc_msihandle( &si->hdr ); 575 if( *pHandle ) 576 ret = ERROR_SUCCESS; 577 else 578 ret = ERROR_NOT_ENOUGH_MEMORY; 579 msiobj_release( &si->hdr ); 580 } 581 582 msiobj_release( &db->hdr ); 583 return ret; 584 } 585 586 UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase, 587 LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle) 588 { 589 LPWSTR szwDatabase = NULL; 590 UINT ret; 591 592 TRACE("%d %s %d %p\n", hDatabase, debugstr_a(szDatabase), 593 uiUpdateCount, pHandle); 594 595 if( szDatabase ) 596 { 597 szwDatabase = strdupAtoW( szDatabase ); 598 if( !szwDatabase ) 599 return ERROR_FUNCTION_FAILED; 600 } 601 602 ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle); 603 604 msi_free( szwDatabase ); 605 606 return ret; 607 } 608 609 UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, PUINT pCount) 610 { 611 MSISUMMARYINFO *si; 612 613 TRACE("%d %p\n", hSummaryInfo, pCount); 614 615 si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO ); 616 if( !si ) 617 return ERROR_INVALID_HANDLE; 618 619 if( pCount ) 620 *pCount = get_property_count( si->property ); 621 msiobj_release( &si->hdr ); 622 623 return ERROR_SUCCESS; 624 } 625 626 static UINT get_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT *puiDataType, INT *piValue, 627 FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf) 628 { 629 PROPVARIANT *prop; 630 UINT ret = ERROR_SUCCESS; 631 632 prop = &si->property[uiProperty]; 633 634 if( puiDataType ) 635 *puiDataType = prop->vt; 636 637 switch( prop->vt ) 638 { 639 case VT_I2: 640 if( piValue ) 641 *piValue = prop->u.iVal; 642 break; 643 case VT_I4: 644 if( piValue ) 645 *piValue = prop->u.lVal; 646 break; 647 case VT_LPSTR: 648 if( pcchValueBuf ) 649 { 650 DWORD len = 0; 651 652 if( str->unicode ) 653 { 654 len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, NULL, 0 ) - 1; 655 MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, str->str.w, *pcchValueBuf ); 656 } 657 else 658 { 659 len = lstrlenA( prop->u.pszVal ); 660 if( str->str.a ) 661 lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf ); 662 } 663 if (len >= *pcchValueBuf) 664 ret = ERROR_MORE_DATA; 665 *pcchValueBuf = len; 666 } 667 break; 668 case VT_FILETIME: 669 if( pftValue ) 670 *pftValue = prop->u.filetime; 671 break; 672 case VT_EMPTY: 673 break; 674 default: 675 FIXME("Unknown property variant type\n"); 676 break; 677 } 678 return ret; 679 } 680 681 LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) 682 { 683 PROPVARIANT *prop; 684 685 if ( uiProperty >= MSI_MAX_PROPS ) 686 return NULL; 687 prop = &si->property[uiProperty]; 688 if( prop->vt != VT_LPSTR ) 689 return NULL; 690 return strdupAtoW( prop->u.pszVal ); 691 } 692 693 INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) 694 { 695 PROPVARIANT *prop; 696 697 if ( uiProperty >= MSI_MAX_PROPS ) 698 return -1; 699 prop = &si->property[uiProperty]; 700 if( prop->vt != VT_I4 ) 701 return -1; 702 return prop->u.lVal; 703 } 704 705 LPWSTR msi_get_suminfo_product( IStorage *stg ) 706 { 707 MSISUMMARYINFO *si; 708 LPWSTR prod; 709 UINT r; 710 711 r = msi_get_suminfo( stg, 0, &si ); 712 if (r != ERROR_SUCCESS) 713 { 714 ERR("no summary information!\n"); 715 return NULL; 716 } 717 prod = msi_suminfo_dup_string( si, PID_REVNUMBER ); 718 msiobj_release( &si->hdr ); 719 return prod; 720 } 721 722 UINT WINAPI MsiSummaryInfoGetPropertyA( 723 MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue, 724 FILETIME *pftValue, LPSTR szValueBuf, LPDWORD pcchValueBuf) 725 { 726 MSISUMMARYINFO *si; 727 awstring str; 728 UINT r; 729 730 TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType, 731 piValue, pftValue, szValueBuf, pcchValueBuf ); 732 733 if (uiProperty >= MSI_MAX_PROPS) 734 { 735 if (puiDataType) *puiDataType = VT_EMPTY; 736 return ERROR_UNKNOWN_PROPERTY; 737 } 738 739 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 740 return ERROR_INVALID_HANDLE; 741 742 str.unicode = FALSE; 743 str.str.a = szValueBuf; 744 745 r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf ); 746 msiobj_release( &si->hdr ); 747 return r; 748 } 749 750 UINT WINAPI MsiSummaryInfoGetPropertyW( 751 MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue, 752 FILETIME *pftValue, LPWSTR szValueBuf, LPDWORD pcchValueBuf) 753 { 754 MSISUMMARYINFO *si; 755 awstring str; 756 UINT r; 757 758 TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType, 759 piValue, pftValue, szValueBuf, pcchValueBuf ); 760 761 if (uiProperty >= MSI_MAX_PROPS) 762 { 763 if (puiDataType) *puiDataType = VT_EMPTY; 764 return ERROR_UNKNOWN_PROPERTY; 765 } 766 767 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 768 return ERROR_INVALID_HANDLE; 769 770 str.unicode = TRUE; 771 str.str.w = szValueBuf; 772 773 r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf ); 774 msiobj_release( &si->hdr ); 775 return r; 776 } 777 778 static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type, 779 INT iValue, FILETIME *pftValue, awcstring *str ) 780 { 781 PROPVARIANT *prop; 782 UINT len; 783 784 TRACE("%p, %u, %u, %d, %p, %p\n", si, uiProperty, type, iValue, pftValue, str ); 785 786 prop = &si->property[uiProperty]; 787 788 if( prop->vt == VT_EMPTY ) 789 { 790 if( !si->update_count ) 791 return ERROR_FUNCTION_FAILED; 792 793 si->update_count--; 794 } 795 else if( prop->vt != type ) 796 return ERROR_SUCCESS; 797 798 free_prop( prop ); 799 prop->vt = type; 800 switch( type ) 801 { 802 case VT_I4: 803 prop->u.lVal = iValue; 804 break; 805 case VT_I2: 806 prop->u.iVal = iValue; 807 break; 808 case VT_FILETIME: 809 prop->u.filetime = *pftValue; 810 break; 811 case VT_LPSTR: 812 if( str->unicode ) 813 { 814 len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1, 815 NULL, 0, NULL, NULL ); 816 prop->u.pszVal = msi_alloc( len ); 817 WideCharToMultiByte( CP_ACP, 0, str->str.w, -1, 818 prop->u.pszVal, len, NULL, NULL ); 819 } 820 else 821 { 822 len = lstrlenA( str->str.a ) + 1; 823 prop->u.pszVal = msi_alloc( len ); 824 lstrcpyA( prop->u.pszVal, str->str.a ); 825 } 826 break; 827 } 828 829 return ERROR_SUCCESS; 830 } 831 832 UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, 833 INT iValue, FILETIME *pftValue, LPCWSTR szValue ) 834 { 835 awcstring str; 836 MSISUMMARYINFO *si; 837 UINT type, ret; 838 839 TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue, 840 debugstr_w(szValue) ); 841 842 type = get_type( uiProperty ); 843 if( type == VT_EMPTY || type != uiDataType ) 844 return ERROR_DATATYPE_MISMATCH; 845 846 if( uiDataType == VT_LPSTR && !szValue ) 847 return ERROR_INVALID_PARAMETER; 848 849 if( uiDataType == VT_FILETIME && !pftValue ) 850 return ERROR_INVALID_PARAMETER; 851 852 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 853 return ERROR_INVALID_HANDLE; 854 855 str.unicode = TRUE; 856 str.str.w = szValue; 857 858 ret = set_prop( si, uiProperty, type, iValue, pftValue, &str ); 859 msiobj_release( &si->hdr ); 860 return ret; 861 } 862 863 UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, 864 INT iValue, FILETIME *pftValue, LPCSTR szValue ) 865 { 866 awcstring str; 867 MSISUMMARYINFO *si; 868 UINT type, ret; 869 870 TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue, 871 debugstr_a(szValue) ); 872 873 type = get_type( uiProperty ); 874 if( type == VT_EMPTY || type != uiDataType ) 875 return ERROR_DATATYPE_MISMATCH; 876 877 if( uiDataType == VT_LPSTR && !szValue ) 878 return ERROR_INVALID_PARAMETER; 879 880 if( uiDataType == VT_FILETIME && !pftValue ) 881 return ERROR_INVALID_PARAMETER; 882 883 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ))) 884 return ERROR_INVALID_HANDLE; 885 886 str.unicode = FALSE; 887 str.str.a = szValue; 888 889 ret = set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str ); 890 msiobj_release( &si->hdr ); 891 return ret; 892 } 893 894 static UINT suminfo_persist( MSISUMMARYINFO *si ) 895 { 896 UINT ret = ERROR_FUNCTION_FAILED; 897 IStream *stm = NULL; 898 DWORD grfMode; 899 HRESULT r; 900 901 grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE; 902 r = IStorage_CreateStream( si->storage, szSumInfo, grfMode, 0, 0, &stm ); 903 if( SUCCEEDED(r) ) 904 { 905 ret = save_summary_info( si, stm ); 906 IStream_Release( stm ); 907 } 908 return ret; 909 } 910 911 static void parse_filetime( LPCWSTR str, FILETIME *ft ) 912 { 913 SYSTEMTIME lt, utc; 914 const WCHAR *p = str; 915 WCHAR *end; 916 917 memset( <, 0, sizeof(lt) ); 918 919 /* YYYY/MM/DD hh:mm:ss */ 920 921 while (isspaceW( *p )) p++; 922 923 lt.wYear = strtolW( p, &end, 10 ); 924 if (*end != '/') return; 925 p = end + 1; 926 927 lt.wMonth = strtolW( p, &end, 10 ); 928 if (*end != '/') return; 929 p = end + 1; 930 931 lt.wDay = strtolW( p, &end, 10 ); 932 if (*end != ' ') return; 933 p = end + 1; 934 935 while (isspaceW( *p )) p++; 936 937 lt.wHour = strtolW( p, &end, 10 ); 938 if (*end != ':') return; 939 p = end + 1; 940 941 lt.wMinute = strtolW( p, &end, 10 ); 942 if (*end != ':') return; 943 p = end + 1; 944 945 lt.wSecond = strtolW( p, &end, 10 ); 946 947 TzSpecificLocalTimeToSystemTime( NULL, <, &utc ); 948 SystemTimeToFileTime( &utc, ft ); 949 } 950 951 static UINT parse_prop( LPCWSTR prop, LPCWSTR value, UINT *pid, INT *int_value, 952 FILETIME *ft_value, awcstring *str_value ) 953 { 954 *pid = atoiW( prop ); 955 switch (*pid) 956 { 957 #ifdef __REACTOS__ 958 case PID_CODEPAGE_MSI: 959 #else 960 case PID_CODEPAGE: 961 #endif 962 case PID_WORDCOUNT: 963 case PID_CHARCOUNT: 964 #ifdef __REACTOS__ 965 case PID_SECURITY_MSI: 966 #else 967 case PID_SECURITY: 968 #endif 969 case PID_PAGECOUNT: 970 *int_value = atoiW( value ); 971 break; 972 973 case PID_LASTPRINTED: 974 case PID_CREATE_DTM: 975 case PID_LASTSAVE_DTM: 976 parse_filetime( value, ft_value ); 977 break; 978 979 case PID_SUBJECT: 980 case PID_AUTHOR: 981 case PID_KEYWORDS: 982 case PID_COMMENTS: 983 case PID_TEMPLATE: 984 case PID_LASTAUTHOR: 985 case PID_REVNUMBER: 986 case PID_APPNAME: 987 case PID_TITLE: 988 str_value->str.w = value; 989 str_value->unicode = TRUE; 990 break; 991 992 default: 993 WARN("unhandled prop id %u\n", *pid); 994 return ERROR_FUNCTION_FAILED; 995 } 996 997 return ERROR_SUCCESS; 998 } 999 1000 UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ) 1001 { 1002 UINT r; 1003 int i, j; 1004 MSISUMMARYINFO *si; 1005 1006 r = msi_get_suminfo( db->storage, num_records * (num_columns / 2), &si ); 1007 if (r != ERROR_SUCCESS) 1008 { 1009 if (!(si = create_suminfo( db->storage, num_records * (num_columns / 2) ))) 1010 return ERROR_OUTOFMEMORY; 1011 r = ERROR_SUCCESS; 1012 } 1013 1014 for (i = 0; i < num_records; i++) 1015 { 1016 for (j = 0; j < num_columns; j += 2) 1017 { 1018 UINT pid; 1019 INT int_value = 0; 1020 FILETIME ft_value; 1021 awcstring str_value; 1022 1023 r = parse_prop( records[i][j], records[i][j + 1], &pid, &int_value, &ft_value, &str_value ); 1024 if (r != ERROR_SUCCESS) 1025 goto end; 1026 1027 r = set_prop( si, pid, get_type(pid), int_value, &ft_value, &str_value ); 1028 if (r != ERROR_SUCCESS) 1029 goto end; 1030 } 1031 } 1032 1033 end: 1034 if (r == ERROR_SUCCESS) 1035 r = suminfo_persist( si ); 1036 1037 msiobj_release( &si->hdr ); 1038 return r; 1039 } 1040 1041 static UINT save_prop( MSISUMMARYINFO *si, HANDLE handle, UINT row ) 1042 { 1043 static const char fmt_systemtime[] = "%d/%02d/%02d %02d:%02d:%02d"; 1044 char data[20]; /* largest string: YYYY/MM/DD hh:mm:ss */ 1045 static const char fmt_begin[] = "%u\t"; 1046 static const char data_end[] = "\r\n"; 1047 static const char fmt_int[] = "%u"; 1048 UINT r, data_type, len; 1049 SYSTEMTIME system_time; 1050 FILETIME file_time; 1051 INT int_value; 1052 awstring str; 1053 DWORD sz; 1054 1055 str.unicode = FALSE; 1056 str.str.a = NULL; 1057 len = 0; 1058 r = get_prop( si, row, &data_type, &int_value, &file_time, &str, &len ); 1059 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) 1060 return r; 1061 if (data_type == VT_EMPTY) 1062 return ERROR_SUCCESS; /* property not set */ 1063 snprintf( data, sizeof(data), fmt_begin, row ); 1064 sz = lstrlenA( data ); 1065 if (!WriteFile( handle, data, sz, &sz, NULL )) 1066 return ERROR_WRITE_FAULT; 1067 1068 switch (data_type) 1069 { 1070 case VT_I2: 1071 case VT_I4: 1072 snprintf( data, sizeof(data), fmt_int, int_value ); 1073 sz = lstrlenA( data ); 1074 if (!WriteFile( handle, data, sz, &sz, NULL )) 1075 return ERROR_WRITE_FAULT; 1076 break; 1077 case VT_LPSTR: 1078 len++; 1079 if (!(str.str.a = msi_alloc( len ))) 1080 return ERROR_OUTOFMEMORY; 1081 r = get_prop( si, row, NULL, NULL, NULL, &str, &len ); 1082 if (r != ERROR_SUCCESS) 1083 { 1084 msi_free( str.str.a ); 1085 return r; 1086 } 1087 sz = lstrlenA( str.str.a ); 1088 if (!WriteFile( handle, str.str.a, sz, &sz, NULL )) 1089 { 1090 msi_free( str.str.a ); 1091 return ERROR_WRITE_FAULT; 1092 } 1093 msi_free( str.str.a ); 1094 break; 1095 case VT_FILETIME: 1096 if (!FileTimeToSystemTime( &file_time, &system_time )) 1097 return ERROR_FUNCTION_FAILED; 1098 snprintf( data, sizeof(data), fmt_systemtime, system_time.wYear, system_time.wMonth, 1099 system_time.wDay, system_time.wHour, system_time.wMinute, 1100 system_time.wSecond ); 1101 sz = lstrlenA( data ); 1102 if (!WriteFile( handle, data, sz, &sz, NULL )) 1103 return ERROR_WRITE_FAULT; 1104 break; 1105 case VT_EMPTY: 1106 /* cannot reach here, property not set */ 1107 break; 1108 default: 1109 FIXME( "Unknown property variant type\n" ); 1110 return ERROR_FUNCTION_FAILED; 1111 } 1112 1113 sz = lstrlenA( data_end ); 1114 if (!WriteFile( handle, data_end, sz, &sz, NULL )) 1115 return ERROR_WRITE_FAULT; 1116 1117 return ERROR_SUCCESS; 1118 } 1119 1120 UINT msi_export_suminfo( MSIDATABASE *db, HANDLE handle ) 1121 { 1122 UINT i, r, num_rows; 1123 MSISUMMARYINFO *si; 1124 1125 r = msi_get_suminfo( db->storage, 0, &si ); 1126 if (r != ERROR_SUCCESS) 1127 r = msi_get_db_suminfo( db, 0, &si ); 1128 if (r != ERROR_SUCCESS) 1129 return r; 1130 1131 num_rows = get_property_count( si->property ); 1132 if (!num_rows) 1133 { 1134 msiobj_release( &si->hdr ); 1135 return ERROR_FUNCTION_FAILED; 1136 } 1137 1138 for (i = 0; i < num_rows; i++) 1139 { 1140 r = save_prop( si, handle, i ); 1141 if (r != ERROR_SUCCESS) 1142 { 1143 msiobj_release( &si->hdr ); 1144 return r; 1145 } 1146 } 1147 1148 msiobj_release( &si->hdr ); 1149 return ERROR_SUCCESS; 1150 } 1151 1152 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle ) 1153 { 1154 MSISUMMARYINFO *si; 1155 UINT ret; 1156 1157 TRACE("%d\n", handle ); 1158 1159 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ); 1160 if( !si ) 1161 return ERROR_INVALID_HANDLE; 1162 1163 ret = suminfo_persist( si ); 1164 1165 msiobj_release( &si->hdr ); 1166 return ret; 1167 } 1168 1169 UINT WINAPI MsiCreateTransformSummaryInfoA( MSIHANDLE db, MSIHANDLE db_ref, LPCSTR transform, int error, int validation ) 1170 { 1171 UINT r; 1172 WCHAR *transformW = NULL; 1173 1174 TRACE("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_a(transform), error, validation); 1175 1176 if (transform && !(transformW = strdupAtoW( transform ))) 1177 return ERROR_OUTOFMEMORY; 1178 1179 r = MsiCreateTransformSummaryInfoW( db, db_ref, transformW, error, validation ); 1180 msi_free( transformW ); 1181 return r; 1182 } 1183 1184 UINT WINAPI MsiCreateTransformSummaryInfoW( MSIHANDLE db, MSIHANDLE db_ref, LPCWSTR transform, int error, int validation ) 1185 { 1186 FIXME("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_w(transform), error, validation); 1187 return ERROR_FUNCTION_FAILED; 1188 } 1189 1190 UINT msi_load_suminfo_properties( MSIPACKAGE *package ) 1191 { 1192 static const WCHAR packagecodeW[] = {'P','a','c','k','a','g','e','C','o','d','e',0}; 1193 MSISUMMARYINFO *si; 1194 WCHAR *package_code; 1195 UINT r, len; 1196 awstring str; 1197 INT count; 1198 1199 r = msi_get_suminfo( package->db->storage, 0, &si ); 1200 if (r != ERROR_SUCCESS) 1201 { 1202 r = msi_get_db_suminfo( package->db, 0, &si ); 1203 if (r != ERROR_SUCCESS) 1204 { 1205 ERR("Unable to open summary information stream %u\n", r); 1206 return r; 1207 } 1208 } 1209 1210 str.unicode = TRUE; 1211 str.str.w = NULL; 1212 len = 0; 1213 r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len ); 1214 if (r != ERROR_MORE_DATA) 1215 { 1216 WARN("Unable to query revision number %u\n", r); 1217 msiobj_release( &si->hdr ); 1218 return ERROR_FUNCTION_FAILED; 1219 } 1220 1221 len++; 1222 if (!(package_code = msi_alloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; 1223 str.str.w = package_code; 1224 1225 r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len ); 1226 if (r != ERROR_SUCCESS) 1227 { 1228 msi_free( package_code ); 1229 msiobj_release( &si->hdr ); 1230 return r; 1231 } 1232 1233 r = msi_set_property( package->db, packagecodeW, package_code, len ); 1234 msi_free( package_code ); 1235 1236 count = 0; 1237 get_prop( si, PID_WORDCOUNT, NULL, &count, NULL, NULL, NULL ); 1238 package->WordCount = count; 1239 1240 msiobj_release( &si->hdr ); 1241 return r; 1242 } 1243