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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #define NONAMELESSUNION
31 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
40 #define MSI_MAX_PROPS 20
60 } PROPERTYSECTIONHEADER
;
82 #define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER))
92 typedef struct tagMSISUMMARYINFO
97 PROPVARIANT property
[MSI_MAX_PROPS
];
100 static const WCHAR szSumInfo
[] = { 5 ,'S','u','m','m','a','r','y',
101 'I','n','f','o','r','m','a','t','i','o','n',0 };
103 static void free_prop( PROPVARIANT
*prop
)
105 if (prop
->vt
== VT_LPSTR
)
106 HeapFree( GetProcessHeap(), 0, prop
->u
.pszVal
);
110 static void MSI_CloseSummaryInfo( MSIOBJECTHDR
*arg
)
112 MSISUMMARYINFO
*si
= (MSISUMMARYINFO
*) arg
;
115 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
116 free_prop( &si
->property
[i
] );
117 msiobj_release( &si
->db
->hdr
);
120 static UINT
get_type( UINT uiProperty
)
138 case PID_LASTPRINTED
:
140 case PID_LASTSAVE_DTM
:
152 static UINT
get_property_count( PROPVARIANT
*property
)
158 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
159 if( property
[i
].vt
!= VT_EMPTY
)
164 /* FIXME: doesn't deal with endian conversion */
165 static void read_properties_from_data( PROPVARIANT
*prop
, LPBYTE data
, DWORD sz
)
170 PROPERTY_DATA
*propdata
;
171 PROPVARIANT
*property
;
172 PROPERTYIDOFFSET
*idofs
;
173 PROPERTYSECTIONHEADER
*section_hdr
;
175 section_hdr
= (PROPERTYSECTIONHEADER
*) &data
[0];
176 idofs
= (PROPERTYIDOFFSET
*) &data
[SECT_HDR_SIZE
];
178 /* now set all the properties */
179 for( i
= 0; i
< section_hdr
->cProperties
; i
++ )
181 type
= get_type( idofs
[i
].propid
);
182 if( type
== VT_EMPTY
)
184 ERR("propid %ld has unknown type\n", idofs
[i
].propid
);
188 propdata
= (PROPERTY_DATA
*) &data
[ idofs
[i
].dwOffset
];
190 /* check the type is the same as we expect */
191 if( type
!= propdata
->type
)
193 ERR("wrong type %d != %ld\n", type
, propdata
->type
);
197 /* check we don't run off the end of the data */
198 size
= sz
- idofs
[i
].dwOffset
- sizeof(DWORD
);
199 if( sizeof(DWORD
) > size
||
200 ( type
== VT_FILETIME
&& sizeof(FILETIME
) > size
) ||
201 ( type
== VT_LPSTR
&& (propdata
->u
.str
.len
+ sizeof(DWORD
)) > size
) )
203 ERR("not enough data\n");
207 if( idofs
[i
].propid
>= MSI_MAX_PROPS
)
209 ERR("Unknown property ID %ld\n", idofs
[i
].propid
);
213 property
= &prop
[ idofs
[i
].propid
];
216 if( type
== VT_LPSTR
)
218 LPSTR str
= HeapAlloc( GetProcessHeap(), 0, 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
->u
.pszVal
= str
;
223 else if( type
== VT_FILETIME
)
224 property
->u
.filetime
= propdata
->u
.ft
;
225 else if( type
== VT_I2
)
226 property
->u
.iVal
= propdata
->u
.i2
;
227 else if( type
== VT_I4
)
228 property
->u
.lVal
= propdata
->u
.i4
;
232 static UINT
load_summary_info( MSISUMMARYINFO
*si
, IStream
*stm
)
234 UINT ret
= ERROR_FUNCTION_FAILED
;
235 PROPERTYSETHEADER set_hdr
;
236 FORMATIDOFFSET format_hdr
;
237 PROPERTYSECTIONHEADER section_hdr
;
243 TRACE("%p %p\n", si
, stm
);
245 /* read the header */
247 r
= IStream_Read( stm
, &set_hdr
, sz
, &count
);
248 if( FAILED(r
) || count
!= sz
)
251 if( set_hdr
.wByteOrder
!= 0xfffe )
253 ERR("property set not big-endian %04X\n", set_hdr
.wByteOrder
);
257 sz
= sizeof format_hdr
;
258 r
= IStream_Read( stm
, &format_hdr
, sz
, &count
);
259 if( FAILED(r
) || count
!= sz
)
262 /* check the format id is correct */
263 if( !IsEqualGUID( &FMTID_SummaryInformation
, &format_hdr
.fmtid
) )
266 /* seek to the location of the section */
267 ofs
.QuadPart
= format_hdr
.dwOffset
;
268 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, NULL
);
272 /* read the section itself */
274 r
= IStream_Read( stm
, §ion_hdr
, sz
, &count
);
275 if( FAILED(r
) || count
!= sz
)
278 if( section_hdr
.cProperties
> MSI_MAX_PROPS
)
280 ERR("too many properties %ld\n", section_hdr
.cProperties
);
284 data
= HeapAlloc( GetProcessHeap(), 0, section_hdr
.cbSection
);
288 memcpy( data
, §ion_hdr
, SECT_HDR_SIZE
);
290 /* read all the data in one go */
291 sz
= section_hdr
.cbSection
- SECT_HDR_SIZE
;
292 r
= IStream_Read( stm
, &data
[ SECT_HDR_SIZE
], sz
, &count
);
293 if( SUCCEEDED(r
) && count
== sz
)
294 read_properties_from_data( si
->property
, data
, sz
+ SECT_HDR_SIZE
);
296 ERR("failed to read properties %ld %ld\n", count
, sz
);
298 HeapFree( GetProcessHeap(), 0, data
);
302 static DWORD
write_dword( LPBYTE data
, DWORD ofs
, DWORD val
)
306 data
[ofs
++] = val
&0xff;
307 data
[ofs
++] = (val
>>8)&0xff;
308 data
[ofs
++] = (val
>>16)&0xff;
309 data
[ofs
++] = (val
>>24)&0xff;
314 static DWORD
write_filetime( LPBYTE data
, DWORD ofs
, LPFILETIME ft
)
316 write_dword( data
, ofs
, ft
->dwLowDateTime
);
317 write_dword( data
, ofs
+ 4, ft
->dwHighDateTime
);
321 static DWORD
write_string( LPBYTE data
, DWORD ofs
, LPCSTR str
)
323 DWORD len
= lstrlenA( str
) + 1;
324 write_dword( data
, ofs
, len
);
326 lstrcpyA( &data
[ofs
+ 4], str
);
327 return (7 + len
) & ~3;
330 static UINT
write_property_to_data( PROPVARIANT
*prop
, LPBYTE data
)
334 if( prop
->vt
== VT_EMPTY
)
338 sz
+= write_dword( data
, sz
, prop
->vt
);
342 sz
+= write_dword( data
, sz
, prop
->u
.iVal
);
345 sz
+= write_dword( data
, sz
, prop
->u
.lVal
);
348 sz
+= write_filetime( data
, sz
, &prop
->u
.filetime
);
351 sz
+= write_string( data
, sz
, prop
->u
.pszVal
);
357 static UINT
save_summary_info( MSISUMMARYINFO
* si
, IStream
*stm
)
359 UINT ret
= ERROR_FUNCTION_FAILED
;
360 PROPERTYSETHEADER set_hdr
;
361 FORMATIDOFFSET format_hdr
;
362 PROPERTYSECTIONHEADER section_hdr
;
363 PROPERTYIDOFFSET idofs
[MSI_MAX_PROPS
];
369 /* write the header */
371 memset( &set_hdr
, 0, sz
);
372 set_hdr
.wByteOrder
= 0xfffe;
374 set_hdr
.dwOSVer
= 0x00020005; /* build 5, platform id 2 */
375 /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */
376 set_hdr
.reserved
= 1;
377 r
= IStream_Write( stm
, &set_hdr
, sz
, &count
);
378 if( FAILED(r
) || count
!= sz
)
381 /* write the format header */
382 sz
= sizeof format_hdr
;
383 memcpy( &format_hdr
.fmtid
, &FMTID_SummaryInformation
, sizeof (FMTID
) );
384 format_hdr
.dwOffset
= sizeof format_hdr
+ sizeof set_hdr
;
385 r
= IStream_Write( stm
, &format_hdr
, sz
, &count
);
386 if( FAILED(r
) || count
!= sz
)
389 /* add up how much space the data will take and calculate the offsets */
390 section_hdr
.cbSection
= sizeof section_hdr
;
391 section_hdr
.cbSection
+= (get_property_count( si
->property
) * sizeof idofs
[0]);
392 section_hdr
.cProperties
= 0;
394 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
396 sz
= write_property_to_data( &si
->property
[i
], NULL
);
399 idofs
[ section_hdr
.cProperties
].propid
= i
;
400 idofs
[ section_hdr
.cProperties
].dwOffset
= section_hdr
.cbSection
;
401 section_hdr
.cProperties
++;
402 section_hdr
.cbSection
+= sz
;
405 data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, section_hdr
.cbSection
);
408 memcpy( &data
[sz
], §ion_hdr
, sizeof section_hdr
);
409 sz
+= sizeof section_hdr
;
411 memcpy( &data
[sz
], idofs
, section_hdr
.cProperties
* sizeof idofs
[0] );
412 sz
+= section_hdr
.cProperties
* sizeof idofs
[0];
414 /* write out the data */
415 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
416 sz
+= write_property_to_data( &si
->property
[i
], &data
[sz
] );
418 r
= IStream_Write( stm
, data
, sz
, &count
);
419 HeapFree( GetProcessHeap(), 0, data
);
420 if( FAILED(r
) || count
!= sz
)
423 return ERROR_SUCCESS
;
426 UINT WINAPI
MsiGetSummaryInformationW( MSIHANDLE hDatabase
,
427 LPCWSTR szDatabase
, UINT uiUpdateCount
, MSIHANDLE
*pHandle
)
429 UINT ret
= ERROR_SUCCESS
;
437 TRACE("%ld %s %d %p\n", hDatabase
, debugstr_w(szDatabase
),
438 uiUpdateCount
, pHandle
);
441 return ERROR_INVALID_PARAMETER
;
447 res
= MSI_OpenDatabaseW(szDatabase
, NULL
, &db
);
448 if( res
!= ERROR_SUCCESS
)
453 db
= msihandle2msiinfo(hDatabase
, MSIHANDLETYPE_DATABASE
);
455 return ERROR_INVALID_PARAMETER
;
458 si
= alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO
,
459 sizeof (MSISUMMARYINFO
), MSI_CloseSummaryInfo
);
462 ret
= ERROR_FUNCTION_FAILED
;
466 msiobj_addref( &db
->hdr
);
468 memset( &si
->property
, 0, sizeof si
->property
);
469 si
->update_count
= uiUpdateCount
;
471 /* read the stream... if we fail, we'll start with an empty property set */
472 grfMode
= STGM_READ
| STGM_SHARE_EXCLUSIVE
;
473 r
= IStorage_OpenStream( si
->db
->storage
, szSumInfo
, 0, grfMode
, 0, &stm
);
476 load_summary_info( si
, stm
);
477 IStream_Release( stm
);
480 handle
= alloc_msihandle( &si
->hdr
);
484 ret
= ERROR_FUNCTION_FAILED
;
485 msiobj_release( &si
->hdr
);
489 msiobj_release( &db
->hdr
);
494 UINT WINAPI
MsiGetSummaryInformationA(MSIHANDLE hDatabase
,
495 LPCSTR szDatabase
, UINT uiUpdateCount
, MSIHANDLE
*pHandle
)
497 LPWSTR szwDatabase
= NULL
;
500 TRACE("%ld %s %d %p\n", hDatabase
, debugstr_a(szDatabase
),
501 uiUpdateCount
, pHandle
);
505 szwDatabase
= strdupAtoW( szDatabase
);
507 return ERROR_FUNCTION_FAILED
;
510 ret
= MsiGetSummaryInformationW(hDatabase
, szwDatabase
, uiUpdateCount
, pHandle
);
512 HeapFree( GetProcessHeap(), 0, szwDatabase
);
517 UINT WINAPI
MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo
, UINT
*pCount
)
521 TRACE("%ld %p\n",hSummaryInfo
, pCount
);
523 si
= msihandle2msiinfo( hSummaryInfo
, MSIHANDLETYPE_SUMMARYINFO
);
525 return ERROR_INVALID_HANDLE
;
528 *pCount
= get_property_count( si
->property
);
529 msiobj_release( &si
->hdr
);
531 return ERROR_SUCCESS
;
534 static UINT
get_prop( MSIHANDLE handle
, UINT uiProperty
, UINT
*puiDataType
,
535 INT
*piValue
, FILETIME
*pftValue
, awstring
*str
, DWORD
*pcchValueBuf
)
540 TRACE("%ld %d %p %p %p %p %p\n", handle
, uiProperty
, puiDataType
,
541 piValue
, pftValue
, str
, pcchValueBuf
);
543 si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
);
545 return ERROR_INVALID_HANDLE
;
547 prop
= &si
->property
[uiProperty
];
550 *puiDataType
= prop
->vt
;
556 *piValue
= prop
->u
.iVal
;
560 *piValue
= prop
->u
.lVal
;
569 len
= MultiByteToWideChar( CP_ACP
, 0, prop
->u
.pszVal
, -1,
570 str
->str
.w
, *pcchValueBuf
);
574 len
= lstrlenA( prop
->u
.pszVal
);
576 lstrcpynA(str
->str
.a
, prop
->u
.pszVal
, *pcchValueBuf
);
583 memcpy(pftValue
, &prop
->u
.filetime
, sizeof (FILETIME
) );
588 FIXME("Unknown property variant type\n");
591 msiobj_release( &si
->hdr
);
592 return ERROR_SUCCESS
;
595 UINT WINAPI
MsiSummaryInfoGetPropertyA(
596 MSIHANDLE handle
, UINT uiProperty
, UINT
*puiDataType
, INT
*piValue
,
597 FILETIME
*pftValue
, LPSTR szValueBuf
, DWORD
*pcchValueBuf
)
601 TRACE("%ld %d %p %p %p %p %p\n", handle
, uiProperty
, puiDataType
,
602 piValue
, pftValue
, szValueBuf
, pcchValueBuf
);
605 str
.str
.a
= szValueBuf
;
607 return get_prop( handle
, uiProperty
, puiDataType
, piValue
,
608 pftValue
, &str
, pcchValueBuf
);
611 UINT WINAPI
MsiSummaryInfoGetPropertyW(
612 MSIHANDLE handle
, UINT uiProperty
, UINT
*puiDataType
, INT
*piValue
,
613 FILETIME
*pftValue
, LPWSTR szValueBuf
, DWORD
*pcchValueBuf
)
617 TRACE("%ld %d %p %p %p %p %p\n", handle
, uiProperty
, puiDataType
,
618 piValue
, pftValue
, szValueBuf
, pcchValueBuf
);
621 str
.str
.w
= szValueBuf
;
623 return get_prop( handle
, uiProperty
, puiDataType
, piValue
,
624 pftValue
, &str
, pcchValueBuf
);
627 static UINT
set_prop( MSIHANDLE handle
, UINT uiProperty
, UINT uiDataType
,
628 INT iValue
, FILETIME
* pftValue
, awstring
*str
)
632 UINT type
, len
, ret
= ERROR_SUCCESS
;
634 TRACE("%ld %u %u %i %p %p\n", handle
, uiProperty
, uiDataType
,
635 iValue
, pftValue
, str
);
637 type
= get_type( uiProperty
);
638 if( type
== VT_EMPTY
|| type
!= uiDataType
)
639 return ERROR_DATATYPE_MISMATCH
;
641 if( uiDataType
== VT_LPSTR
&& !str
->str
.w
)
642 return ERROR_INVALID_PARAMETER
;
644 if( uiDataType
== VT_FILETIME
&& !pftValue
)
645 return ERROR_INVALID_PARAMETER
;
647 si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
);
649 return ERROR_INVALID_HANDLE
;
651 prop
= &si
->property
[uiProperty
];
653 if( prop
->vt
== VT_EMPTY
)
655 if( !si
->update_count
)
657 ret
= ERROR_FUNCTION_FAILED
;
662 else if( prop
->vt
!= type
)
670 prop
->u
.lVal
= iValue
;
673 prop
->u
.iVal
= iValue
;
676 memcpy( &prop
->u
.filetime
, pftValue
, sizeof prop
->u
.filetime
);
681 len
= WideCharToMultiByte( CP_ACP
, 0, str
->str
.w
, -1,
682 NULL
, 0, NULL
, NULL
);
683 prop
->u
.pszVal
= HeapAlloc( GetProcessHeap(), 0, len
);
684 WideCharToMultiByte( CP_ACP
, 0, str
->str
.w
, -1,
685 prop
->u
.pszVal
, len
, NULL
, NULL
);
689 len
= lstrlenA( str
->str
.a
) + 1;
690 prop
->u
.pszVal
= HeapAlloc( GetProcessHeap(), 0, len
);
691 lstrcpyA( prop
->u
.pszVal
, str
->str
.a
);
697 msiobj_release( &si
->hdr
);
701 UINT WINAPI
MsiSummaryInfoSetPropertyW( MSIHANDLE handle
, UINT uiProperty
,
702 UINT uiDataType
, INT iValue
, FILETIME
* pftValue
, LPWSTR szValue
)
706 TRACE("%ld %u %u %i %p %s\n", handle
, uiProperty
, uiDataType
,
707 iValue
, pftValue
, debugstr_w(szValue
) );
711 return set_prop( handle
, uiProperty
, uiDataType
, iValue
, pftValue
, &str
);
714 UINT WINAPI
MsiSummaryInfoSetPropertyA( MSIHANDLE handle
, UINT uiProperty
,
715 UINT uiDataType
, INT iValue
, FILETIME
* pftValue
, LPSTR szValue
)
719 TRACE("%ld %u %u %i %p %s\n", handle
, uiProperty
, uiDataType
,
720 iValue
, pftValue
, debugstr_a(szValue
) );
724 return set_prop( handle
, uiProperty
, uiDataType
, iValue
, pftValue
, &str
);
727 UINT WINAPI
MsiSummaryInfoPersist( MSIHANDLE handle
)
733 UINT ret
= ERROR_FUNCTION_FAILED
;
735 TRACE("%ld\n", handle
);
737 si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
);
739 return ERROR_INVALID_HANDLE
;
741 grfMode
= STGM_CREATE
| STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
;
742 r
= IStorage_CreateStream( si
->db
->storage
, szSumInfo
, grfMode
, 0, 0, &stm
);
745 ret
= save_summary_info( si
, stm
);
746 IStream_Release( stm
);
748 msiobj_release( &si
->hdr
);