MSI: implement summary information loading and saving

Mike McCormack mike at codeweavers.com
Fri Mar 18 04:31:49 CST 2005


ChangeLog:
* implement summary information loading and saving
-------------- next part --------------
Index: include/msi.h
===================================================================
RCS file: /home/wine/wine/include/msi.h,v
retrieving revision 1.21
diff -u -p -r1.21 msi.h
--- include/msi.h	10 Feb 2005 18:57:42 -0000	1.21
+++ include/msi.h	18 Mar 2005 10:30:52 -0000
@@ -201,20 +201,6 @@ UINT WINAPI MsiOpenProductA(LPCSTR, MSIH
 UINT WINAPI MsiOpenProductW(LPCWSTR, MSIHANDLE*);
 #define     MsiOpenProduct WINELIB_NAME_AW(MsiOpenProduct)
 
-UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *);
-UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *);
-#define     MsiGetSummaryInformation WINELIB_NAME_AW(MsiGetSummaryInformation)
-
-UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*);
-UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*);
-#define     MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty)
-
-UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE);
-
-UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPSTR);
-UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPWSTR);
-#define     MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty)
-
 UINT WINAPI MsiProvideComponentFromDescriptorA(LPCSTR,LPSTR,DWORD*,DWORD*);
 UINT WINAPI MsiProvideComponentFromDescriptorW(LPCWSTR,LPWSTR,DWORD*,DWORD*);
 #define     MsiProvideComponentFromDescriptor WINELIB_NAME_AW(MsiProvideComponentFromDescriptor)
Index: include/msiquery.h
===================================================================
RCS file: /home/wine/wine/include/msiquery.h,v
retrieving revision 1.10
diff -u -p -r1.10 msiquery.h
--- include/msiquery.h	28 Jan 2005 11:28:00 -0000	1.10
+++ include/msiquery.h	18 Mar 2005 10:30:52 -0000
@@ -181,6 +181,21 @@ UINT WINAPI MsiPreviewBillboardA(MSIHAND
 UINT WINAPI MsiPreviewBillboardW(MSIHANDLE, LPCWSTR, LPCWSTR);
 #define     MsiPreviewBillboard WINELIB_NAME_AW(MsiPreviewBillboard)
 
+UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *);
+UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *);
+#define     MsiGetSummaryInformation WINELIB_NAME_AW(MsiGetSummaryInformation)
+
+UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*);
+UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*);
+#define     MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty)
+
+UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPSTR);
+UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPWSTR);
+#define     MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty)
+
+UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE);
+UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE,UINT*);
+
 UINT WINAPI MsiEnableUIPreview(MSIHANDLE, MSIHANDLE*);
 BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE);
 
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.50
diff -u -p -r1.50 msipriv.h
--- dlls/msi/msipriv.h	16 Mar 2005 11:31:35 -0000	1.50
+++ dlls/msi/msipriv.h	18 Mar 2005 10:30:53 -0000
@@ -171,12 +171,6 @@ typedef struct tagMSIVIEWOPS
 
 } MSIVIEWOPS;
 
