suminfo.c 21.5 KB
Newer Older
1 2 3
/*
 * Implementation of the Microsoft Installer (msi.dll)
 *
4
 * Copyright 2002, 2005 Mike McCormack for CodeWeavers
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22
#include <stdarg.h>

23 24 25
#define COBJMACROS
#define NONAMELESSUNION

26 27 28
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
29
#include "winnls.h"
30 31 32 33
#include "shlwapi.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
34
#include "msidefs.h"
35 36
#include "msipriv.h"
#include "objidl.h"
37
#include "propvarutil.h"
38
#include "msiserver.h"
39 40 41

WINE_DEFAULT_DEBUG_CHANNEL(msi);

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
#include "pshpack1.h"

typedef struct { 
    WORD wByteOrder;
    WORD wFormat;
    DWORD dwOSVer;
    CLSID clsID;
    DWORD reserved;
} PROPERTYSETHEADER;

typedef struct { 
    FMTID fmtid;
    DWORD dwOffset;
} FORMATIDOFFSET;

typedef struct { 
    DWORD cbSection;
    DWORD cProperties;
} PROPERTYSECTIONHEADER; 
 
typedef struct { 
    DWORD propid;
    DWORD dwOffset;
} PROPERTYIDOFFSET; 

typedef struct {
    DWORD type;
    union {
        INT i4;
        SHORT i2;
        FILETIME ft;
        struct {
            DWORD len;
            BYTE str[1];
        } str;
    } u;
} PROPERTY_DATA;
 
#include "poppack.h"

82 83 84 85
static HRESULT (WINAPI *pPropVariantChangeType)
    (PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc,
     PROPVAR_CHANGE_FLAGS flags, VARTYPE vt);

86 87
#define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER))

88
static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y',
89 90
                       'I','n','f','o','r','m','a','t','i','o','n',0 };

91 92 93
static void free_prop( PROPVARIANT *prop )
{
    if (prop->vt == VT_LPSTR )
94
        msi_free( prop->u.pszVal );
95 96 97
    prop->vt = VT_EMPTY;
}

98
static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
99
{
100
    MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg;
101 102 103 104
    DWORD i;

    for( i = 0; i < MSI_MAX_PROPS; i++ )
        free_prop( &si->property[i] );
105
    IStorage_Release( si->storage );
106 107
}

108
static UINT get_type( UINT uiProperty )
109
{
110 111 112 113
    switch( uiProperty )
    {
    case PID_CODEPAGE:
         return VT_I2;
114

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    case PID_SUBJECT:
    case PID_AUTHOR:
    case PID_KEYWORDS:
    case PID_COMMENTS:
    case PID_TEMPLATE:
    case PID_LASTAUTHOR:
    case PID_REVNUMBER:
    case PID_APPNAME:
    case PID_TITLE:
         return VT_LPSTR;

    case PID_LASTPRINTED:
    case PID_CREATE_DTM:
    case PID_LASTSAVE_DTM:
         return VT_FILETIME;

    case PID_WORDCOUNT:
    case PID_CHARCOUNT:
    case PID_SECURITY:
    case PID_PAGECOUNT:
         return VT_I4;
    }
    return VT_EMPTY;
}
139

140
static UINT get_property_count( const PROPVARIANT *property )
141 142 143 144 145
{
    UINT i, n = 0;

    if( !property )
        return n;
146
    for( i = 0; i < MSI_MAX_PROPS; i++ )
147 148 149 150
        if( property[i].vt != VT_EMPTY )
            n++;
    return n;
}
151

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
static UINT propvar_changetype(PROPVARIANT *changed, PROPVARIANT *property, VARTYPE vt)
{
    HRESULT hr;
    HMODULE propsys = LoadLibraryA("propsys.dll");
    pPropVariantChangeType = (void *)GetProcAddress(propsys, "PropVariantChangeType");

    if (!pPropVariantChangeType)
    {
        ERR("PropVariantChangeType function missing!\n");
        return ERROR_FUNCTION_FAILED;
    }

    hr = pPropVariantChangeType(changed, property, 0, vt);
    return (hr == S_OK) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
}

168
/* FIXME: doesn't deal with endian conversion */
169
static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz )
170 171
{
    UINT type;
172
    DWORD i, size;
173
    PROPERTY_DATA *propdata;
174 175
    PROPVARIANT property, *ptr;
    PROPVARIANT changed;
176 177 178 179 180
    PROPERTYIDOFFSET *idofs;
    PROPERTYSECTIONHEADER *section_hdr;

    section_hdr = (PROPERTYSECTIONHEADER*) &data[0];
    idofs = (PROPERTYIDOFFSET*) &data[SECT_HDR_SIZE];
181 182

    /* now set all the properties */
183
    for( i = 0; i < section_hdr->cProperties; i++ )
184
    {
185 186 187 188 189 190
        if( idofs[i].propid >= MSI_MAX_PROPS )
        {
            ERR("Unknown property ID %d\n", idofs[i].propid );
            break;
        }

191 192 193
        type = get_type( idofs[i].propid );
        if( type == VT_EMPTY )
        {
194
            ERR("propid %d has unknown type\n", idofs[i].propid);
195 196 197
            break;
        }

198
        propdata = (PROPERTY_DATA*) &data[ idofs[i].dwOffset ];
199 200 201 202

        /* check we don't run off the end of the data */
        size = sz - idofs[i].dwOffset - sizeof(DWORD);
        if( sizeof(DWORD) > size ||
203 204
            ( propdata->type == VT_FILETIME && sizeof(FILETIME) > size ) ||
            ( propdata->type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) )
205 206 207 208 209
        {
            ERR("not enough data\n");
            break;
        }

210 211
        property.vt = propdata->type;
        if( propdata->type == VT_LPSTR )
212
        {
213
            LPSTR str = msi_alloc( propdata->u.str.len );
214 215
            memcpy( str, propdata->u.str.str, propdata->u.str.len );
            str[ propdata->u.str.len - 1 ] = 0;
216 217 218 219 220 221 222 223 224 225 226 227 228 229
            property.u.pszVal = str;
        }
        else if( propdata->type == VT_FILETIME )
            property.u.filetime = propdata->u.ft;
        else if( propdata->type == VT_I2 )
            property.u.iVal = propdata->u.i2;
        else if( propdata->type == VT_I4 )
            property.u.lVal = propdata->u.i4;

        /* check the type is the same as we expect */
        if( type != propdata->type )
        {
            propvar_changetype(&changed, &property, type);
            ptr = &changed;
230
        }
231 232 233
        else
            ptr = &property;

234
        prop[ idofs[i].propid ] = *ptr;
235
    }
236
}
237

