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 172 173 174
{
    UINT type;
    DWORD i;
    int size;
    PROPERTY_DATA *propdata;
175 176
    PROPVARIANT property, *ptr;
    PROPVARIANT changed;
177 178 179 180 181
    PROPERTYIDOFFSET *idofs;
    PROPERTYSECTIONHEADER *section_hdr;

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

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

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

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

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

211 212
        property.vt = propdata->type;
        if( propdata->type == VT_LPSTR )
213
        {
214
            LPSTR str = msi_alloc( propdata->u.str.len );
215 216
            memcpy( str, propdata->u.str.str, propdata->u.str.len );
            str[ propdata->u.str.len - 1 ] = 0;
217 218 219 220 221 222 223 224 225 226 227 228 229 230
            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;
231
        }
232 233 234
        else
            ptr = &property;

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

239 240 241 242 243 244 245 246 247 248
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;
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 279
    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 */
280
    sz = SECT_HDR_SIZE;
281 282 283 284 285 286
    r = IStream_Read( stm, &section_hdr, sz, &count );
    if( FAILED(r) || count != sz )
        return ret;

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

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

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

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

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

309 310 311 312 313 314 315 316 317 318 319 320
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;
}

321
static DWORD write_filetime( LPBYTE data, DWORD ofs, const FILETIME *ft )
322 323 324 325 326 327 328 329 330 331 332
{
    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 )
333
        memcpy( &data[ofs + 4], str, len );
334 335 336
    return (7 + len) & ~3;
}

337
static UINT write_property_to_data( const PROPVARIANT *prop, LPBYTE data )
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 363
    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;
}

364
static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm )
365 366 367 368 369 370 371 372
{
    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;
373
    HRESULT r;
374
    int i;
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389

    /* 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;
390
    format_hdr.fmtid = FMTID_SummaryInformation;
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
    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;
    }

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

    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 );
425
    msi_free( data );
426 427 428 429 430 431
    if( FAILED(r) || count != sz )
        return ret;

    return ERROR_SUCCESS;
}

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

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

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

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

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

460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
    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;
    }
482
    else
483 484 485
    {
        db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
        if( !db )
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
        {
            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;
        }
508 509
    }

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

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

    return ret;
}

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

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

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

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

545
    msi_free( szwDatabase );
546 547

    return ret;
548 549
}

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

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

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

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

564 565 566 567 568 569 570 571
    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;
572
    UINT ret = ERROR_SUCCESS;
573 574 575

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

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

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

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

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

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

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

638 639 640 641 642 643 644 645 646 647 648 649
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 );
}

650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
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;
}

666
UINT WINAPI MsiSummaryInfoGetPropertyA(
667 668
      MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
      FILETIME *pftValue, LPSTR szValueBuf, LPDWORD pcchValueBuf)
669 670 671 672 673 674 675 676 677 678 679
{
    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 );
680 681 682
}

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

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

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

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

static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
699
               INT iValue, FILETIME* pftValue, awcstring *str )
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
{
    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 )
720 721
        return ERROR_INVALID_HANDLE;

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

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

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

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

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

    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 );
783 784
}

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

    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 );
796 797
}

798
UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
799
{
800 801 802 803 804 805 806 807 808 809 810 811 812
    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;
813
    r = IStorage_CreateStream( si->storage, szSumInfo, grfMode, 0, 0, &stm );
814 815 816 817 818 819 820 821
    if( SUCCEEDED(r) )
    {
        ret = save_summary_info( si, stm );
        IStream_Release( stm );
    }
    msiobj_release( &si->hdr );

    return ret;
822
}