suminfo.c 19.3 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 18 19 20
 *
 * 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

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 37 38 39
#include "msipriv.h"
#include "objidl.h"

WINE_DEFAULT_DEBUG_CHANNEL(msi);

40 41 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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
#define MSI_MAX_PROPS 19

#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"

typedef struct {
    BOOL unicode;
    union {
       LPSTR a;
       LPWSTR w;
    } str;
} awstring;

typedef struct tagMSISUMMARYINFO
{
    MSIOBJECTHDR hdr;
    MSIDATABASE *db;
    DWORD update_count;
    PROPVARIANT property[MSI_MAX_PROPS];
} MSISUMMARYINFO;

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

101 102 103 104 105 106 107
static void free_prop( PROPVARIANT *prop )
{
    if (prop->vt == VT_LPSTR )
        HeapFree( GetProcessHeap(), 0, prop->u.pszVal );
    prop->vt = VT_EMPTY;
}

108
static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
109
{
110
    MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg;
111 112 113 114
    DWORD i;

    for( i = 0; i < MSI_MAX_PROPS; i++ )
        free_prop( &si->property[i] );
115
    msiobj_release( &si->db->hdr );
116 117
}

118
static UINT get_type( UINT uiProperty )
119
{
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    switch( uiProperty )
    {
    case PID_CODEPAGE:
         return VT_I2;
    
    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;
}
149

150 151 152 153 154 155
static UINT get_property_count( PROPVARIANT *property )
{
    UINT i, n = 0;

    if( !property )
        return n;
156
    for( i = 0; i < MSI_MAX_PROPS; i++ )
157 158 159 160
        if( property[i].vt != VT_EMPTY )
            n++;
    return n;
}
161

162 163 164 165 166 167 168 169 170 171 172 173
/* FIXME: doesn't deal with endian conversion */
static void read_properties_from_data( PROPVARIANT *prop,
              PROPERTYIDOFFSET *idofs, DWORD count, LPBYTE data, DWORD sz )
{
    UINT type;
    DWORD i;
    int size;
    PROPERTY_DATA *propdata;
    PROPVARIANT *property;

    /* now set all the properties */
    for( i = 0; i < count; i++ )
174
    {
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
        type = get_type( idofs[i].propid );
        if( type == VT_EMPTY )
        {
            ERR("propid %ld has unknown type\n", idofs[i].propid);
            break;
        }

        propdata = (PROPERTY_DATA*) &data[idofs[i].dwOffset];

        /* check the type is the same as we expect */
        if( type != propdata->type )
        {
            ERR("wrong type\n");
            break;
        }

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

        property = &prop[ idofs[i].propid ];
        property->vt = type;

        if( type == VT_LPSTR )
        {
            LPSTR str = HeapAlloc( GetProcessHeap(), 0, propdata->u.str.len );
            memcpy( str, propdata->u.str.str, propdata->u.str.len );
            str[ propdata->u.str.len - 1 ] = 0;
            property->u.pszVal = str;
        }
        else if( type == VT_FILETIME )
            property->u.filetime = propdata->u.ft;
        else if( type == VT_I2 )
            property->u.iVal = propdata->u.i2;
        else if( type == VT_I4 )
            property->u.lVal = propdata->u.i4;
217
    }
218
}
219

220 221 222 223 224 225 226 227 228 229 230
static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
{
    UINT ret = ERROR_FUNCTION_FAILED;
    PROPERTYSETHEADER set_hdr;
    FORMATIDOFFSET format_hdr;
    PROPERTYSECTIONHEADER section_hdr;
    PROPERTYIDOFFSET idofs[MSI_MAX_PROPS];
    LPBYTE data = NULL;
    LARGE_INTEGER ofs;
    ULONG count, sz;
    HRESULT r;
231

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 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 279 280 281 282 283 284 285 286 287 288 289
    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 */
    sz = sizeof section_hdr;
    r = IStream_Read( stm, &section_hdr, sz, &count );
    if( FAILED(r) || count != sz )
        return ret;

    if( section_hdr.cProperties > MSI_MAX_PROPS )
    {
        ERR("too many properties %ld\n", section_hdr.cProperties);
        return ret;
    }

    /* read the offsets */
    sz = sizeof idofs[0] * section_hdr.cProperties;
    r = IStream_Read( stm, idofs, sz, &count );
    if( FAILED(r) || count != sz )
        return ret;

    /* read all the data in one go */
    sz = section_hdr.cbSection;
    data = HeapAlloc( GetProcessHeap(), 0, sz );
    if( !data )
        return ret;
    r = IStream_Read( stm, data, sz, &count );
    if( SUCCEEDED(r) && count == sz )
    {
        read_properties_from_data( si->property, idofs,
                                   section_hdr.cProperties, data, sz );
    }
290

291
    HeapFree( GetProcessHeap(), 0, data );
292 293 294
    return ret;
}

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
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;
}