238 239 240 241 242 243 244 245 246 247
static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
{
    UINT ret = ERROR_FUNCTION_FAILED;
    PROPERTYSETHEADER set_hdr;
    FORMATIDOFFSET format_hdr;
    PROPERTYSECTIONHEADER section_hdr;
    LPBYTE data = NULL;
    LARGE_INTEGER ofs;
    ULONG count, sz;
    HRESULT r;
248

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
    TRACE("%p %p\n", si, stm);

    /* read the header */
    sz = sizeof set_hdr;
    r = IStream_Read( stm, &set_hdr, sz, &count );
    if( FAILED(r) || count != sz )
        return ret;

    if( set_hdr.wByteOrder != 0xfffe )
    {
        ERR("property set not big-endian %04X\n", set_hdr.wByteOrder);
        return ret;
    }

    sz = sizeof format_hdr;
    r = IStream_Read( stm, &format_hdr, sz, &count );
    if( FAILED(r) || count != sz )
        return ret;

    /* check the format id is correct */
    if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) )
        return ret;

    /* seek to the location of the section */
    ofs.QuadPart = format_hdr.dwOffset;
    r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL );
    if( FAILED(r) )
        return ret;

    /* read the section itself */
279
    sz = SECT_HDR_SIZE;
280 281 282 283 284 285
    r = IStream_Read( stm, &section_hdr, sz, &count );
    if( FAILED(r) || count != sz )
        return ret;

    if( section_hdr.cProperties > MSI_MAX_PROPS )
    {
286
        ERR("too many properties %d\n", section_hdr.cProperties);
287 288 289
        return ret;
    }

