2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002, 2005 Mike McCormack for CodeWeavers
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.
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.
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
24 #define NONAMELESSUNION
32 #include "wine/debug.h"
33 #include "wine/exception.h"
38 #include "propvarutil.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
47 struct property_set_header
56 struct format_id_offset
62 struct property_section_header
68 struct property_id_offset
90 static HRESULT (WINAPI
*pPropVariantChangeType
)
91 (PROPVARIANT
*ppropvarDest
, REFPROPVARIANT propvarSrc
,
92 PROPVAR_CHANGE_FLAGS flags
, VARTYPE vt
);
94 #define SECT_HDR_SIZE (sizeof(struct property_section_header))
96 static void free_prop( PROPVARIANT
*prop
)
98 if (prop
->vt
== VT_LPSTR
)
103 static void MSI_CloseSummaryInfo( MSIOBJECTHDR
*arg
)
105 MSISUMMARYINFO
*si
= (MSISUMMARYINFO
*) arg
;
108 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
109 free_prop( &si
->property
[i
] );
110 IStorage_Release( si
->storage
);
113 static UINT
get_type( UINT uiProperty
)
131 case PID_LASTPRINTED
:
133 case PID_LASTSAVE_DTM
:
145 static UINT
get_property_count( const PROPVARIANT
*property
)
151 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
152 if( property
[i
].vt
!= VT_EMPTY
)
157 static UINT
propvar_changetype(PROPVARIANT
*changed
, PROPVARIANT
*property
, VARTYPE vt
)
160 HMODULE propsys
= LoadLibraryA("propsys.dll");
161 pPropVariantChangeType
= (void *)GetProcAddress(propsys
, "PropVariantChangeType");
163 if (!pPropVariantChangeType
)
165 ERR("PropVariantChangeType function missing!\n");
166 return ERROR_FUNCTION_FAILED
;
169 hr
= pPropVariantChangeType(changed
, property
, 0, vt
);
170 return (hr
== S_OK
) ? ERROR_SUCCESS
: ERROR_FUNCTION_FAILED
;
173 /* FIXME: doesn't deal with endian conversion */
174 static void read_properties_from_data( PROPVARIANT
*prop
, LPBYTE data
, DWORD sz
)
178 struct property_data
*propdata
;
179 PROPVARIANT property
, *ptr
;
181 struct property_id_offset
*idofs
;
182 struct property_section_header
*section_hdr
;
184 section_hdr
= (struct property_section_header
*) &data
[0];
185 idofs
= (struct property_id_offset
*)&data
[SECT_HDR_SIZE
];
187 /* now set all the properties */
188 for( i
= 0; i
< section_hdr
->cProperties
; i
++ )
190 if( idofs
[i
].propid
>= MSI_MAX_PROPS
)
192 ERR( "unknown property ID %lu\n", idofs
[i
].propid
);
196 type
= get_type( idofs
[i
].propid
);
197 if( type
== VT_EMPTY
)
199 ERR( "propid %lu has unknown type\n", idofs
[i
].propid
);
203 propdata
= (struct property_data
*)&data
[ idofs
[i
].dwOffset
];
205 /* check we don't run off the end of the data */
206 size
= sz
- idofs
[i
].dwOffset
- sizeof(DWORD
);
207 if( sizeof(DWORD
) > size
||
208 ( propdata
->type
== VT_FILETIME
&& sizeof(FILETIME
) > size
) ||
209 ( propdata
->type
== VT_LPSTR
&& (propdata
->u
.str
.len
+ sizeof(DWORD
)) > size
) )
211 ERR("not enough data\n");
215 property
.vt
= propdata
->type
;
216 if( propdata
->type
== VT_LPSTR
)
218 char *str
= malloc( propdata
->u
.str
.len
);
219 memcpy( str
, propdata
->u
.str
.str
, propdata
->u
.str
.len
);
220 str
[ propdata
->u
.str
.len
- 1 ] = 0;
221 property
.pszVal
= str
;
223 else if( propdata
->type
== VT_FILETIME
)
224 property
.filetime
= propdata
->u
.ft
;
225 else if( propdata
->type
== VT_I2
)
226 property
.iVal
= propdata
->u
.i2
;
227 else if( propdata
->type
== VT_I4
)
228 property
.lVal
= propdata
->u
.i4
;
230 /* check the type is the same as we expect */
231 if( type
!= propdata
->type
)
233 propvar_changetype(&changed
, &property
, type
);
239 prop
[ idofs
[i
].propid
] = *ptr
;
243 static UINT
load_summary_info( MSISUMMARYINFO
*si
, IStream
*stm
)
245 struct property_set_header set_hdr
;
246 struct format_id_offset format_hdr
;
247 struct property_section_header section_hdr
;
253 TRACE("%p %p\n", si
, stm
);
255 /* read the header */
257 r
= IStream_Read( stm
, &set_hdr
, sz
, &count
);
258 if( FAILED(r
) || count
!= sz
)
259 return ERROR_FUNCTION_FAILED
;
261 if( set_hdr
.wByteOrder
!= 0xfffe )
263 ERR("property set not big-endian %04X\n", set_hdr
.wByteOrder
);
264 return ERROR_FUNCTION_FAILED
;
267 sz
= sizeof format_hdr
;
268 r
= IStream_Read( stm
, &format_hdr
, sz
, &count
);
269 if( FAILED(r
) || count
!= sz
)
270 return ERROR_FUNCTION_FAILED
;
272 /* check the format id is correct */
273 if( !IsEqualGUID( &FMTID_SummaryInformation
, &format_hdr
.fmtid
) )
274 return ERROR_FUNCTION_FAILED
;
276 /* seek to the location of the section */
277 ofs
.QuadPart
= format_hdr
.dwOffset
;
278 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, NULL
);
280 return ERROR_FUNCTION_FAILED
;
282 /* read the section itself */
284 r
= IStream_Read( stm
, §ion_hdr
, sz
, &count
);
285 if( FAILED(r
) || count
!= sz
)
286 return ERROR_FUNCTION_FAILED
;
288 if( section_hdr
.cProperties
> MSI_MAX_PROPS
)
290 ERR( "too many properties %lu\n", section_hdr
.cProperties
);
291 return ERROR_FUNCTION_FAILED
;
294 data
= malloc( section_hdr
.cbSection
);
296 return ERROR_FUNCTION_FAILED
;
298 memcpy( data
, §ion_hdr
, SECT_HDR_SIZE
);
300 /* read all the data in one go */
301 sz
= section_hdr
.cbSection
- SECT_HDR_SIZE
;
302 r
= IStream_Read( stm
, &data
[ SECT_HDR_SIZE
], sz
, &count
);
303 if( SUCCEEDED(r
) && count
== sz
)
304 read_properties_from_data( si
->property
, data
, sz
+ SECT_HDR_SIZE
);
306 ERR( "failed to read properties %lu %lu\n", count
, sz
);
309 return ERROR_SUCCESS
;
312 static DWORD
write_dword( LPBYTE data
, DWORD ofs
, DWORD val
)
316 data
[ofs
++] = val
&0xff;
317 data
[ofs
++] = (val
>>8)&0xff;
318 data
[ofs
++] = (val
>>16)&0xff;
319 data
[ofs
++] = (val
>>24)&0xff;
324 static DWORD
write_filetime( LPBYTE data
, DWORD ofs
, const FILETIME
*ft
)
326 write_dword( data
, ofs
, ft
->dwLowDateTime
);
327 write_dword( data
, ofs
+ 4, ft
->dwHighDateTime
);
331 static DWORD
write_string( LPBYTE data
, DWORD ofs
, LPCSTR str
)
333 DWORD len
= lstrlenA( str
) + 1;
334 write_dword( data
, ofs
, len
);
336 memcpy( &data
[ofs
+ 4], str
, len
);
337 return (7 + len
) & ~3;
340 static UINT
write_property_to_data( const PROPVARIANT
*prop
, LPBYTE data
)
344 if( prop
->vt
== VT_EMPTY
)
348 sz
+= write_dword( data
, sz
, prop
->vt
);
352 sz
+= write_dword( data
, sz
, prop
->iVal
);
355 sz
+= write_dword( data
, sz
, prop
->lVal
);
358 sz
+= write_filetime( data
, sz
, &prop
->filetime
);
361 sz
+= write_string( data
, sz
, prop
->pszVal
);
367 static UINT
save_summary_info( const MSISUMMARYINFO
* si
, IStream
*stm
)
369 UINT ret
= ERROR_FUNCTION_FAILED
;
370 struct property_set_header set_hdr
;
371 struct format_id_offset format_hdr
;
372 struct property_section_header section_hdr
;
373 struct property_id_offset idofs
[MSI_MAX_PROPS
];
379 /* write the header */
381 memset( &set_hdr
, 0, sz
);
382 set_hdr
.wByteOrder
= 0xfffe;
384 set_hdr
.dwOSVer
= 0x00020005; /* build 5, platform id 2 */
385 /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */
386 set_hdr
.reserved
= 1;
387 r
= IStream_Write( stm
, &set_hdr
, sz
, &count
);
388 if( FAILED(r
) || count
!= sz
)
391 /* write the format header */
392 sz
= sizeof format_hdr
;
393 format_hdr
.fmtid
= FMTID_SummaryInformation
;
394 format_hdr
.dwOffset
= sizeof format_hdr
+ sizeof set_hdr
;
395 r
= IStream_Write( stm
, &format_hdr
, sz
, &count
);
396 if( FAILED(r
) || count
!= sz
)
399 /* add up how much space the data will take and calculate the offsets */
400 section_hdr
.cbSection
= sizeof section_hdr
;
401 section_hdr
.cbSection
+= (get_property_count( si
->property
) * sizeof idofs
[0]);
402 section_hdr
.cProperties
= 0;
403 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
405 sz
= write_property_to_data( &si
->property
[i
], NULL
);
408 idofs
[ section_hdr
.cProperties
].propid
= i
;
409 idofs
[ section_hdr
.cProperties
].dwOffset
= section_hdr
.cbSection
;
410 section_hdr
.cProperties
++;
411 section_hdr
.cbSection
+= sz
;
414 data
= calloc( 1, section_hdr
.cbSection
);
417 memcpy( &data
[sz
], §ion_hdr
, sizeof section_hdr
);
418 sz
+= sizeof section_hdr
;
420 memcpy( &data
[sz
], idofs
, section_hdr
.cProperties
* sizeof idofs
[0] );
421 sz
+= section_hdr
.cProperties
* sizeof idofs
[0];
423 /* write out the data */
424 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
425 sz
+= write_property_to_data( &si
->property
[i
], &data
[sz
] );
427 r
= IStream_Write( stm
, data
, sz
, &count
);
429 if( FAILED(r
) || count
!= sz
)
432 return ERROR_SUCCESS
;
435 static MSISUMMARYINFO
*create_suminfo( IStorage
*stg
, UINT update_count
)
439 if (!(si
= alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO
, sizeof(MSISUMMARYINFO
), MSI_CloseSummaryInfo
)))
442 si
->update_count
= update_count
;
443 IStorage_AddRef( stg
);
449 UINT
msi_get_suminfo( IStorage
*stg
, UINT uiUpdateCount
, MSISUMMARYINFO
**ret
)
456 TRACE("%p, %u\n", stg
, uiUpdateCount
);
458 if (!(si
= create_suminfo( stg
, uiUpdateCount
))) return ERROR_OUTOFMEMORY
;
460 hr
= IStorage_OpenStream( si
->storage
, L
"\5SummaryInformation", 0, STGM_READ
|STGM_SHARE_EXCLUSIVE
, 0, &stm
);
463 msiobj_release( &si
->hdr
);
464 return ERROR_FUNCTION_FAILED
;
467 r
= load_summary_info( si
, stm
);
468 IStream_Release( stm
);
469 if (r
!= ERROR_SUCCESS
)
471 msiobj_release( &si
->hdr
);
476 return ERROR_SUCCESS
;
479 UINT
msi_get_db_suminfo( MSIDATABASE
*db
, UINT uiUpdateCount
, MSISUMMARYINFO
**ret
)
485 if (!(si
= create_suminfo( db
->storage
, uiUpdateCount
))) return ERROR_OUTOFMEMORY
;
487 r
= msi_get_stream( db
, L
"\5SummaryInformation", &stm
);
488 if (r
!= ERROR_SUCCESS
)
490 msiobj_release( &si
->hdr
);
494 r
= load_summary_info( si
, stm
);
495 IStream_Release( stm
);
496 if (r
!= ERROR_SUCCESS
)
498 msiobj_release( &si
->hdr
);
503 return ERROR_SUCCESS
;
506 UINT WINAPI
MsiGetSummaryInformationW( MSIHANDLE hDatabase
, const WCHAR
*szDatabase
, UINT uiUpdateCount
,
513 TRACE( "%lu, %s, %u, %p\n", hDatabase
, debugstr_w(szDatabase
), uiUpdateCount
, pHandle
);
516 return ERROR_INVALID_PARAMETER
;
518 if( szDatabase
&& szDatabase
[0] )
520 LPCWSTR persist
= uiUpdateCount
? MSIDBOPEN_TRANSACT
: MSIDBOPEN_READONLY
;
522 ret
= MSI_OpenDatabaseW( szDatabase
, persist
, &db
);
523 if( ret
!= ERROR_SUCCESS
)
528 db
= msihandle2msiinfo( hDatabase
, MSIHANDLETYPE_DATABASE
);
531 MSIHANDLE remote
, remote_suminfo
;
533 if (!(remote
= msi_get_remote(hDatabase
)))
534 return ERROR_INVALID_HANDLE
;
538 ret
= remote_DatabaseGetSummaryInformation(remote
, uiUpdateCount
, &remote_suminfo
);
542 ret
= GetExceptionCode();
547 *pHandle
= alloc_msi_remote_handle(remote_suminfo
);
553 ret
= msi_get_suminfo( db
->storage
, uiUpdateCount
, &si
);
554 if (ret
!= ERROR_SUCCESS
)
555 ret
= msi_get_db_suminfo( db
, uiUpdateCount
, &si
);
556 if (ret
!= ERROR_SUCCESS
)
558 if ((si
= create_suminfo( db
->storage
, uiUpdateCount
)))
562 if (ret
== ERROR_SUCCESS
)
564 *pHandle
= alloc_msihandle( &si
->hdr
);
568 ret
= ERROR_NOT_ENOUGH_MEMORY
;
569 msiobj_release( &si
->hdr
);
572 msiobj_release( &db
->hdr
);
576 UINT WINAPI
MsiGetSummaryInformationA( MSIHANDLE hDatabase
, const char *szDatabase
, UINT uiUpdateCount
,
579 WCHAR
*szwDatabase
= NULL
;
582 TRACE( "%lu, %s, %u, %p\n", hDatabase
, debugstr_a(szDatabase
), uiUpdateCount
, pHandle
);
586 szwDatabase
= strdupAtoW( szDatabase
);
588 return ERROR_FUNCTION_FAILED
;
591 ret
= MsiGetSummaryInformationW(hDatabase
, szwDatabase
, uiUpdateCount
, pHandle
);
598 UINT WINAPI
MsiSummaryInfoGetPropertyCount( MSIHANDLE hSummaryInfo
, UINT
*pCount
)
602 TRACE( "%lu, %p\n", hSummaryInfo
, pCount
);
604 si
= msihandle2msiinfo( hSummaryInfo
, MSIHANDLETYPE_SUMMARYINFO
);
610 if (!(remote
= msi_get_remote( hSummaryInfo
)))
611 return ERROR_INVALID_HANDLE
;
615 ret
= remote_SummaryInfoGetPropertyCount( remote
, pCount
);
619 ret
= GetExceptionCode();
627 *pCount
= get_property_count( si
->property
);
628 msiobj_release( &si
->hdr
);
630 return ERROR_SUCCESS
;
633 static UINT
get_prop( MSISUMMARYINFO
*si
, UINT uiProperty
, UINT
*puiDataType
, INT
*piValue
,
634 FILETIME
*pftValue
, awstring
*str
, DWORD
*pcchValueBuf
)
637 UINT ret
= ERROR_SUCCESS
;
639 prop
= &si
->property
[uiProperty
];
642 *puiDataType
= prop
->vt
;
648 *piValue
= prop
->iVal
;
652 *piValue
= prop
->lVal
;
661 len
= MultiByteToWideChar( CP_ACP
, 0, prop
->pszVal
, -1, NULL
, 0 ) - 1;
662 MultiByteToWideChar( CP_ACP
, 0, prop
->pszVal
, -1, str
->str
.w
, *pcchValueBuf
);
666 len
= lstrlenA( prop
->pszVal
);
668 lstrcpynA(str
->str
.a
, prop
->pszVal
, *pcchValueBuf
);
670 if (len
>= *pcchValueBuf
)
671 ret
= ERROR_MORE_DATA
;
677 *pftValue
= prop
->filetime
;
682 FIXME("Unknown property variant type\n");
688 LPWSTR
msi_suminfo_dup_string( MSISUMMARYINFO
*si
, UINT uiProperty
)
692 if ( uiProperty
>= MSI_MAX_PROPS
)
694 prop
= &si
->property
[uiProperty
];
695 if( prop
->vt
!= VT_LPSTR
)
697 return strdupAtoW( prop
->pszVal
);
700 INT
msi_suminfo_get_int32( MSISUMMARYINFO
*si
, UINT uiProperty
)
704 if ( uiProperty
>= MSI_MAX_PROPS
)
706 prop
= &si
->property
[uiProperty
];
707 if( prop
->vt
!= VT_I4
)
712 LPWSTR
msi_get_suminfo_product( IStorage
*stg
)
718 r
= msi_get_suminfo( stg
, 0, &si
);
719 if (r
!= ERROR_SUCCESS
)
721 ERR("no summary information!\n");
724 prod
= msi_suminfo_dup_string( si
, PID_REVNUMBER
);
725 msiobj_release( &si
->hdr
);
729 UINT WINAPI
MsiSummaryInfoGetPropertyA( MSIHANDLE handle
, UINT uiProperty
, UINT
*puiDataType
, INT
*piValue
,
730 FILETIME
*pftValue
, char *szValueBuf
, DWORD
*pcchValueBuf
)
736 TRACE( "%lu, %u, %p, %p, %p, %p, %p\n", handle
, uiProperty
, puiDataType
, piValue
, pftValue
, szValueBuf
,
739 if (uiProperty
>= MSI_MAX_PROPS
)
741 if (puiDataType
) *puiDataType
= VT_EMPTY
;
742 return ERROR_UNKNOWN_PROPERTY
;
745 if (!(si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
)))
750 if (!(remote
= msi_get_remote( handle
)))
751 return ERROR_INVALID_HANDLE
;
755 r
= remote_SummaryInfoGetProperty( remote
, uiProperty
, puiDataType
, piValue
, pftValue
, &buf
);
759 r
= GetExceptionCode();
765 r
= msi_strncpyWtoA( buf
, -1, szValueBuf
, pcchValueBuf
, TRUE
);
768 midl_user_free( buf
);
773 str
.str
.a
= szValueBuf
;
775 r
= get_prop( si
, uiProperty
, puiDataType
, piValue
, pftValue
, &str
, pcchValueBuf
);
776 msiobj_release( &si
->hdr
);
780 UINT WINAPI
MsiSummaryInfoGetPropertyW( MSIHANDLE handle
, UINT uiProperty
, UINT
*puiDataType
, INT
*piValue
,
781 FILETIME
*pftValue
, WCHAR
*szValueBuf
, DWORD
*pcchValueBuf
)
787 TRACE( "%lu, %u, %p, %p, %p, %p, %p\n", handle
, uiProperty
, puiDataType
, piValue
, pftValue
, szValueBuf
,
790 if (uiProperty
>= MSI_MAX_PROPS
)
792 if (puiDataType
) *puiDataType
= VT_EMPTY
;
793 return ERROR_UNKNOWN_PROPERTY
;
796 if (!(si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
)))
801 if (!(remote
= msi_get_remote( handle
)))
802 return ERROR_INVALID_HANDLE
;
806 r
= remote_SummaryInfoGetProperty( remote
, uiProperty
, puiDataType
, piValue
, pftValue
, &buf
);
810 r
= GetExceptionCode();
815 r
= msi_strncpyW( buf
, -1, szValueBuf
, pcchValueBuf
);
817 midl_user_free( buf
);
822 str
.str
.w
= szValueBuf
;
824 r
= get_prop( si
, uiProperty
, puiDataType
, piValue
, pftValue
, &str
, pcchValueBuf
);
825 msiobj_release( &si
->hdr
);
829 static UINT
set_prop( MSISUMMARYINFO
*si
, UINT uiProperty
, UINT type
,
830 INT iValue
, FILETIME
*pftValue
, awcstring
*str
)
835 TRACE("%p, %u, %u, %d, %p, %p\n", si
, uiProperty
, type
, iValue
, pftValue
, str
);
837 prop
= &si
->property
[uiProperty
];
839 if( prop
->vt
== VT_EMPTY
)
841 if( !si
->update_count
)
842 return ERROR_FUNCTION_FAILED
;
846 else if( prop
->vt
!= type
)
847 return ERROR_SUCCESS
;
860 prop
->filetime
= *pftValue
;
865 len
= WideCharToMultiByte( CP_ACP
, 0, str
->str
.w
, -1,
866 NULL
, 0, NULL
, NULL
);
867 prop
->pszVal
= malloc( len
);
868 WideCharToMultiByte( CP_ACP
, 0, str
->str
.w
, -1,
869 prop
->pszVal
, len
, NULL
, NULL
);
873 len
= lstrlenA( str
->str
.a
) + 1;
874 prop
->pszVal
= malloc( len
);
875 lstrcpyA( prop
->pszVal
, str
->str
.a
);
880 return ERROR_SUCCESS
;
883 static UINT
suminfo_set_prop( MSISUMMARYINFO
*si
, UINT uiProperty
, UINT uiDataType
, INT iValue
, FILETIME
*pftValue
,
886 UINT type
= get_type( uiProperty
);
887 if( type
== VT_EMPTY
|| type
!= uiDataType
)
888 return ERROR_DATATYPE_MISMATCH
;
890 if( uiDataType
== VT_LPSTR
&& !str
->str
.a
)
891 return ERROR_INVALID_PARAMETER
;
893 if( uiDataType
== VT_FILETIME
&& !pftValue
)
894 return ERROR_INVALID_PARAMETER
;
896 return set_prop( si
, uiProperty
, type
, iValue
, pftValue
, str
);
899 UINT WINAPI
MsiSummaryInfoSetPropertyW( MSIHANDLE handle
, UINT uiProperty
, UINT uiDataType
, INT iValue
,
900 FILETIME
*pftValue
, const WCHAR
*szValue
)
906 TRACE( "%lu, %u, %u, %d, %p, %s\n", handle
, uiProperty
, uiDataType
, iValue
, pftValue
, debugstr_w(szValue
) );
908 if (!(si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
)))
912 if ((remote
= msi_get_remote( handle
)))
914 WARN("MsiSummaryInfoSetProperty not allowed during a custom action!\n");
915 return ERROR_FUNCTION_FAILED
;
918 return ERROR_INVALID_HANDLE
;
924 ret
= suminfo_set_prop( si
, uiProperty
, uiDataType
, iValue
, pftValue
, &str
);
925 msiobj_release( &si
->hdr
);
929 UINT WINAPI
MsiSummaryInfoSetPropertyA( MSIHANDLE handle
, UINT uiProperty
, UINT uiDataType
, INT iValue
,
930 FILETIME
*pftValue
, const char *szValue
)
936 TRACE( "%lu, %u, %u, %d, %p, %s\n", handle
, uiProperty
, uiDataType
, iValue
, pftValue
, debugstr_a(szValue
) );
938 if (!(si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
)))
942 if ((remote
= msi_get_remote( handle
)))
944 WARN("MsiSummaryInfoSetProperty not allowed during a custom action!\n");
945 return ERROR_FUNCTION_FAILED
;
948 return ERROR_INVALID_HANDLE
;
954 ret
= suminfo_set_prop( si
, uiProperty
, uiDataType
, iValue
, pftValue
, &str
);
955 msiobj_release( &si
->hdr
);
959 static UINT
suminfo_persist( MSISUMMARYINFO
*si
)
961 UINT ret
= ERROR_FUNCTION_FAILED
;
966 grfMode
= STGM_CREATE
| STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
;
967 r
= IStorage_CreateStream( si
->storage
, L
"\5SummaryInformation", grfMode
, 0, 0, &stm
);
970 ret
= save_summary_info( si
, stm
);
971 IStream_Release( stm
);
976 static void parse_filetime( LPCWSTR str
, FILETIME
*ft
)
979 const WCHAR
*p
= str
;
982 memset( <
, 0, sizeof(lt
) );
984 /* YYYY/MM/DD hh:mm:ss */
986 while (iswspace( *p
)) p
++;
988 lt
.wYear
= wcstol( p
, &end
, 10 );
989 if (*end
!= '/') return;
992 lt
.wMonth
= wcstol( p
, &end
, 10 );
993 if (*end
!= '/') return;
996 lt
.wDay
= wcstol( p
, &end
, 10 );
997 if (*end
!= ' ') return;
1000 while (iswspace( *p
)) p
++;
1002 lt
.wHour
= wcstol( p
, &end
, 10 );
1003 if (*end
!= ':') return;
1006 lt
.wMinute
= wcstol( p
, &end
, 10 );
1007 if (*end
!= ':') return;
1010 lt
.wSecond
= wcstol( p
, &end
, 10 );
1012 TzSpecificLocalTimeToSystemTime( NULL
, <
, &utc
);
1013 SystemTimeToFileTime( &utc
, ft
);
1016 static UINT
parse_prop( LPCWSTR prop
, LPCWSTR value
, UINT
*pid
, INT
*int_value
,
1017 FILETIME
*ft_value
, awcstring
*str_value
)
1019 *pid
= wcstol( prop
, NULL
, 10 );
1027 *int_value
= wcstol( value
, NULL
, 10 );
1030 case PID_LASTPRINTED
:
1031 case PID_CREATE_DTM
:
1032 case PID_LASTSAVE_DTM
:
1033 parse_filetime( value
, ft_value
);
1041 case PID_LASTAUTHOR
:
1045 str_value
->str
.w
= value
;
1046 str_value
->unicode
= TRUE
;
1050 WARN("unhandled prop id %u\n", *pid
);
1051 return ERROR_FUNCTION_FAILED
;
1054 return ERROR_SUCCESS
;
1057 UINT
msi_add_suminfo( MSIDATABASE
*db
, LPWSTR
**records
, int num_records
, int num_columns
)
1063 r
= msi_get_suminfo( db
->storage
, num_records
* (num_columns
/ 2), &si
);
1064 if (r
!= ERROR_SUCCESS
)
1066 if (!(si
= create_suminfo( db
->storage
, num_records
* (num_columns
/ 2) )))
1067 return ERROR_OUTOFMEMORY
;
1071 for (i
= 0; i
< num_records
; i
++)
1073 for (j
= 0; j
< num_columns
; j
+= 2)
1078 awcstring str_value
;
1080 r
= parse_prop( records
[i
][j
], records
[i
][j
+ 1], &pid
, &int_value
, &ft_value
, &str_value
);
1081 if (r
!= ERROR_SUCCESS
)
1084 r
= set_prop( si
, pid
, get_type(pid
), int_value
, &ft_value
, &str_value
);
1085 if (r
!= ERROR_SUCCESS
)
1091 if (r
== ERROR_SUCCESS
)
1092 r
= suminfo_persist( si
);
1094 msiobj_release( &si
->hdr
);
1098 static UINT
save_prop( MSISUMMARYINFO
*si
, HANDLE handle
, UINT row
)
1100 static const char fmt_systemtime
[] = "%04u/%02u/%02u %02u:%02u:%02u";
1101 char data
[36]; /* largest string: YYYY/MM/DD hh:mm:ss */
1102 static const char fmt_begin
[] = "%u\t";
1103 static const char data_end
[] = "\r\n";
1104 static const char fmt_int
[] = "%u";
1106 SYSTEMTIME system_time
;
1112 str
.unicode
= FALSE
;
1115 r
= get_prop( si
, row
, &data_type
, &int_value
, &file_time
, &str
, &len
);
1116 if (r
!= ERROR_SUCCESS
&& r
!= ERROR_MORE_DATA
)
1118 if (data_type
== VT_EMPTY
)
1119 return ERROR_SUCCESS
; /* property not set */
1120 sz
= sprintf( data
, fmt_begin
, row
);
1121 if (!WriteFile( handle
, data
, sz
, &sz
, NULL
))
1122 return ERROR_WRITE_FAULT
;
1128 sz
= sprintf( data
, fmt_int
, int_value
);
1129 if (!WriteFile( handle
, data
, sz
, &sz
, NULL
))
1130 return ERROR_WRITE_FAULT
;
1134 if (!(str
.str
.a
= malloc( len
)))
1135 return ERROR_OUTOFMEMORY
;
1136 r
= get_prop( si
, row
, NULL
, NULL
, NULL
, &str
, &len
);
1137 if (r
!= ERROR_SUCCESS
)
1143 if (!WriteFile( handle
, str
.str
.a
, sz
, &sz
, NULL
))
1146 return ERROR_WRITE_FAULT
;
1151 if (!FileTimeToSystemTime( &file_time
, &system_time
))
1152 return ERROR_FUNCTION_FAILED
;
1153 sz
= sprintf( data
, fmt_systemtime
, system_time
.wYear
, system_time
.wMonth
,
1154 system_time
.wDay
, system_time
.wHour
, system_time
.wMinute
,
1155 system_time
.wSecond
);
1156 if (!WriteFile( handle
, data
, sz
, &sz
, NULL
))
1157 return ERROR_WRITE_FAULT
;
1160 /* cannot reach here, property not set */
1163 FIXME( "Unknown property variant type\n" );
1164 return ERROR_FUNCTION_FAILED
;
1167 sz
= ARRAY_SIZE(data_end
) - 1;
1168 if (!WriteFile( handle
, data_end
, sz
, &sz
, NULL
))
1169 return ERROR_WRITE_FAULT
;
1171 return ERROR_SUCCESS
;
1174 UINT
msi_export_suminfo( MSIDATABASE
*db
, HANDLE handle
)
1176 UINT i
, r
, num_rows
;
1179 r
= msi_get_suminfo( db
->storage
, 0, &si
);
1180 if (r
!= ERROR_SUCCESS
)
1181 r
= msi_get_db_suminfo( db
, 0, &si
);
1182 if (r
!= ERROR_SUCCESS
)
1185 num_rows
= get_property_count( si
->property
);
1188 msiobj_release( &si
->hdr
);
1189 return ERROR_FUNCTION_FAILED
;
1192 for (i
= 0; i
< num_rows
; i
++)
1194 r
= save_prop( si
, handle
, i
);
1195 if (r
!= ERROR_SUCCESS
)
1197 msiobj_release( &si
->hdr
);
1202 msiobj_release( &si
->hdr
);
1203 return ERROR_SUCCESS
;
1206 UINT WINAPI
MsiSummaryInfoPersist( MSIHANDLE handle
)
1211 TRACE( "%lu\n", handle
);
1213 si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
);
1215 return ERROR_INVALID_HANDLE
;
1217 ret
= suminfo_persist( si
);
1219 msiobj_release( &si
->hdr
);
1223 UINT WINAPI
MsiCreateTransformSummaryInfoA( MSIHANDLE db
, MSIHANDLE db_ref
, const char *transform
, int error
,
1227 WCHAR
*transformW
= NULL
;
1229 TRACE( "%lu, %lu, %s, %d, %d\n", db
, db_ref
, debugstr_a(transform
), error
, validation
);
1231 if (transform
&& !(transformW
= strdupAtoW( transform
)))
1232 return ERROR_OUTOFMEMORY
;
1234 r
= MsiCreateTransformSummaryInfoW( db
, db_ref
, transformW
, error
, validation
);
1239 UINT WINAPI
MsiCreateTransformSummaryInfoW( MSIHANDLE db
, MSIHANDLE db_ref
, const WCHAR
*transform
, int error
,
1242 FIXME( "%lu, %lu, %s, %d, %d\n", db
, db_ref
, debugstr_w(transform
), error
, validation
);
1243 return ERROR_FUNCTION_FAILED
;
1246 UINT
msi_load_suminfo_properties( MSIPACKAGE
*package
)
1249 WCHAR
*package_code
;
1255 r
= msi_get_suminfo( package
->db
->storage
, 0, &si
);
1256 if (r
!= ERROR_SUCCESS
)
1258 r
= msi_get_db_suminfo( package
->db
, 0, &si
);
1259 if (r
!= ERROR_SUCCESS
)
1261 ERR("Unable to open summary information stream %u\n", r
);
1269 r
= get_prop( si
, PID_REVNUMBER
, NULL
, NULL
, NULL
, &str
, &len
);
1270 if (r
!= ERROR_MORE_DATA
)
1272 WARN("Unable to query revision number %u\n", r
);
1273 msiobj_release( &si
->hdr
);
1274 return ERROR_FUNCTION_FAILED
;
1278 if (!(package_code
= malloc( len
* sizeof(WCHAR
) ))) return ERROR_OUTOFMEMORY
;
1279 str
.str
.w
= package_code
;
1281 r
= get_prop( si
, PID_REVNUMBER
, NULL
, NULL
, NULL
, &str
, &len
);
1282 if (r
!= ERROR_SUCCESS
)
1284 free( package_code
);
1285 msiobj_release( &si
->hdr
);
1289 r
= msi_set_property( package
->db
, L
"PackageCode", package_code
, len
);
1290 free( package_code
);
1293 get_prop( si
, PID_WORDCOUNT
, NULL
, &count
, NULL
, NULL
, NULL
);
1294 package
->WordCount
= count
;
1296 msiobj_release( &si
->hdr
);
1300 UINT __cdecl
s_remote_SummaryInfoGetPropertyCount( MSIHANDLE suminfo
, UINT
*count
)
1302 return MsiSummaryInfoGetPropertyCount( suminfo
, count
);
1305 UINT __cdecl
s_remote_SummaryInfoGetProperty( MSIHANDLE suminfo
, UINT property
, UINT
*type
,
1306 INT
*value
, FILETIME
*ft
, LPWSTR
*buf
)
1312 r
= MsiSummaryInfoGetPropertyW( suminfo
, property
, type
, value
, ft
, empty
, &size
);
1313 if (r
== ERROR_MORE_DATA
)
1316 *buf
= midl_user_allocate( size
* sizeof(WCHAR
) );
1317 if (!*buf
) return ERROR_OUTOFMEMORY
;
1318 r
= MsiSummaryInfoGetPropertyW( suminfo
, property
, type
, value
, ft
, *buf
, &size
);