static DWORD write_filetime( LPBYTE data, DWORD ofs, LPFILETIME ft )
{
    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 )
        lstrcpyA( &data[ofs + 4], str );
    return (7 + len) & ~3;
}

static UINT write_property_to_data( PROPVARIANT *prop, LPBYTE data )
324
{
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
    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;
}

static UINT save_summary_info( MSISUMMARYINFO * si, IStream *stm )
{
    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;
359
    HRESULT r;
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
    int i, n;

    /* 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;
    memcpy( &format_hdr.fmtid, &FMTID_SummaryInformation, sizeof (FMTID) );
    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;
    n = 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;
    }

    data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, section_hdr.cbSection );

    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 );
    HeapFree( GetProcessHeap(), 0, data );
    if( FAILED(r) || count != sz )
        return ret;

    return ERROR_SUCCESS;
}

UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, 
              LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
{
    UINT ret = ERROR_SUCCESS;
    IStream *stm = NULL;
    MSISUMMARYINFO *si;
425
    MSIHANDLE handle;
426 427
    MSIDATABASE *db;
    DWORD grfMode;
428
    HRESULT r;
429 430

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

433
    if( !pHandle )
434 435 436 437 438 439
        return ERROR_INVALID_PARAMETER;

    if( szDatabase )
    {
        UINT res;

440
        res = MSI_OpenDatabaseW(szDatabase, NULL, &db);
441 442 443
        if( res != ERROR_SUCCESS )
            return res;
    }
444 445 446 447 448 449
    else
    {
        db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
        if( !db )
            return ERROR_INVALID_PARAMETER;
    }
450

451 452 453
    si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, 
                  sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
    if( !si )
454
    {
455 456
        ret = ERROR_FUNCTION_FAILED;
        goto end;
457 458
    }

459 460 461 462
    msiobj_addref( &db->hdr );
    si->db = db;
    memset( &si->property, 0, sizeof si->property );
    si->update_count = uiUpdateCount;
463

464 465 466 467
    /* read the stream... if we fail, we'll start with an empty property set */
    grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
    r = IStorage_OpenStream( si->db->storage, szSumInfo, 0, grfMode, 0, &stm );
    if( SUCCEEDED(r) )
468
    {
469 470
        load_summary_info( si, stm );
        IStream_Release( stm );
471 472
    }

473
    handle = alloc_msihandle( &si->hdr );
474
    if( handle )
475
        *pHandle = handle;
476 477
    else
        ret = ERROR_FUNCTION_FAILED;
478
    msiobj_release( &si->hdr );
479 480

end:
481
    if( db )
482
        msiobj_release(&db->hdr);
483 484 485 486

    return ret;
}

487 488
UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase, 
              LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
489
{
490 491
    LPWSTR szwDatabase = NULL;
    UINT ret;
492

493 494
    TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase), 
          uiUpdateCount, pHandle);
495

496 497 498 499 500 501 502 503
    if( szDatabase )
    {
        szwDatabase = strdupAtoW( szDatabase );
        if( !szwDatabase )
            return ERROR_FUNCTION_FAILED;
    }

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

505 506 507
    HeapFree( GetProcessHeap(), 0, szwDatabase );

    return ret;
508 509
}