290
    data = msi_alloc( section_hdr.cbSection);
291
    if( !data )
292 293
        return ret;

294 295
    memcpy( data, &section_hdr, SECT_HDR_SIZE );

296
    /* read all the data in one go */
297 298
    sz = section_hdr.cbSection - SECT_HDR_SIZE;
    r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count );
299
    if( SUCCEEDED(r) && count == sz )
300 301
        read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE );
    else
302
        ERR("failed to read properties %d %d\n", count, sz);
303

304
    msi_free( data );
305 306 307
    return ret;
}

308 309 310 311 312 313 314 315 316 317 318 319
static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val )
{
    if( data )
    {
        data[ofs++] = val&0xff;
        data[ofs++] = (val>>8)&0xff;
        data[ofs++] = (val>>16)&0xff;
        data[ofs++] = (val>>24)&0xff;
    }
    return 4;
}

320
static DWORD write_filetime( LPBYTE data, DWORD ofs, const FILETIME *ft )
321 322 323 324 325 326 327 328 329 330 331
{
    write_dword( data, ofs, ft->dwLowDateTime );
    write_dword( data, ofs + 4, ft->dwHighDateTime );
    return 8;
}

static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str )
{
    DWORD len = lstrlenA( str ) + 1;
    write_dword( data, ofs, len );
    if( data )
332
        memcpy( &data[ofs + 4], str, len );
333 334 335
    return (7 + len) & ~3;
}

336
static UINT write_property_to_data( const PROPVARIANT *prop, LPBYTE data )
337
{
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
    DWORD sz = 0;

    if( prop->vt == VT_EMPTY )
        return sz;

    /* add the type */
    sz += write_dword( data, sz, prop->vt );
    switch( prop->vt )
    {
    case VT_I2:
        sz += write_dword( data, sz, prop->u.iVal );
        break;
    case VT_I4:
        sz += write_dword( data, sz, prop->u.lVal );
        break;
    case VT_FILETIME:
        sz += write_filetime( data, sz, &prop->u.filetime );
        break;
    case VT_LPSTR:
        sz += write_string( data, sz, prop->u.pszVal );
        break;
    }
    return sz;
}

363
static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm )
364 365 366 367 368 369 370 371
{
    UINT ret = ERROR_FUNCTION_FAILED;
    PROPERTYSETHEADER set_hdr;
    FORMATIDOFFSET format_hdr;
    PROPERTYSECTIONHEADER section_hdr;
    PROPERTYIDOFFSET idofs[MSI_MAX_PROPS];
    LPBYTE data = NULL;
    ULONG count, sz;
372
    HRESULT r;
373
    int i;
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388

    /* write the header */
    sz = sizeof set_hdr;
    memset( &set_hdr, 0, sz );
    set_hdr.wByteOrder = 0xfffe;
    set_hdr.wFormat = 0;
    set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */
    /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */
    set_hdr.reserved = 1;
    r = IStream_Write( stm, &set_hdr, sz, &count );
    if( FAILED(r) || count != sz )
        return ret;

    /* write the format header */
    sz = sizeof format_hdr;
389
    format_hdr.fmtid = FMTID_SummaryInformation;
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
    format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr;
    r = IStream_Write( stm, &format_hdr, sz, &count );
    if( FAILED(r) || count != sz )
        return ret;

    /* add up how much space the data will take and calculate the offsets */
    section_hdr.cbSection = sizeof section_hdr;
    section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]);
    section_hdr.cProperties = 0;
    for( i = 0; i < MSI_MAX_PROPS; i++ )
    {
        sz = write_property_to_data( &si->property[i], NULL );
        if( !sz )
            continue;
        idofs[ section_hdr.cProperties ].propid = i;
        idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection;
        section_hdr.cProperties++;
        section_hdr.cbSection += sz;
    }