-typedef struct tagMSISUMMARYINFO
-{
-    MSIOBJECTHDR hdr;
-    IPropertyStorage *propstg;
-} MSISUMMARYINFO;
-
 struct tagMSIVIEW
 {
     MSIOBJECTHDR hdr;
Index: dlls/msi/suminfo.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/suminfo.c,v
retrieving revision 1.14
diff -u -p -r1.14 suminfo.c
--- dlls/msi/suminfo.c	10 Mar 2005 11:15:40 -0000	1.14
+++ dlls/msi/suminfo.c	18 Mar 2005 10:30:53 -0000
@@ -1,7 +1,7 @@
 /*
  * Implementation of the Microsoft Installer (msi.dll)
  *
- * Copyright 2002 Mike McCormack for CodeWeavers
+ * Copyright 2002, 2005 Mike McCormack for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -31,61 +31,395 @@
 #include "wine/debug.h"
 #include "msi.h"
 #include "msiquery.h"
+#include "msidefs.h"
 #include "msipriv.h"
 #include "objidl.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
+#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;
+
 static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y',
                        'I','n','f','o','r','m','a','t','i','o','n',0 };
 
 static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
 {
-    MSISUMMARYINFO *suminfo = (MSISUMMARYINFO *) arg;
-    IPropertyStorage_Release( suminfo->propstg );
+    MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg;
+    msiobj_release( &si->db->hdr );
 }
 
-UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase, 
-              LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *phSummaryInfo)
+static UINT get_type( UINT uiProperty )
 {
-    LPWSTR szwDatabase = NULL;
-    UINT ret;
+    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;
+}
 
-    TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase), 
-          uiUpdateCount, phSummaryInfo);
+static UINT get_property_count( PROPVARIANT *property )
+{
+    UINT i, n = 0;
 
-    if( szDatabase )
+    if( !property )
+        return n;
+    for( i=0; i<MSI_MAX_PROPS; i++ )
+        if( property[i].vt != VT_EMPTY )
+            n++;
+    return n;
+}
+
+/* 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++ )
     {
-        UINT len = MultiByteToWideChar( CP_ACP, 0, szDatabase, -1, NULL, 0 );
-        szwDatabase = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
-        if( !szwDatabase )
-            return ERROR_FUNCTION_FAILED;
-        MultiByteToWideChar( CP_ACP, 0, szDatabase, -1, szwDatabase, len );
+        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;
+    }
+}
+
+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;
+
+    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;
     }
 
-    ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, phSummaryInfo);
+    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;
 
-    HeapFree( GetProcessHeap(), 0, szwDatabase );
+    /* 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 );
+    }
+
+    HeapFree( GetProcessHeap(), 0, data );
     return ret;
 }
 
-UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE hDatabase, 
-              LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *phSummaryInfo)
+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 )
+{
+    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;
     HRESULT r;
+    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;
     MSIHANDLE handle;
-    MSISUMMARYINFO *suminfo;
     MSIDATABASE *db;
-    UINT ret = ERROR_SUCCESS;
-    IPropertySetStorage *psstg = NULL;
-    IPropertyStorage *ps = NULL;
     DWORD grfMode;
+    HRESULT r;
 
     TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
-           uiUpdateCount, phSummaryInfo);
+           uiUpdateCount, pHandle);
 
-    if( !phSummaryInfo )
+    if( !pHandle )
         return ERROR_INVALID_PARAMETER;
 
     if( szDatabase )
@@ -103,113 +437,136 @@ UINT WINAPI MsiGetSummaryInformationW(MS
             return ERROR_INVALID_PARAMETER;
     }
 
-    r = IStorage_QueryInterface( db->storage, 
-             &IID_IPropertySetStorage, (LPVOID)&psstg);
-    if( FAILED( r ) )
+    si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, 
+                  sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
+    if( !si )
     {
-        ERR("IStorage -> IPropertySetStorage failed\n");
         ret = ERROR_FUNCTION_FAILED;
         goto end;
     }
 
-    grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
-    r = IPropertySetStorage_Open( psstg, &FMTID_SummaryInformation, grfMode, &ps );
-    if( FAILED( r ) )
-    {
-        ERR("failed to get IPropertyStorage r=%08lx\n",r);
-        ret = ERROR_FUNCTION_FAILED;
-        goto end;
-    }
+    msiobj_addref( &db->hdr );
+    si->db = db;
+    memset( &si->property, 0, sizeof si->property );
+    si->update_count = uiUpdateCount;
 
-    suminfo = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, 
-                  sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
-    if( !suminfo )
+    /* 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) )
     {
-        ret = ERROR_FUNCTION_FAILED;
-        goto end;
+        load_summary_info( si, stm );
+        IStream_Release( stm );
     }
 
-    IPropertyStorage_AddRef(ps);
-    suminfo->propstg = ps;
-    handle = alloc_msihandle( &suminfo->hdr );
+    handle = alloc_msihandle( &si->hdr );
     if( handle )
-        *phSummaryInfo = handle;
+        *pHandle = handle;
     else
         ret = ERROR_FUNCTION_FAILED;
-    msiobj_release( &suminfo->hdr );
+    msiobj_release( &si->hdr );
 
 end:
-    if( ps )
-        IPropertyStorage_Release(ps);
-    if( psstg )
-        IPropertySetStorage_Release(psstg);
     if( db )
         msiobj_release(&db->hdr);
 
     return ret;
 }
 
-UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount)
+UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase, 
+              LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
 {
-    MSISUMMARYINFO *suminfo;
+    LPWSTR szwDatabase = NULL;
+    UINT ret;
 
-    FIXME("%ld %p\n",hSummaryInfo, pCount);
+    TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase), 
+          uiUpdateCount, pHandle);
 
-    suminfo = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
-    if( !suminfo )
-        return ERROR_INVALID_HANDLE;
+    if( szDatabase )
+    {
+        szwDatabase = strdupAtoW( szDatabase );
+        if( !szwDatabase )
+            return ERROR_FUNCTION_FAILED;
+    }
+
+    ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle);
+
+    HeapFree( GetProcessHeap(), 0, szwDatabase );
 
-    msiobj_release( &suminfo->hdr );
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    return ret;
 }
 
-UINT WINAPI MsiSummaryInfoGetPropertyA(
-      MSIHANDLE hSummaryInfo, UINT uiProperty, UINT *puiDataType, INT *piValue,
-      FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf)
+UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount)
 {
-    MSISUMMARYINFO *suminfo;
-    HRESULT r;
-    PROPSPEC spec;
-    PROPVARIANT var;
-    UINT rc = ERROR_SUCCESS;
-
-    TRACE("%ld %d %p %p %p %p %p\n",
-        hSummaryInfo, uiProperty, puiDataType, piValue,
-        pftValue, szValueBuf, pcchValueBuf);
+    MSISUMMARYINFO *si;
 
-    suminfo = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
-    if( !suminfo )
+    TRACE("%ld %p\n",hSummaryInfo, pCount);
+
+    si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
+    if( !si )
         return ERROR_INVALID_HANDLE;
 
-    spec.ulKind = PRSPEC_PROPID;
-    spec.u.propid = uiProperty;
+    if( pCount )
+        *pCount = get_property_count( si->property );
+    msiobj_release( &si->hdr );
 
-    r = IPropertyStorage_ReadMultiple( suminfo->propstg, 1, &spec, &var);
-    if( FAILED(r) )
-    {
-        rc = ERROR_FUNCTION_FAILED;
-        goto end;
-    }
+    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);
+
+    type = get_type( uiProperty );
     if( puiDataType )
-        *puiDataType = var.vt;
+        *puiDataType = type;
+
+    si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
+    if( !si )
+        return ERROR_INVALID_HANDLE;
+
+    prop = &si->property[uiProperty];
+    if( prop->vt != type )
+        goto end;
 
-    switch( var.vt )
+    switch( type )
     {
+    case VT_I2:
+        if( piValue )
+            *piValue = prop->u.iVal;
+        break;
     case VT_I4:
         if( piValue )
-            *piValue = var.u.lVal;
+            *piValue = prop->u.lVal;
         break;
     case VT_LPSTR:
-        if( pcchValueBuf && szValueBuf )
+        if( pcchValueBuf )
         {
-            lstrcpynA(szValueBuf, var.u.pszVal, *pcchValueBuf );
-            *pcchValueBuf = lstrlenA( var.u.pszVal );
+            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;
         }
         break;
     case VT_FILETIME:
         if( pftValue )
-            memcpy(pftValue, &var.u.filetime, sizeof (FILETIME) );
+            memcpy(pftValue, &prop->u.filetime, sizeof (FILETIME) );
         break;
     case VT_EMPTY:
         break;
@@ -217,93 +574,165 @@ UINT WINAPI MsiSummaryInfoGetPropertyA(
         FIXME("Unknown property variant type\n");
         break;
     }
-
 end:
-    msiobj_release( &suminfo->hdr );
-    return rc;
+    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 );
 }
 
 UINT WINAPI MsiSummaryInfoGetPropertyW(
-      MSIHANDLE hSummaryInfo, UINT uiProperty, UINT *puiDataType, INT *piValue,
+      MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
       FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf)
 {
-    MSISUMMARYINFO *suminfo;
-    HRESULT r;
-    PROPSPEC spec;
-    PROPVARIANT var;
-    UINT rc = ERROR_SUCCESS;
-
-    TRACE("%ld %d %p %p %p %p %p\n",
-        hSummaryInfo, uiProperty, puiDataType, piValue,
-        pftValue, szValueBuf, pcchValueBuf);
+    awstring str;
+
+    TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
+          piValue, pftValue, szValueBuf, pcchValueBuf );
+
+    str.unicode = TRUE;
+    str.str.w = szValueBuf;
+
+    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;
 
-    suminfo = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
-    if( !suminfo )
+    si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
+    if( !si )
         return ERROR_INVALID_HANDLE;
 
-    spec.ulKind = PRSPEC_PROPID;
-    spec.u.propid = uiProperty;
+    prop = &si->property[uiProperty];
 
-    r = IPropertyStorage_ReadMultiple( suminfo->propstg, 1, &spec, &var);
-    if( FAILED(r) )
+    if( prop->vt == VT_EMPTY )
     {
-        rc = ERROR_FUNCTION_FAILED;
-        goto end;
+        if( !si->update_count )
+        {
+            ret = ERROR_FUNCTION_FAILED;
+            goto end;
+        }
+        si->update_count--;
+        prop->vt = type;
     }
+    else if( prop->vt != type )
+        goto end;
 
-    if( puiDataType )
-        *puiDataType = var.vt;
-
-    switch( var.vt )
+    switch( type )
     {
     case VT_I4:
-        if( piValue )
-            *piValue = var.u.lVal;
+        prop->u.lVal = iValue;
         break;
-    case VT_LPSTR:
-        if( pcchValueBuf && szValueBuf )
-        {
-            MultiByteToWideChar(CP_ACP, 0,  var.u.pszVal, -1, szValueBuf, 
-                                *pcchValueBuf );
-            *pcchValueBuf = lstrlenA( var.u.pszVal );
-        }
+    case VT_I2:
+        prop->u.iVal = iValue;
         break;
     case VT_FILETIME:
-        if( pftValue )
-            memcpy(pftValue, &var.u.filetime, sizeof (FILETIME) );
+        memcpy( &prop->u.filetime, pftValue, sizeof prop->u.filetime );
         break;
-    case VT_EMPTY:
-        break;
-    default:
-        FIXME("Unknown property variant type\n");
+    case VT_LPSTR:
+        HeapFree( GetProcessHeap(), 0, prop->u.pszVal );
+        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 );
+        }
         break;
     }
 
 end:
-    msiobj_release( &suminfo->hdr );
-    return rc;
+    msiobj_release( &si->hdr );
+    return ret;
 }
 
-UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE hSummaryInfo, UINT uiProperty,
-                                       UINT uiDataType, INT iValue, 
-                                       FILETIME* pftValue, LPSTR szValue )
+UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
+               UINT uiDataType, INT iValue, FILETIME* pftValue, LPWSTR szValue )
 {
-    FIXME("%ld %u %u %i %p %s\n", hSummaryInfo, uiProperty,
-          uiDataType, iValue, pftValue, debugstr_a(szValue) );
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    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 );
 }
 
-UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE hSummaryInfo, UINT uiProperty,
-                                       UINT uiDataType, INT iValue, 
-                                       FILETIME* pftValue, LPWSTR szValue )
+UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
+               UINT uiDataType, INT iValue, FILETIME* pftValue, LPSTR szValue )
 {
-    FIXME("%ld %u %u %i %p %s\n", hSummaryInfo, uiProperty,
-          uiDataType, iValue, pftValue, debugstr_w(szValue) );
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    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 );
 }
 
-UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE hSummaryInfo )
+UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
 {
-    FIXME("%ld\n", hSummaryInfo );
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    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;
 }


More information about the wine-patches mailing list