510
UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount)
511
{
512
    MSISUMMARYINFO *si;
513

514
    TRACE("%ld %p\n",hSummaryInfo, pCount);
515

516 517
    si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
    if( !si )
518 519
        return ERROR_INVALID_HANDLE;

520 521 522
    if( pCount )
        *pCount = get_property_count( si->property );
    msiobj_release( &si->hdr );
523

524 525 526 527 528 529 530 531 532 533 534 535
    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;
    UINT type;

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

537
    type = get_type( uiProperty );
538
    if( puiDataType )
539
        *puiDataType = type;
540

541 542 543 544 545 546 547 548 549
    si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
    if( !si )
        return ERROR_INVALID_HANDLE;

    prop = &si->property[uiProperty];
    if( prop->vt != type )
        goto end;

    switch( type )
550
    {
551 552 553 554
    case VT_I2:
        if( piValue )
            *piValue = prop->u.iVal;
        break;
555 556
    case VT_I4:
        if( piValue )
557
            *piValue = prop->u.lVal;
558 559
        break;
    case VT_LPSTR:
560
        if( pcchValueBuf )
561
        {
562 563 564 565 566 567 568 569 570 571 572 573 574 575
            DWORD len = 0;

            if( str->unicode )
            {
                len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1,
                                           str->str.w, *pcchValueBuf );
            }
            else
            {
                len = lstrlenA( prop->u.pszVal );
                if( str->str.a )
                    lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf );
            }
            *pcchValueBuf = len;
576 577 578 579
        }
        break;
    case VT_FILETIME:
        if( pftValue )
580
            memcpy(pftValue, &prop->u.filetime, sizeof (FILETIME) );
581 582 583 584 585 586 587
        break;
    case VT_EMPTY:
        break;
    default:
        FIXME("Unknown property variant type\n");
        break;
    }
588
end:
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
    msiobj_release( &si->hdr );
    return ERROR_SUCCESS;
}

UINT WINAPI MsiSummaryInfoGetPropertyA(
      MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
      FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf)
{
    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 );
607 608 609
}

UINT WINAPI MsiSummaryInfoGetPropertyW(
610
      MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
611 612
      FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf)
{
613 614 615 616
    awstring str;

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

618 619
    str.unicode = TRUE;
    str.str.w = szValueBuf;
620

621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
    return get_prop( handle, uiProperty, puiDataType, piValue,
                     pftValue, &str, pcchValueBuf );
}

static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
               INT iValue, FILETIME* pftValue, awstring *str )
{
    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 )
647 648
        return ERROR_INVALID_HANDLE;

649
    prop = &si->property[uiProperty];
650

651
    if( prop->vt == VT_EMPTY )
652
    {
653 654 655 656 657 658
        if( !si->update_count )
        {
            ret = ERROR_FUNCTION_FAILED;
            goto end;
        }
        si->update_count--;
659
    }
660 661
    else if( prop->vt != type )
        goto end;
662

663 664
    free_prop( prop );
    prop->vt = type;
665
    switch( type )
666 667
    {
    case VT_I4:
668
        prop->u.lVal = iValue;
669
        break;
670 671
    case VT_I2:
        prop->u.iVal = iValue;
672 673
        break;
    case VT_FILETIME:
674
        memcpy( &prop->u.filetime, pftValue, sizeof prop->u.filetime );
675
        break;
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
    case VT_LPSTR:
        if( str->unicode )
        {
            len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
                                       NULL, 0, NULL, NULL );
            prop->u.pszVal = HeapAlloc( GetProcessHeap(), 0, len );
            WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
                                 prop->u.pszVal, len, NULL, NULL );
        }
        else
        {
            len = lstrlenA( str->str.a ) + 1;
            prop->u.pszVal = HeapAlloc( GetProcessHeap(), 0, len );
            lstrcpyA( prop->u.pszVal, str->str.a );
        }
691 692 693
        break;
    }

694
end:
695 696
    msiobj_release( &si->hdr );
    return ret;
697
}
698

699 700
UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
               UINT uiDataType, INT iValue, FILETIME* pftValue, LPWSTR szValue )
701
{
702 703 704 705 706 707 708 709
    awstring str;

    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 );
710 711
}

712 713
UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
               UINT uiDataType, INT iValue, FILETIME* pftValue, LPSTR szValue )
714
{
715 716 717 718 719 720 721 722
    awstring str;

    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 );
723 724
}

725
UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
726
{
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
    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;
    r = IStorage_CreateStream( si->db->storage, szSumInfo, grfMode, 0, 0, &stm );
    if( SUCCEEDED(r) )
    {
        ret = save_summary_info( si, stm );
        IStream_Release( stm );
    }
    msiobj_release( &si->hdr );

    return ret;
749
}