410
    data = msi_alloc_zero( section_hdr.cbSection );
411 412 413 414 415 416 417 418 419 420 421 422 423

    sz = 0;
    memcpy( &data[sz], &section_hdr, sizeof section_hdr );
    sz += sizeof section_hdr;

    memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] );
    sz += section_hdr.cProperties * sizeof idofs[0];

    /* write out the data */
    for( i = 0; i < MSI_MAX_PROPS; i++ )
        sz += write_property_to_data( &si->property[i], &data[sz] );

    r = IStream_Write( stm, data, sz, &count );
424
    msi_free( data );
425 426 427 428 429 430
    if( FAILED(r) || count != sz )
        return ret;

    return ERROR_SUCCESS;
}

431
MSISUMMARYINFO *MSI_GetSummaryInformationW( IStorage *stg, UINT uiUpdateCount )
432 433 434
{
    IStream *stm = NULL;
    MSISUMMARYINFO *si;
435
    DWORD grfMode;
436
    HRESULT r;
437

438
    TRACE("%p %d\n", stg, uiUpdateCount );
439

440 441 442
    si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, 
                  sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
    if( !si )
443
        return si;
444

445
    memset( si->property, 0, sizeof si->property );
446
    si->update_count = uiUpdateCount;
447 448
    IStorage_AddRef( stg );
    si->storage = stg;
449

450 451
    /* read the stream... if we fail, we'll start with an empty property set */
    grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
452
    r = IStorage_OpenStream( si->storage, szSumInfo, 0, grfMode, 0, &stm );
453
    if( SUCCEEDED(r) )
454
    {
455 456
        load_summary_info( si, stm );
        IStream_Release( stm );
457 458
    }

459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
    return si;
}

UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, 
              LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
{
    MSISUMMARYINFO *si;
    MSIDATABASE *db;
    UINT ret = ERROR_FUNCTION_FAILED;

    TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
           uiUpdateCount, pHandle);

    if( !pHandle )
        return ERROR_INVALID_PARAMETER;

    if( szDatabase )
    {
        ret = MSI_OpenDatabaseW( szDatabase, NULL, &db );
        if( ret != ERROR_SUCCESS )
            return ret;
    }
481
    else
482 483 484
    {
        db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
        if( !db )
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
        {
            HRESULT hr;
            IWineMsiRemoteDatabase *remote_database;

            remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hDatabase );
            if ( !remote_database )
                return ERROR_INVALID_HANDLE;

            hr = IWineMsiRemoteDatabase_GetSummaryInformation( remote_database,
                                                               uiUpdateCount, pHandle );
            IWineMsiRemoteDatabase_Release( remote_database );

            if (FAILED(hr))
            {
                if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
                    return HRESULT_CODE(hr);

                return ERROR_FUNCTION_FAILED;
            }

            return ERROR_SUCCESS;
        }
507 508
    }

509
    si = MSI_GetSummaryInformationW( db->storage, uiUpdateCount );
510 511 512 513 514
    if (si)
    {
        *pHandle = alloc_msihandle( &si->hdr );
        if( *pHandle )
            ret = ERROR_SUCCESS;
515 516
        else
            ret = ERROR_NOT_ENOUGH_MEMORY;
517 518
        msiobj_release( &si->hdr );
    }
519

520
    if( db )
521
        msiobj_release( &db->hdr );
522 523 524 525

    return ret;
}

526 527
UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase, 
              LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
528
{
529 530
    LPWSTR szwDatabase = NULL;
    UINT ret;
531

532 533
    TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase), 
          uiUpdateCount, pHandle);
534

535 536 537 538 539 540 541 542
    if( szDatabase )
    {
        szwDatabase = strdupAtoW( szDatabase );
        if( !szwDatabase )
            return ERROR_FUNCTION_FAILED;
    }

    ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle);
543

544
    msi_free( szwDatabase );
