xref: /reactos/dll/win32/msi/suminfo.c (revision f4be6dc3)
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002, 2005 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 
23 #define COBJMACROS
24 
25 #include "stdio.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wine/debug.h"
32 #include "wine/exception.h"
33 #include "msi.h"
34 #include "msiquery.h"
35 #include "msidefs.h"
36 #include "objidl.h"
37 #include "propvarutil.h"
38 
39 #include "msipriv.h"
40 #include "winemsi_s.h"
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43 
44 #include "pshpack1.h"
45 
46 struct property_set_header
47 {
48     WORD wByteOrder;
49     WORD wFormat;
50     DWORD dwOSVer;
51     CLSID clsID;
52     DWORD reserved;
53 };
54 
55 struct format_id_offset
56 {
57     FMTID fmtid;
58     DWORD dwOffset;
59 };
60 
61 struct property_section_header
62 {
63     DWORD cbSection;
64     DWORD cProperties;
65 };
66 
67 struct property_id_offset
68 {
69     DWORD propid;
70     DWORD dwOffset;
71 };
72 
73 struct property_data
74 {
75     DWORD type;
76     union {
77         INT i4;
78         SHORT i2;
79         FILETIME ft;
80         struct {
81             DWORD len;
82             BYTE str[1];
83         } str;
84     } u;
85 };
86 
87 #include "poppack.h"
88 
89 static HRESULT (WINAPI *pPropVariantChangeType)
90     (PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc,
91      PROPVAR_CHANGE_FLAGS flags, VARTYPE vt);
92 
93 #define SECT_HDR_SIZE (sizeof(struct property_section_header))
94 
free_prop(PROPVARIANT * prop)95 static void free_prop( PROPVARIANT *prop )
96 {
97     if (prop->vt == VT_LPSTR )
98         free( prop->pszVal );
99     prop->vt = VT_EMPTY;
100 }
101 
MSI_CloseSummaryInfo(MSIOBJECTHDR * arg)102 static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
103 {
104     MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg;
105     DWORD i;
106 
107     for( i = 0; i < MSI_MAX_PROPS; i++ )
108         free_prop( &si->property[i] );
109     IStorage_Release( si->storage );
110 }
111 
112 #ifdef __REACTOS__
113 #define PID_DICTIONARY_MSI 0
114 #define PID_CODEPAGE_MSI 1
115 #define PID_SECURITY_MSI 19
116 #endif
117 
get_type(UINT uiProperty)118 static UINT get_type( UINT uiProperty )
119 {
120     switch( uiProperty )
121     {
122 #ifdef __REACTOS__
123     case PID_CODEPAGE_MSI:
124 #else
125     case PID_CODEPAGE:
126 #endif
127          return VT_I2;
128 
129     case PID_SUBJECT:
130     case PID_AUTHOR:
131     case PID_KEYWORDS:
132     case PID_COMMENTS:
133     case PID_TEMPLATE:
134     case PID_LASTAUTHOR:
135     case PID_REVNUMBER:
136     case PID_APPNAME:
137     case PID_TITLE:
138          return VT_LPSTR;
139 
140     case PID_LASTPRINTED:
141     case PID_CREATE_DTM:
142     case PID_LASTSAVE_DTM:
143          return VT_FILETIME;
144 
145     case PID_WORDCOUNT:
146     case PID_CHARCOUNT:
147 #ifdef __REACTOS__
148     case PID_SECURITY_MSI:
149 #else
150     case PID_SECURITY:
151 #endif
152     case PID_PAGECOUNT:
153          return VT_I4;
154     }
155     return VT_EMPTY;
156 }
157 
get_property_count(const PROPVARIANT * property)158 static UINT get_property_count( const PROPVARIANT *property )
159 {
160     UINT i, n = 0;
161 
162     if( !property )
163         return n;
164     for( i = 0; i < MSI_MAX_PROPS; i++ )
165         if( property[i].vt != VT_EMPTY )
166             n++;
167     return n;
168 }
169 
propvar_changetype(PROPVARIANT * changed,PROPVARIANT * property,VARTYPE vt)170 static UINT propvar_changetype(PROPVARIANT *changed, PROPVARIANT *property, VARTYPE vt)
171 {
172     HRESULT hr;
173     HMODULE propsys = LoadLibraryA("propsys.dll");
174     pPropVariantChangeType = (void *)GetProcAddress(propsys, "PropVariantChangeType");
175 
176     if (!pPropVariantChangeType)
177     {
178         ERR("PropVariantChangeType function missing!\n");
179         return ERROR_FUNCTION_FAILED;
180     }
181 
182     hr = pPropVariantChangeType(changed, property, 0, vt);
183     return (hr == S_OK) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
184 }
185 
186 /* FIXME: doesn't deal with endian conversion */
read_properties_from_data(PROPVARIANT * prop,LPBYTE data,DWORD sz)187 static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz )
188 {
189     UINT type;
190     DWORD i, size;
191     struct property_data *propdata;
192     PROPVARIANT property, *ptr;
193     PROPVARIANT changed;
194     struct property_id_offset *idofs;
195     struct property_section_header *section_hdr;
196 
197     section_hdr = (struct property_section_header *) &data[0];
198     idofs = (struct property_id_offset *)&data[SECT_HDR_SIZE];
199 
200     /* now set all the properties */
201     for( i = 0; i < section_hdr->cProperties; i++ )
202     {
203         if( idofs[i].propid >= MSI_MAX_PROPS )
204         {
205             ERR( "unknown property ID %lu\n", idofs[i].propid );
206             break;
207         }
208 
209         type = get_type( idofs[i].propid );
210         if( type == VT_EMPTY )
211         {
212             ERR( "propid %lu has unknown type\n", idofs[i].propid );
213             break;
214         }
215 
216         propdata = (struct property_data *)&data[ idofs[i].dwOffset ];
217 
218         /* check we don't run off the end of the data */
219         size = sz - idofs[i].dwOffset - sizeof(DWORD);
220         if( sizeof(DWORD) > size ||
221             ( propdata->type == VT_FILETIME && sizeof(FILETIME) > size ) ||
222             ( propdata->type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) )
223         {
224             ERR("not enough data\n");
225             break;
226         }
227 
228         property.vt = propdata->type;
229         if( propdata->type == VT_LPSTR )
230         {
231             char *str = malloc( propdata->u.str.len );
232             memcpy( str, propdata->u.str.str, propdata->u.str.len );
233             str[ propdata->u.str.len - 1 ] = 0;
234             property.pszVal = str;
235         }
236         else if( propdata->type == VT_FILETIME )
237             property.filetime = propdata->u.ft;
238         else if( propdata->type == VT_I2 )
239             property.iVal = propdata->u.i2;
240         else if( propdata->type == VT_I4 )
241             property.lVal = propdata->u.i4;
242 
243         /* check the type is the same as we expect */
244         if( type != propdata->type )
245         {
246             propvar_changetype(&changed, &property, type);
247             ptr = &changed;
248         }
249         else
250             ptr = &property;
251 
252         prop[ idofs[i].propid ] = *ptr;
253     }
254 }
255 
load_summary_info(MSISUMMARYINFO * si,IStream * stm)256 static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
257 {
258     struct property_set_header set_hdr;
259     struct format_id_offset format_hdr;
260     struct property_section_header section_hdr;
261     LPBYTE data = NULL;
262     LARGE_INTEGER ofs;
263     ULONG count, sz;
264     HRESULT r;
265 
266     TRACE("%p %p\n", si, stm);
267 
268     /* read the header */
269     sz = sizeof set_hdr;
270     r = IStream_Read( stm, &set_hdr, sz, &count );
271     if( FAILED(r) || count != sz )
272         return ERROR_FUNCTION_FAILED;
273 
274     if( set_hdr.wByteOrder != 0xfffe )
275     {
276         ERR("property set not big-endian %04X\n", set_hdr.wByteOrder);
277         return ERROR_FUNCTION_FAILED;
278     }
279 
280     sz = sizeof format_hdr;
281     r = IStream_Read( stm, &format_hdr, sz, &count );
282     if( FAILED(r) || count != sz )
283         return ERROR_FUNCTION_FAILED;
284 
285     /* check the format id is correct */
286     if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) )
287         return ERROR_FUNCTION_FAILED;
288 
289     /* seek to the location of the section */
290     ofs.QuadPart = format_hdr.dwOffset;
291     r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL );
292     if( FAILED(r) )
293         return ERROR_FUNCTION_FAILED;
294 
295     /* read the section itself */
296     sz = SECT_HDR_SIZE;
297     r = IStream_Read( stm, &section_hdr, sz, &count );
298     if( FAILED(r) || count != sz )
299         return ERROR_FUNCTION_FAILED;
300 
301     if( section_hdr.cProperties > MSI_MAX_PROPS )
302     {
303         ERR( "too many properties %lu\n", section_hdr.cProperties );
304         return ERROR_FUNCTION_FAILED;
305     }
306 
307     data = malloc( section_hdr.cbSection );
308     if( !data )
309         return ERROR_FUNCTION_FAILED;
310 
311     memcpy( data, &section_hdr, SECT_HDR_SIZE );
312 
313     /* read all the data in one go */
314     sz = section_hdr.cbSection - SECT_HDR_SIZE;
315     r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count );
316     if( SUCCEEDED(r) && count == sz )
317         read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE );
318     else
319         ERR( "failed to read properties %lu %lu\n", count, sz );
320 
321     free( data );
322     return ERROR_SUCCESS;
323 }
324 
write_dword(LPBYTE data,DWORD ofs,DWORD val)325 static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val )
326 {
327     if( data )
328     {
329         data[ofs++] = val&0xff;
330         data[ofs++] = (val>>8)&0xff;
331         data[ofs++] = (val>>16)&0xff;
332         data[ofs++] = (val>>24)&0xff;
333     }
334     return 4;
335 }
336 
write_filetime(LPBYTE data,DWORD ofs,const FILETIME * ft)337 static DWORD write_filetime( LPBYTE data, DWORD ofs, const FILETIME *ft )
338 {
339     write_dword( data, ofs, ft->dwLowDateTime );
340     write_dword( data, ofs + 4, ft->dwHighDateTime );
341     return 8;
342 }
343 
write_string(LPBYTE data,DWORD ofs,LPCSTR str)344 static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str )
345 {
346     DWORD len = lstrlenA( str ) + 1;
347     write_dword( data, ofs, len );
348     if( data )
349         memcpy( &data[ofs + 4], str, len );
350     return (7 + len) & ~3;
351 }
352 
write_property_to_data(const PROPVARIANT * prop,LPBYTE data)353 static UINT write_property_to_data( const PROPVARIANT *prop, LPBYTE data )
354 {
355     DWORD sz = 0;
356 
357     if( prop->vt == VT_EMPTY )
358         return sz;
359 
360     /* add the type */
361     sz += write_dword( data, sz, prop->vt );
362     switch( prop->vt )
363     {
364     case VT_I2:
365         sz += write_dword( data, sz, prop->iVal );
366         break;
367     case VT_I4:
368         sz += write_dword( data, sz, prop->lVal );
369         break;
370     case VT_FILETIME:
371         sz += write_filetime( data, sz, &prop->filetime );
372         break;
373     case VT_LPSTR:
374         sz += write_string( data, sz, prop->pszVal );
375         break;
376     }
377     return sz;
378 }
379 
save_summary_info(const MSISUMMARYINFO * si,IStream * stm)380 static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm )
381 {
382     UINT ret = ERROR_FUNCTION_FAILED;
383     struct property_set_header set_hdr;
384     struct format_id_offset format_hdr;
385     struct property_section_header section_hdr;
386     struct property_id_offset idofs[MSI_MAX_PROPS];
387     LPBYTE data = NULL;
388     ULONG count, sz;
389     HRESULT r;
390     int i;
391 
392     /* write the header */
393     sz = sizeof set_hdr;
394     memset( &set_hdr, 0, sz );
395     set_hdr.wByteOrder = 0xfffe;
396     set_hdr.wFormat = 0;
397     set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */
398     /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */
399     set_hdr.reserved = 1;
400     r = IStream_Write( stm, &set_hdr, sz, &count );
401     if( FAILED(r) || count != sz )
402         return ret;
403 
404     /* write the format header */
405     sz = sizeof format_hdr;
406     format_hdr.fmtid = FMTID_SummaryInformation;
407     format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr;
408     r = IStream_Write( stm, &format_hdr, sz, &count );
409     if( FAILED(r) || count != sz )
410         return ret;
411 
412     /* add up how much space the data will take and calculate the offsets */
413     section_hdr.cbSection = sizeof section_hdr;
414     section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]);
415     section_hdr.cProperties = 0;
416     for( i = 0; i < MSI_MAX_PROPS; i++ )
417     {
418         sz = write_property_to_data( &si->property[i], NULL );
419         if( !sz )
420             continue;
421         idofs[ section_hdr.cProperties ].propid = i;
422         idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection;
423         section_hdr.cProperties++;
424         section_hdr.cbSection += sz;
425     }
426 
427     data = calloc( 1, section_hdr.cbSection );
428 
429     sz = 0;
430     memcpy( &data[sz], &section_hdr, sizeof section_hdr );
431     sz += sizeof section_hdr;
432 
433     memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] );
434     sz += section_hdr.cProperties * sizeof idofs[0];
435 
436     /* write out the data */
437     for( i = 0; i < MSI_MAX_PROPS; i++ )
438         sz += write_property_to_data( &si->property[i], &data[sz] );
439 
440     r = IStream_Write( stm, data, sz, &count );
441     free( data );
442     if( FAILED(r) || count != sz )
443         return ret;
444 
445     return ERROR_SUCCESS;
446 }
447 
create_suminfo(IStorage * stg,UINT update_count)448 static MSISUMMARYINFO *create_suminfo( IStorage *stg, UINT update_count )
449 {
450     MSISUMMARYINFO *si;
451 
452     if (!(si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, sizeof(MSISUMMARYINFO), MSI_CloseSummaryInfo )))
453         return NULL;
454 
455     si->update_count = update_count;
456     IStorage_AddRef( stg );
457     si->storage = stg;
458 
459     return si;
460 }
461 
msi_get_suminfo(IStorage * stg,UINT uiUpdateCount,MSISUMMARYINFO ** ret)462 UINT msi_get_suminfo( IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **ret )
463 {
464     IStream *stm;
465     MSISUMMARYINFO *si;
466     HRESULT hr;
467     UINT r;
468 
469     TRACE("%p, %u\n", stg, uiUpdateCount);
470 
471     if (!(si = create_suminfo( stg, uiUpdateCount ))) return ERROR_OUTOFMEMORY;
472 
473     hr = IStorage_OpenStream( si->storage, L"\5SummaryInformation", 0, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stm );
474     if (FAILED( hr ))
475     {
476         msiobj_release( &si->hdr );
477         return ERROR_FUNCTION_FAILED;
478     }
479 
480     r = load_summary_info( si, stm );
481     IStream_Release( stm );
482     if (r != ERROR_SUCCESS)
483     {
484         msiobj_release( &si->hdr );
485         return r;
486     }
487 
488     *ret = si;
489     return ERROR_SUCCESS;
490 }
491 
msi_get_db_suminfo(MSIDATABASE * db,UINT uiUpdateCount,MSISUMMARYINFO ** ret)492 UINT msi_get_db_suminfo( MSIDATABASE *db, UINT uiUpdateCount, MSISUMMARYINFO **ret )
493 {
494     IStream *stm;
495     MSISUMMARYINFO *si;
496     UINT r;
497 
498     if (!(si = create_suminfo( db->storage, uiUpdateCount ))) return ERROR_OUTOFMEMORY;
499 
500     r = msi_get_stream( db, L"\5SummaryInformation", &stm );
501     if (r != ERROR_SUCCESS)
502     {
503         msiobj_release( &si->hdr );
504         return r;
505     }
506 
507     r = load_summary_info( si, stm );
508     IStream_Release( stm );
509     if (r != ERROR_SUCCESS)
510     {
511         msiobj_release( &si->hdr );
512         return r;
513     }
514 
515     *ret = si;
516     return ERROR_SUCCESS;
517 }
518 
MsiGetSummaryInformationW(MSIHANDLE hDatabase,const WCHAR * szDatabase,UINT uiUpdateCount,MSIHANDLE * pHandle)519 UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, const WCHAR *szDatabase, UINT uiUpdateCount,
520                                        MSIHANDLE *pHandle )
521 {
522     MSISUMMARYINFO *si;
523     MSIDATABASE *db;
524     UINT ret;
525 
526     TRACE( "%lu, %s, %u, %p\n", hDatabase, debugstr_w(szDatabase), uiUpdateCount, pHandle );
527 
528     if( !pHandle )
529         return ERROR_INVALID_PARAMETER;
530 
531     if( szDatabase && szDatabase[0] )
532     {
533         LPCWSTR persist = uiUpdateCount ? MSIDBOPEN_TRANSACT : MSIDBOPEN_READONLY;
534 
535         ret = MSI_OpenDatabaseW( szDatabase, persist, &db );
536         if( ret != ERROR_SUCCESS )
537             return ret;
538     }
539     else
540     {
541         db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
542         if( !db )
543         {
544             MSIHANDLE remote, remote_suminfo;
545 
546             if (!(remote = msi_get_remote(hDatabase)))
547                 return ERROR_INVALID_HANDLE;
548 
549             __TRY
550             {
551                 ret = remote_DatabaseGetSummaryInformation(remote, uiUpdateCount, &remote_suminfo);
552             }
553             __EXCEPT(rpc_filter)
554             {
555                 ret = GetExceptionCode();
556             }
557             __ENDTRY
558 
559             if (!ret)
560                 *pHandle = alloc_msi_remote_handle(remote_suminfo);
561 
562             return ret;
563         }
564     }
565 
566     ret = msi_get_suminfo( db->storage, uiUpdateCount, &si );
567     if (ret != ERROR_SUCCESS)
568         ret = msi_get_db_suminfo( db, uiUpdateCount, &si );
569     if (ret != ERROR_SUCCESS)
570     {
571         if ((si = create_suminfo( db->storage, uiUpdateCount )))
572             ret = ERROR_SUCCESS;
573     }
574 
575     if (ret == ERROR_SUCCESS)
576     {
577         *pHandle = alloc_msihandle( &si->hdr );
578         if( *pHandle )
579             ret = ERROR_SUCCESS;
580         else
581             ret = ERROR_NOT_ENOUGH_MEMORY;
582         msiobj_release( &si->hdr );
583     }
584 
585     msiobj_release( &db->hdr );
586     return ret;
587 }
588 
MsiGetSummaryInformationA(MSIHANDLE hDatabase,const char * szDatabase,UINT uiUpdateCount,MSIHANDLE * pHandle)589 UINT WINAPI MsiGetSummaryInformationA( MSIHANDLE hDatabase, const char *szDatabase, UINT uiUpdateCount,
590                                        MSIHANDLE *pHandle )
591 {
592     WCHAR *szwDatabase = NULL;
593     UINT ret;
594 
595     TRACE( "%lu, %s, %u, %p\n", hDatabase, debugstr_a(szDatabase), uiUpdateCount, pHandle );
596 
597     if( szDatabase )
598     {
599         szwDatabase = strdupAtoW( szDatabase );
600         if( !szwDatabase )
601             return ERROR_FUNCTION_FAILED;
602     }
603 
604     ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle);
605 
606     free( szwDatabase );
607 
608     return ret;
609 }
610 
MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo,UINT * pCount)611 UINT WINAPI MsiSummaryInfoGetPropertyCount( MSIHANDLE hSummaryInfo, UINT *pCount )
612 {
613     MSISUMMARYINFO *si;
614 
615     TRACE( "%lu, %p\n", hSummaryInfo, pCount );
616 
617     si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
618     if( !si )
619     {
620         MSIHANDLE remote;
621         UINT ret;
622 
623         if (!(remote = msi_get_remote( hSummaryInfo )))
624             return ERROR_INVALID_HANDLE;
625 
626         __TRY
627         {
628             ret = remote_SummaryInfoGetPropertyCount( remote, pCount );
629         }
630         __EXCEPT(rpc_filter)
631         {
632             ret = GetExceptionCode();
633         }
634         __ENDTRY
635 
636         return ret;
637     }
638 
639     if( pCount )
640         *pCount = get_property_count( si->property );
641     msiobj_release( &si->hdr );
642 
643     return ERROR_SUCCESS;
644 }
645 
get_prop(MSISUMMARYINFO * si,UINT uiProperty,UINT * puiDataType,INT * piValue,FILETIME * pftValue,awstring * str,DWORD * pcchValueBuf)646 static UINT get_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT *puiDataType, INT *piValue,
647                       FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
648 {
649     PROPVARIANT *prop;
650     UINT ret = ERROR_SUCCESS;
651 
652     prop = &si->property[uiProperty];
653 
654     if( puiDataType )
655         *puiDataType = prop->vt;
656 
657     switch( prop->vt )
658     {
659     case VT_I2:
660         if( piValue )
661             *piValue = prop->iVal;
662         break;
663     case VT_I4:
664         if( piValue )
665             *piValue = prop->lVal;
666         break;
667     case VT_LPSTR:
668         if( pcchValueBuf )
669         {
670             DWORD len = 0;
671 
672             if( str->unicode )
673             {
674                 len = MultiByteToWideChar( CP_ACP, 0, prop->pszVal, -1, NULL, 0 ) - 1;
675                 MultiByteToWideChar( CP_ACP, 0, prop->pszVal, -1, str->str.w, *pcchValueBuf );
676             }
677             else
678             {
679                 len = lstrlenA( prop->pszVal );
680                 if( str->str.a )
681                     lstrcpynA(str->str.a, prop->pszVal, *pcchValueBuf );
682             }
683             if (len >= *pcchValueBuf)
684                 ret = ERROR_MORE_DATA;
685             *pcchValueBuf = len;
686         }
687         break;
688     case VT_FILETIME:
689         if( pftValue )
690             *pftValue = prop->filetime;
691         break;
692     case VT_EMPTY:
693         break;
694     default:
695         FIXME("Unknown property variant type\n");
696         break;
697     }
698     return ret;
699 }
700 
msi_suminfo_dup_string(MSISUMMARYINFO * si,UINT uiProperty)701 LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty )
702 {
703     PROPVARIANT *prop;
704 
705     if ( uiProperty >= MSI_MAX_PROPS )
706         return NULL;
707     prop = &si->property[uiProperty];
708     if( prop->vt != VT_LPSTR )
709         return NULL;
710     return strdupAtoW( prop->pszVal );
711 }
712 
msi_suminfo_get_int32(MSISUMMARYINFO * si,UINT uiProperty)713 INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty )
714 {
715     PROPVARIANT *prop;
716 
717     if ( uiProperty >= MSI_MAX_PROPS )
718         return -1;
719     prop = &si->property[uiProperty];
720     if( prop->vt != VT_I4 )
721         return -1;
722     return prop->lVal;
723 }
724 
msi_get_suminfo_product(IStorage * stg)725 LPWSTR msi_get_suminfo_product( IStorage *stg )
726 {
727     MSISUMMARYINFO *si;
728     LPWSTR prod;
729     UINT r;
730 
731     r = msi_get_suminfo( stg, 0, &si );
732     if (r != ERROR_SUCCESS)
733     {
734         ERR("no summary information!\n");
735         return NULL;
736     }
737     prod = msi_suminfo_dup_string( si, PID_REVNUMBER );
738     msiobj_release( &si->hdr );
739     return prod;
740 }
741 
MsiSummaryInfoGetPropertyA(MSIHANDLE handle,UINT uiProperty,UINT * puiDataType,INT * piValue,FILETIME * pftValue,char * szValueBuf,DWORD * pcchValueBuf)742 UINT WINAPI MsiSummaryInfoGetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
743                                         FILETIME *pftValue, char *szValueBuf, DWORD *pcchValueBuf )
744 {
745     MSISUMMARYINFO *si;
746     awstring str;
747     UINT r;
748 
749     TRACE( "%lu, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType, piValue, pftValue, szValueBuf,
750            pcchValueBuf );
751 
752     if (uiProperty >= MSI_MAX_PROPS)
753     {
754         if (puiDataType) *puiDataType = VT_EMPTY;
755         return ERROR_UNKNOWN_PROPERTY;
756     }
757 
758     if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
759     {
760         MSIHANDLE remote;
761         WCHAR *buf = NULL;
762 
763         if (!(remote = msi_get_remote( handle )))
764             return ERROR_INVALID_HANDLE;
765 
766         __TRY
767         {
768             r = remote_SummaryInfoGetProperty( remote, uiProperty, puiDataType, piValue, pftValue, &buf );
769         }
770         __EXCEPT(rpc_filter)
771         {
772             r = GetExceptionCode();
773         }
774         __ENDTRY
775 
776         if (!r && buf)
777         {
778             r = msi_strncpyWtoA( buf, -1, szValueBuf, pcchValueBuf, TRUE );
779         }
780 
781         midl_user_free( buf );
782         return r;
783     }
784 
785     str.unicode = FALSE;
786     str.str.a = szValueBuf;
787 
788     r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf );
789     msiobj_release( &si->hdr );
790     return r;
791 }
792 
MsiSummaryInfoGetPropertyW(MSIHANDLE handle,UINT uiProperty,UINT * puiDataType,INT * piValue,FILETIME * pftValue,WCHAR * szValueBuf,DWORD * pcchValueBuf)793 UINT WINAPI MsiSummaryInfoGetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
794                                         FILETIME *pftValue, WCHAR *szValueBuf, DWORD *pcchValueBuf )
795 {
796     MSISUMMARYINFO *si;
797     awstring str;
798     UINT r;
799 
800     TRACE( "%lu, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType, piValue, pftValue, szValueBuf,
801            pcchValueBuf );
802 
803     if (uiProperty >= MSI_MAX_PROPS)
804     {
805         if (puiDataType) *puiDataType = VT_EMPTY;
806         return ERROR_UNKNOWN_PROPERTY;
807     }
808 
809     if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
810     {
811         MSIHANDLE remote;
812         WCHAR *buf = NULL;
813 
814         if (!(remote = msi_get_remote( handle )))
815             return ERROR_INVALID_HANDLE;
816 
817         __TRY
818         {
819             r = remote_SummaryInfoGetProperty( remote, uiProperty, puiDataType, piValue, pftValue, &buf );
820         }
821         __EXCEPT(rpc_filter)
822         {
823             r = GetExceptionCode();
824         }
825         __ENDTRY
826 
827         if (!r && buf)
828             r = msi_strncpyW( buf, -1, szValueBuf, pcchValueBuf );
829 
830         midl_user_free( buf );
831         return r;
832     }
833 
834     str.unicode = TRUE;
835     str.str.w = szValueBuf;
836 
837     r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf );
838     msiobj_release( &si->hdr );
839     return r;
840 }
841 
set_prop(MSISUMMARYINFO * si,UINT uiProperty,UINT type,INT iValue,FILETIME * pftValue,awcstring * str)842 static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type,
843                       INT iValue, FILETIME *pftValue, awcstring *str )
844 {
845     PROPVARIANT *prop;
846     UINT len;
847 
848     TRACE("%p, %u, %u, %d, %p, %p\n", si, uiProperty, type, iValue, pftValue, str );
849 
850     prop = &si->property[uiProperty];
851 
852     if( prop->vt == VT_EMPTY )
853     {
854         if( !si->update_count )
855             return ERROR_FUNCTION_FAILED;
856 
857         si->update_count--;
858     }
859     else if( prop->vt != type )
860         return ERROR_SUCCESS;
861 
862     free_prop( prop );
863     prop->vt = type;
864     switch( type )
865     {
866     case VT_I4:
867         prop->lVal = iValue;
868         break;
869     case VT_I2:
870         prop->iVal = iValue;
871         break;
872     case VT_FILETIME:
873         prop->filetime = *pftValue;
874         break;
875     case VT_LPSTR:
876         if( str->unicode )
877         {
878             len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
879                                        NULL, 0, NULL, NULL );
880             prop->pszVal = malloc( len );
881             WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
882                                  prop->pszVal, len, NULL, NULL );
883         }
884         else
885         {
886             len = lstrlenA( str->str.a ) + 1;
887             prop->pszVal = malloc( len );
888             lstrcpyA( prop->pszVal, str->str.a );
889         }
890         break;
891     }
892 
893     return ERROR_SUCCESS;
894 }
895 
suminfo_set_prop(MSISUMMARYINFO * si,UINT uiProperty,UINT uiDataType,INT iValue,FILETIME * pftValue,awcstring * str)896 static UINT suminfo_set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT uiDataType, INT iValue, FILETIME *pftValue,
897                               awcstring *str )
898 {
899     UINT type = get_type( uiProperty );
900     if( type == VT_EMPTY || type != uiDataType )
901         return ERROR_DATATYPE_MISMATCH;
902 
903     if( uiDataType == VT_LPSTR && !str->str.a )
904         return ERROR_INVALID_PARAMETER;
905 
906     if( uiDataType == VT_FILETIME && !pftValue )
907         return ERROR_INVALID_PARAMETER;
908 
909     return set_prop( si, uiProperty, type, iValue, pftValue, str );
910 }
911 
MsiSummaryInfoSetPropertyW(MSIHANDLE handle,UINT uiProperty,UINT uiDataType,INT iValue,FILETIME * pftValue,const WCHAR * szValue)912 UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, INT iValue,
913                                         FILETIME *pftValue, const WCHAR *szValue )
914 {
915     awcstring str;
916     MSISUMMARYINFO *si;
917     UINT ret;
918 
919     TRACE( "%lu, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue, debugstr_w(szValue) );
920 
921     if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
922     {
923         MSIHANDLE remote;
924 
925         if ((remote = msi_get_remote( handle )))
926         {
927             WARN("MsiSummaryInfoSetProperty not allowed during a custom action!\n");
928             return ERROR_FUNCTION_FAILED;
929         }
930 
931         return ERROR_INVALID_HANDLE;
932     }
933 
934     str.unicode = TRUE;
935     str.str.w = szValue;
936 
937     ret = suminfo_set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str );
938     msiobj_release( &si->hdr );
939     return ret;
940 }
941 
MsiSummaryInfoSetPropertyA(MSIHANDLE handle,UINT uiProperty,UINT uiDataType,INT iValue,FILETIME * pftValue,const char * szValue)942 UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, INT iValue,
943                                         FILETIME *pftValue, const char *szValue )
944 {
945     awcstring str;
946     MSISUMMARYINFO *si;
947     UINT ret;
948 
949     TRACE( "%lu, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue, debugstr_a(szValue) );
950 
951     if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
952     {
953         MSIHANDLE remote;
954 
955         if ((remote = msi_get_remote( handle )))
956         {
957             WARN("MsiSummaryInfoSetProperty not allowed during a custom action!\n");
958             return ERROR_FUNCTION_FAILED;
959         }
960 
961         return ERROR_INVALID_HANDLE;
962     }
963 
964     str.unicode = FALSE;
965     str.str.a = szValue;
966 
967     ret = suminfo_set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str );
968     msiobj_release( &si->hdr );
969     return ret;
970 }
971 
suminfo_persist(MSISUMMARYINFO * si)972 static UINT suminfo_persist( MSISUMMARYINFO *si )
973 {
974     UINT ret = ERROR_FUNCTION_FAILED;
975     IStream *stm = NULL;
976     DWORD grfMode;
977     HRESULT r;
978 
979     grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
980     r = IStorage_CreateStream( si->storage, L"\5SummaryInformation", grfMode, 0, 0, &stm );
981     if( SUCCEEDED(r) )
982     {
983         ret = save_summary_info( si, stm );
984         IStream_Release( stm );
985     }
986     return ret;
987 }
988 
parse_filetime(LPCWSTR str,FILETIME * ft)989 static void parse_filetime( LPCWSTR str, FILETIME *ft )
990 {
991     SYSTEMTIME lt, utc;
992     const WCHAR *p = str;
993     WCHAR *end;
994 
995     memset( &lt, 0, sizeof(lt) );
996 
997     /* YYYY/MM/DD hh:mm:ss */
998 
999     while (iswspace( *p )) p++;
1000 
1001     lt.wYear = wcstol( p, &end, 10 );
1002     if (*end != '/') return;
1003     p = end + 1;
1004 
1005     lt.wMonth = wcstol( p, &end, 10 );
1006     if (*end != '/') return;
1007     p = end + 1;
1008 
1009     lt.wDay = wcstol( p, &end, 10 );
1010     if (*end != ' ') return;
1011     p = end + 1;
1012 
1013     while (iswspace( *p )) p++;
1014 
1015     lt.wHour = wcstol( p, &end, 10 );
1016     if (*end != ':') return;
1017     p = end + 1;
1018 
1019     lt.wMinute = wcstol( p, &end, 10 );
1020     if (*end != ':') return;
1021     p = end + 1;
1022 
1023     lt.wSecond = wcstol( p, &end, 10 );
1024 
1025     TzSpecificLocalTimeToSystemTime( NULL, &lt, &utc );
1026     SystemTimeToFileTime( &utc, ft );
1027 }
1028 
parse_prop(LPCWSTR prop,LPCWSTR value,UINT * pid,INT * int_value,FILETIME * ft_value,awcstring * str_value)1029 static UINT parse_prop( LPCWSTR prop, LPCWSTR value, UINT *pid, INT *int_value,
1030                         FILETIME *ft_value, awcstring *str_value )
1031 {
1032     *pid = wcstol( prop, NULL, 10);
1033     switch (*pid)
1034     {
1035 #ifdef __REACTOS__
1036     case PID_CODEPAGE_MSI:
1037 #else
1038     case PID_CODEPAGE:
1039 #endif
1040     case PID_WORDCOUNT:
1041     case PID_CHARCOUNT:
1042 #ifdef __REACTOS__
1043     case PID_SECURITY_MSI:
1044 #else
1045     case PID_SECURITY:
1046 #endif
1047     case PID_PAGECOUNT:
1048         *int_value = wcstol( value, NULL, 10);
1049         break;
1050 
1051     case PID_LASTPRINTED:
1052     case PID_CREATE_DTM:
1053     case PID_LASTSAVE_DTM:
1054         parse_filetime( value, ft_value );
1055         break;
1056 
1057     case PID_SUBJECT:
1058     case PID_AUTHOR:
1059     case PID_KEYWORDS:
1060     case PID_COMMENTS:
1061     case PID_TEMPLATE:
1062     case PID_LASTAUTHOR:
1063     case PID_REVNUMBER:
1064     case PID_APPNAME:
1065     case PID_TITLE:
1066         str_value->str.w = value;
1067         str_value->unicode = TRUE;
1068         break;
1069 
1070     default:
1071         WARN("unhandled prop id %u\n", *pid);
1072         return ERROR_FUNCTION_FAILED;
1073     }
1074 
1075     return ERROR_SUCCESS;
1076 }
1077 
msi_add_suminfo(MSIDATABASE * db,LPWSTR ** records,int num_records,int num_columns)1078 UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns )
1079 {
1080     UINT r;
1081     int i, j;
1082     MSISUMMARYINFO *si;
1083 
1084     r = msi_get_suminfo( db->storage, num_records * (num_columns / 2), &si );
1085     if (r != ERROR_SUCCESS)
1086     {
1087         if (!(si = create_suminfo( db->storage, num_records * (num_columns / 2) )))
1088             return ERROR_OUTOFMEMORY;
1089         r = ERROR_SUCCESS;
1090     }
1091 
1092     for (i = 0; i < num_records; i++)
1093     {
1094         for (j = 0; j < num_columns; j += 2)
1095         {
1096             UINT pid;
1097             INT int_value = 0;
1098             FILETIME ft_value;
1099             awcstring str_value;
1100 
1101             r = parse_prop( records[i][j], records[i][j + 1], &pid, &int_value, &ft_value, &str_value );
1102             if (r != ERROR_SUCCESS)
1103                 goto end;
1104 
1105             r = set_prop( si, pid, get_type(pid), int_value, &ft_value, &str_value );
1106             if (r != ERROR_SUCCESS)
1107                 goto end;
1108         }
1109     }
1110 
1111 end:
1112     if (r == ERROR_SUCCESS)
1113         r = suminfo_persist( si );
1114 
1115     msiobj_release( &si->hdr );
1116     return r;
1117 }
1118 
save_prop(MSISUMMARYINFO * si,HANDLE handle,UINT row)1119 static UINT save_prop( MSISUMMARYINFO *si, HANDLE handle, UINT row )
1120 {
1121     static const char fmt_systemtime[] = "%04u/%02u/%02u %02u:%02u:%02u";
1122     char data[36]; /* largest string: YYYY/MM/DD hh:mm:ss */
1123     static const char fmt_begin[] = "%u\t";
1124     static const char data_end[] = "\r\n";
1125     static const char fmt_int[] = "%u";
1126     UINT r, data_type;
1127     SYSTEMTIME system_time;
1128     FILETIME file_time;
1129     INT int_value;
1130     awstring str;
1131     DWORD len, sz;
1132 
1133     str.unicode = FALSE;
1134     str.str.a = NULL;
1135     len = 0;
1136     r = get_prop( si, row, &data_type, &int_value, &file_time, &str, &len );
1137     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
1138         return r;
1139     if (data_type == VT_EMPTY)
1140         return ERROR_SUCCESS; /* property not set */
1141     sz = sprintf( data, fmt_begin, row );
1142     if (!WriteFile( handle, data, sz, &sz, NULL ))
1143         return ERROR_WRITE_FAULT;
1144 
1145     switch( data_type )
1146     {
1147     case VT_I2:
1148     case VT_I4:
1149         sz = sprintf( data, fmt_int, int_value );
1150         if (!WriteFile( handle, data, sz, &sz, NULL ))
1151             return ERROR_WRITE_FAULT;
1152         break;
1153     case VT_LPSTR:
1154         len++;
1155         if (!(str.str.a = malloc( len )))
1156             return ERROR_OUTOFMEMORY;
1157         r = get_prop( si, row, NULL, NULL, NULL, &str, &len );
1158         if (r != ERROR_SUCCESS)
1159         {
1160             free( str.str.a );
1161             return r;
1162         }
1163         sz = len;
1164         if (!WriteFile( handle, str.str.a, sz, &sz, NULL ))
1165         {
1166             free( str.str.a );
1167             return ERROR_WRITE_FAULT;
1168         }
1169         free( str.str.a );
1170         break;
1171     case VT_FILETIME:
1172         if (!FileTimeToSystemTime( &file_time, &system_time ))
1173             return ERROR_FUNCTION_FAILED;
1174         sz = sprintf( data, fmt_systemtime, system_time.wYear, system_time.wMonth,
1175                       system_time.wDay, system_time.wHour, system_time.wMinute,
1176                       system_time.wSecond );
1177         if (!WriteFile( handle, data, sz, &sz, NULL ))
1178             return ERROR_WRITE_FAULT;
1179         break;
1180     case VT_EMPTY:
1181         /* cannot reach here, property not set */
1182         break;
1183     default:
1184         FIXME( "Unknown property variant type\n" );
1185         return ERROR_FUNCTION_FAILED;
1186     }
1187 
1188     sz = ARRAY_SIZE(data_end) - 1;
1189     if (!WriteFile( handle, data_end, sz, &sz, NULL ))
1190         return ERROR_WRITE_FAULT;
1191 
1192     return ERROR_SUCCESS;
1193 }
1194 
msi_export_suminfo(MSIDATABASE * db,HANDLE handle)1195 UINT msi_export_suminfo( MSIDATABASE *db, HANDLE handle )
1196 {
1197     UINT i, r, num_rows;
1198     MSISUMMARYINFO *si;
1199 
1200     r = msi_get_suminfo( db->storage, 0, &si );
1201     if (r != ERROR_SUCCESS)
1202         r = msi_get_db_suminfo( db, 0, &si );
1203     if (r != ERROR_SUCCESS)
1204         return r;
1205 
1206     num_rows = get_property_count( si->property );
1207     if (!num_rows)
1208     {
1209         msiobj_release( &si->hdr );
1210         return ERROR_FUNCTION_FAILED;
1211     }
1212 
1213     for (i = 0; i < num_rows; i++)
1214     {
1215         r = save_prop( si, handle, i );
1216         if (r != ERROR_SUCCESS)
1217         {
1218             msiobj_release( &si->hdr );
1219             return r;
1220         }
1221     }
1222 
1223     msiobj_release( &si->hdr );
1224     return ERROR_SUCCESS;
1225 }
1226 
MsiSummaryInfoPersist(MSIHANDLE handle)1227 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
1228 {
1229     MSISUMMARYINFO *si;
1230     UINT ret;
1231 
1232     TRACE( "%lu\n", handle );
1233 
1234     si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
1235     if( !si )
1236         return ERROR_INVALID_HANDLE;
1237 
1238     ret = suminfo_persist( si );
1239 
1240     msiobj_release( &si->hdr );
1241     return ret;
1242 }
1243 
MsiCreateTransformSummaryInfoA(MSIHANDLE db,MSIHANDLE db_ref,const char * transform,int error,int validation)1244 UINT WINAPI MsiCreateTransformSummaryInfoA( MSIHANDLE db, MSIHANDLE db_ref, const char *transform, int error,
1245                                             int validation )
1246 {
1247     UINT r;
1248     WCHAR *transformW = NULL;
1249 
1250     TRACE( "%lu, %lu, %s, %d, %d\n", db, db_ref, debugstr_a(transform), error, validation );
1251 
1252     if (transform && !(transformW = strdupAtoW( transform )))
1253         return ERROR_OUTOFMEMORY;
1254 
1255     r = MsiCreateTransformSummaryInfoW( db, db_ref, transformW, error, validation );
1256     free( transformW );
1257     return r;
1258 }
1259 
MsiCreateTransformSummaryInfoW(MSIHANDLE db,MSIHANDLE db_ref,const WCHAR * transform,int error,int validation)1260 UINT WINAPI MsiCreateTransformSummaryInfoW( MSIHANDLE db, MSIHANDLE db_ref, const WCHAR *transform, int error,
1261                                             int validation )
1262 {
1263     FIXME( "%lu, %lu, %s, %d, %d\n", db, db_ref, debugstr_w(transform), error, validation );
1264     return ERROR_FUNCTION_FAILED;
1265 }
1266 
msi_load_suminfo_properties(MSIPACKAGE * package)1267 UINT msi_load_suminfo_properties( MSIPACKAGE *package )
1268 {
1269     MSISUMMARYINFO *si;
1270     WCHAR *package_code;
1271     UINT r;
1272     DWORD len;
1273     awstring str;
1274     INT count;
1275 
1276     r = msi_get_suminfo( package->db->storage, 0, &si );
1277     if (r != ERROR_SUCCESS)
1278     {
1279         r = msi_get_db_suminfo( package->db, 0, &si );
1280         if (r != ERROR_SUCCESS)
1281         {
1282             ERR("Unable to open summary information stream %u\n", r);
1283             return r;
1284         }
1285     }
1286 
1287     str.unicode = TRUE;
1288     str.str.w = NULL;
1289     len = 0;
1290     r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len );
1291     if (r != ERROR_MORE_DATA)
1292     {
1293         WARN("Unable to query revision number %u\n", r);
1294         msiobj_release( &si->hdr );
1295         return ERROR_FUNCTION_FAILED;
1296     }
1297 
1298     len++;
1299     if (!(package_code = malloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
1300     str.str.w = package_code;
1301 
1302     r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len );
1303     if (r != ERROR_SUCCESS)
1304     {
1305         free( package_code );
1306         msiobj_release( &si->hdr );
1307         return r;
1308     }
1309 
1310     r = msi_set_property( package->db, L"PackageCode", package_code, len );
1311     free( package_code );
1312 
1313     count = 0;
1314     get_prop( si, PID_WORDCOUNT, NULL, &count, NULL, NULL, NULL );
1315     package->WordCount = count;
1316 
1317     msiobj_release( &si->hdr );
1318     return r;
1319 }
1320 
s_remote_SummaryInfoGetPropertyCount(MSIHANDLE suminfo,UINT * count)1321 UINT __cdecl s_remote_SummaryInfoGetPropertyCount( MSIHANDLE suminfo, UINT *count )
1322 {
1323     return MsiSummaryInfoGetPropertyCount( suminfo, count );
1324 }
1325 
s_remote_SummaryInfoGetProperty(MSIHANDLE suminfo,UINT property,UINT * type,INT * value,FILETIME * ft,LPWSTR * buf)1326 UINT __cdecl s_remote_SummaryInfoGetProperty( MSIHANDLE suminfo, UINT property, UINT *type,
1327                                               INT *value, FILETIME *ft, LPWSTR *buf )
1328 {
1329     WCHAR empty[1];
1330     DWORD size = 0;
1331     UINT r;
1332 
1333     r = MsiSummaryInfoGetPropertyW( suminfo, property, type, value, ft, empty, &size );
1334     if (r == ERROR_MORE_DATA)
1335     {
1336         size++;
1337         *buf = midl_user_allocate( size * sizeof(WCHAR) );
1338         if (!*buf) return ERROR_OUTOFMEMORY;
1339         r = MsiSummaryInfoGetPropertyW( suminfo, property, type, value, ft, *buf, &size );
1340     }
1341     return r;
1342 }
1343