545 546

    return ret;
547 548
}

549
UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, PUINT pCount)
550
{
551
    MSISUMMARYINFO *si;
552

553
    TRACE("%ld %p\n", hSummaryInfo, pCount);
554

555 556
    si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
    if( !si )
557 558
        return ERROR_INVALID_HANDLE;

559 560 561
    if( pCount )
        *pCount = get_property_count( si->property );
    msiobj_release( &si->hdr );
562

563 564 565 566 567 568 569 570
    return ERROR_SUCCESS;
}

static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
          INT *piValue, FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
{
    MSISUMMARYINFO *si;
    PROPVARIANT *prop;
571
    UINT ret = ERROR_SUCCESS;
572 573 574

    TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
          piValue, pftValue, str, pcchValueBuf);
575

576 577
    if ( uiProperty >= MSI_MAX_PROPS )
    {
578 579
        if (puiDataType) *puiDataType = VT_EMPTY;
        return ERROR_UNKNOWN_PROPERTY;
580 581
    }

582 583 584 585
    si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
    if( !si )
        return ERROR_INVALID_HANDLE;

586 587
    prop = &si->property[uiProperty];

588 589 590 591
    if( puiDataType )
        *puiDataType = prop->vt;

    switch( prop->vt )
592
    {
593 594 595 596
    case VT_I2:
        if( piValue )
            *piValue = prop->u.iVal;
        break;
597 598
    case VT_I4:
        if( piValue )
599
            *piValue = prop->u.lVal;
600 601
        break;
    case VT_LPSTR:
602
        if( pcchValueBuf )
603
        {
604 605 606 607 608 609
            DWORD len = 0;

            if( str->unicode )
            {
                len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1,
                                           str->str.w, *pcchValueBuf );
610
                len--;
611 612 613 614 615 616 617
            }
            else
            {
                len = lstrlenA( prop->u.pszVal );
                if( str->str.a )
                    lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf );
            }
618 619
            if (len >= *pcchValueBuf)
                ret = ERROR_MORE_DATA;
620
            *pcchValueBuf = len;
621 622 623 624
        }
        break;
    case VT_FILETIME:
        if( pftValue )
625
            *pftValue = prop->u.filetime;
626 627 628 629 630 631 632
        break;
    case VT_EMPTY:
        break;
    default:
        FIXME("Unknown property variant type\n");
        break;
    }
633
    msiobj_release( &si->hdr );
634
    return ret;
635 636
}

637 638 639 640 641 642 643 644 645 646 647 648
LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty )
{
    PROPVARIANT *prop;

    if ( uiProperty >= MSI_MAX_PROPS )
        return NULL;
    prop = &si->property[uiProperty];
    if( prop->vt != VT_LPSTR )
        return NULL;
    return strdupAtoW( prop->u.pszVal );
}

649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
LPWSTR msi_get_suminfo_product( IStorage *stg )
{
    MSISUMMARYINFO *si;
    LPWSTR prod;

    si = MSI_GetSummaryInformationW( stg, 0 );
    if (!si)
    {
        ERR("no summary information!\n");
        return NULL;
    }
    prod = msi_suminfo_dup_string( si, PID_REVNUMBER );
    msiobj_release( &si->hdr );
    return prod;
}

665
UINT WINAPI MsiSummaryInfoGetPropertyA(
666 667
      MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
      FILETIME *pftValue, LPSTR szValueBuf, LPDWORD pcchValueBuf)
668 669 670 671 672 673 674 675 676 677 678
{
    awstring str;

    TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
          piValue, pftValue, szValueBuf, pcchValueBuf );

    str.unicode = FALSE;
    str.str.a = szValueBuf;

    return get_prop( handle, uiProperty, puiDataType, piValue,
                     pftValue, &str, pcchValueBuf );
679 680 681
}

UINT WINAPI MsiSummaryInfoGetPropertyW(
682 683
      MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
      FILETIME *pftValue, LPWSTR szValueBuf, LPDWORD pcchValueBuf)
684
{
685 686 687 688
    awstring str;

    TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
          piValue, pftValue, szValueBuf, pcchValueBuf );
689

690 691
    str.unicode = TRUE;
    str.str.w = szValueBuf;
692

693 694 695 696 697
    return get_prop( handle, uiProperty, puiDataType, piValue,
                     pftValue, &str, pcchValueBuf );
}

static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
698
               INT iValue, FILETIME* pftValue, awcstring *str )
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
{
    MSISUMMARYINFO *si;
    PROPVARIANT *prop;
    UINT type, len, ret = ERROR_SUCCESS;

    TRACE("%ld %u %u %i %p %p\n", handle, uiProperty, uiDataType,
          iValue, pftValue, str );

    type = get_type( uiProperty );
    if( type == VT_EMPTY || type != uiDataType )
        return ERROR_DATATYPE_MISMATCH;

    if( uiDataType == VT_LPSTR && !str->str.w )
        return ERROR_INVALID_PARAMETER;

    if( uiDataType == VT_FILETIME && !pftValue )
        return ERROR_INVALID_PARAMETER;

    si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
    if( !si )
719 720
        return ERROR_INVALID_HANDLE;

721
    prop = &si->property[uiProperty];
722

723
    if( prop->vt == VT_EMPTY )
724
    {
725 726 727 728 729 730
        if( !si->update_count )
        {
            ret = ERROR_FUNCTION_FAILED;
            goto end;
        }
        si->update_count--;
731
    }
732 733
    else if( prop->vt != type )
        goto end;
734

735 736
    free_prop( prop );
    prop->vt = type;
737
    switch( type )
738 739
    {
    case VT_I4:
740
        prop->u.lVal = iValue;
741
        break;
742 743
    case VT_I2:
        prop->u.iVal = iValue;
744 745
        break;
    case VT_FILETIME:
746
        prop->u.filetime = *pftValue;
747
        break;
748 749 750 751 752
    case VT_LPSTR:
        if( str->unicode )
        {
            len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
                                       NULL, 0, NULL, NULL );
753
            prop->u.pszVal = msi_alloc( len );
754 755 756 757 758 759
            WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
                                 prop->u.pszVal, len, NULL, NULL );
        }
        else
        {
            len = lstrlenA( str->str.a ) + 1;
760
            prop->u.pszVal = msi_alloc( len );
761 762
            lstrcpyA( prop->u.pszVal, str->str.a );
        }
763 764 765
        break;
    }

766
end:
767 768
    msiobj_release( &si->hdr );
    return ret;
769
}
770

771
UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
772
               UINT uiDataType, INT iValue, FILETIME* pftValue, LPCWSTR szValue )
773
{
774
    awcstring str;
775 776 777 778 779 780 781

    TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
          iValue, pftValue, debugstr_w(szValue) );

    str.unicode = TRUE;
    str.str.w = szValue;
    return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str );
782 783
}

784
UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
785
               UINT uiDataType, INT iValue, FILETIME* pftValue, LPCSTR szValue )
786
{
787
    awcstring str;
788 789 790 791 792 793 794

    TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
          iValue, pftValue, debugstr_a(szValue) );

    str.unicode = FALSE;
    str.str.a = szValue;
    return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str );
795 796
}

797
UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
798
{
799 800 801 802 803 804 805 806 807 808 809 810 811
    IStream *stm = NULL;
    MSISUMMARYINFO *si;
    DWORD grfMode;
    HRESULT r;
    UINT ret = ERROR_FUNCTION_FAILED;

    TRACE("%ld\n", handle );

    si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
    if( !si )
        return ERROR_INVALID_HANDLE;

    grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
812
    r = IStorage_CreateStream( si->storage, szSumInfo, grfMode, 0, 0, &stm );
813 814 815 816 817 818 819 820
    if( SUCCEEDED(r) )
    {
        ret = save_summary_info( si, stm );
        IStream_Release( stm );
    }
    msiobj_release( &si->hdr );

    return ret;
821
}