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))
100 typedef struct tagMSISUMMARYINFO
105 PROPVARIANT property
[MSI_MAX_PROPS
];
108 static const WCHAR szSumInfo
[] = { 5 ,'S','u','m','m','a','r','y',
109 'I','n','f','o','r','m','a','t','i','o','n',0 };
111 static void free_prop( PROPVARIANT
*prop
)
113 if (prop
->vt
== VT_LPSTR
)
114 HeapFree( GetProcessHeap(), 0, prop
->u
.pszVal
);
118 static void MSI_CloseSummaryInfo( MSIOBJECTHDR
*arg
)
120 MSISUMMARYINFO
*si
= (MSISUMMARYINFO
*) arg
;
123 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
124 free_prop( &si
->property
[i
] );
125 msiobj_release( &si
->db
->hdr
);
128 static UINT
get_type( UINT uiProperty
)
146 case PID_LASTPRINTED
:
148 case PID_LASTSAVE_DTM
:
160 static UINT
get_property_count( PROPVARIANT
*property
)
166 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
167 if( property
[i
].vt
!= VT_EMPTY
)
172 /* FIXME: doesn't deal with endian conversion */
173 static void read_properties_from_data( PROPVARIANT
*prop
, LPBYTE data
, DWORD sz
)
178 PROPERTY_DATA
*propdata
;
179 PROPVARIANT
*property
;
180 PROPERTYIDOFFSET
*idofs
;
181 PROPERTYSECTIONHEADER
*section_hdr
;
183 section_hdr
= (PROPERTYSECTIONHEADER
*) &data
[0];
184 idofs
= (PROPERTYIDOFFSET
*) &data
[SECT_HDR_SIZE
];
186 /* now set all the properties */
187 for( i
= 0; i
< section_hdr
->cProperties
; i
++ )
189 type
= get_type( idofs
[i
].propid
);
190 if( type
== VT_EMPTY
)
192 ERR("propid %ld has unknown type\n", idofs
[i
].propid
);
196 propdata
= (PROPERTY_DATA
*) &data
[ idofs
[i
].dwOffset
];
198 /* check the type is the same as we expect */
199 if( type
!= propdata
->type
)
201 ERR("wrong type %d != %ld\n", type
, propdata
->type
);
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 ( type
== VT_FILETIME
&& sizeof(FILETIME
) > size
) ||
209 ( type
== VT_LPSTR
&& (propdata
->u
.str
.len
+ sizeof(DWORD
)) > size
) )
211 ERR("not enough data\n");
215 if( idofs
[i
].propid
>= MSI_MAX_PROPS
)
217 ERR("Unknown property ID %ld\n", idofs
[i
].propid
);
221 property
= &prop
[ idofs
[i
].propid
];
224 if( type
== VT_LPSTR
)
226 LPSTR str
= HeapAlloc( GetProcessHeap(), 0, propdata
->u
.str
.len
);
227 memcpy( str
, propdata
->u
.str
.str
, propdata
->u
.str
.len
);
228 str
[ propdata
->u
.str
.len
- 1 ] = 0;
229 property
->u
.pszVal
= str
;
231 else if( type
== VT_FILETIME
)
232 property
->u
.filetime
= propdata
->u
.ft
;
233 else if( type
== VT_I2
)
234 property
->u
.iVal
= propdata
->u
.i2
;
235 else if( type
== VT_I4
)
236 property
->u
.lVal
= propdata
->u
.i4
;
240 static UINT
load_summary_info( MSISUMMARYINFO
*si
, IStream
*stm
)
242 UINT ret
= ERROR_FUNCTION_FAILED
;
243 PROPERTYSETHEADER set_hdr
;
244 FORMATIDOFFSET format_hdr
;
245 PROPERTYSECTIONHEADER section_hdr
;
251 TRACE("%p %p\n", si
, stm
);
253 /* read the header */
255 r
= IStream_Read( stm
, &set_hdr
, sz
, &count
);
256 if( FAILED(r
) || count
!= sz
)
259 if( set_hdr
.wByteOrder
!= 0xfffe )
261 ERR("property set not big-endian %04X\n", set_hdr
.wByteOrder
);
265 sz
= sizeof format_hdr
;
266 r
= IStream_Read( stm
, &format_hdr
, sz
, &count
);
267 if( FAILED(r
) || count
!= sz
)
270 /* check the format id is correct */
271 if( !IsEqualGUID( &FMTID_SummaryInformation
, &format_hdr
.fmtid
) )
274 /* seek to the location of the section */
275 ofs
.QuadPart
= format_hdr
.dwOffset
;
276 r
= IStream_Seek( stm
, ofs
, STREAM_SEEK_SET
, NULL
);
280 /* read the section itself */
282 r
= IStream_Read( stm
, §ion_hdr
, sz
, &count
);
283 if( FAILED(r
) || count
!= sz
)
286 if( section_hdr
.cProperties
> MSI_MAX_PROPS
)
288 ERR("too many properties %ld\n", section_hdr
.cProperties
);
292 data
= HeapAlloc( GetProcessHeap(), 0, section_hdr
.cbSection
);
296 memcpy( data
, §ion_hdr
, SECT_HDR_SIZE
);
298 /* read all the data in one go */
299 sz
= section_hdr
.cbSection
- SECT_HDR_SIZE
;
300 r
= IStream_Read( stm
, &data
[ SECT_HDR_SIZE
], sz
, &count
);
301 if( SUCCEEDED(r
) && count
== sz
)
302 read_properties_from_data( si
->property
, data
, sz
+ SECT_HDR_SIZE
);
304 ERR("failed to read properties %ld %ld\n", count
, sz
);
306 HeapFree( GetProcessHeap(), 0, data
);
310 static DWORD
write_dword( LPBYTE data
, DWORD ofs
, DWORD val
)
314 data
[ofs
++] = val
&0xff;
315 data
[ofs
++] = (val
>>8)&0xff;
316 data
[ofs
++] = (val
>>16)&0xff;
317 data
[ofs
++] = (val
>>24)&0xff;
322 static DWORD
write_filetime( LPBYTE data
, DWORD ofs
, LPFILETIME ft
)
324 write_dword( data
, ofs
, ft
->dwLowDateTime
);
325 write_dword( data
, ofs
+ 4, ft
->dwHighDateTime
);
329 static DWORD
write_string( LPBYTE data
, DWORD ofs
, LPCSTR str
)
331 DWORD len
= lstrlenA( str
) + 1;
332 write_dword( data
, ofs
, len
);
334 memcpy( &data
[ofs
+ 4], str
, len
);
335 return (7 + len
) & ~3;
338 static UINT
write_property_to_data( PROPVARIANT
*prop
, LPBYTE data
)
342 if( prop
->vt
== VT_EMPTY
)
346 sz
+= write_dword( data
, sz
, prop
->vt
);
350 sz
+= write_dword( data
, sz
, prop
->u
.iVal
);
353 sz
+= write_dword( data
, sz
, prop
->u
.lVal
);
356 sz
+= write_filetime( data
, sz
, &prop
->u
.filetime
);
359 sz
+= write_string( data
, sz
, prop
->u
.pszVal
);
365 static UINT
save_summary_info( MSISUMMARYINFO
* si
, IStream
*stm
)
367 UINT ret
= ERROR_FUNCTION_FAILED
;
368 PROPERTYSETHEADER set_hdr
;
369 FORMATIDOFFSET format_hdr
;
370 PROPERTYSECTIONHEADER section_hdr
;
371 PROPERTYIDOFFSET idofs
[MSI_MAX_PROPS
];
377 /* write the header */
379 memset( &set_hdr
, 0, sz
);
380 set_hdr
.wByteOrder
= 0xfffe;
382 set_hdr
.dwOSVer
= 0x00020005; /* build 5, platform id 2 */
383 /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */
384 set_hdr
.reserved
= 1;
385 r
= IStream_Write( stm
, &set_hdr
, sz
, &count
);
386 if( FAILED(r
) || count
!= sz
)
389 /* write the format header */
390 sz
= sizeof format_hdr
;
391 memcpy( &format_hdr
.fmtid
, &FMTID_SummaryInformation
, sizeof (FMTID
) );
392 format_hdr
.dwOffset
= sizeof format_hdr
+ sizeof set_hdr
;
393 r
= IStream_Write( stm
, &format_hdr
, sz
, &count
);
394 if( FAILED(r
) || count
!= sz
)
397 /* add up how much space the data will take and calculate the offsets */
398 section_hdr
.cbSection
= sizeof section_hdr
;
399 section_hdr
.cbSection
+= (get_property_count( si
->property
) * sizeof idofs
[0]);
400 section_hdr
.cProperties
= 0;
402 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
404 sz
= write_property_to_data( &si
->property
[i
], NULL
);
407 idofs
[ section_hdr
.cProperties
].propid
= i
;
408 idofs
[ section_hdr
.cProperties
].dwOffset
= section_hdr
.cbSection
;
409 section_hdr
.cProperties
++;
410 section_hdr
.cbSection
+= sz
;
413 data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, section_hdr
.cbSection
);
416 memcpy( &data
[sz
], §ion_hdr
, sizeof section_hdr
);
417 sz
+= sizeof section_hdr
;
419 memcpy( &data
[sz
], idofs
, section_hdr
.cProperties
* sizeof idofs
[0] );
420 sz
+= section_hdr
.cProperties
* sizeof idofs
[0];
422 /* write out the data */
423 for( i
= 0; i
< MSI_MAX_PROPS
; i
++ )
424 sz
+= write_property_to_data( &si
->property
[i
], &data
[sz
] );
426 r
= IStream_Write( stm
, data
, sz
, &count
);
427 HeapFree( GetProcessHeap(), 0, data
);
428 if( FAILED(r
) || count
!= sz
)
431 return ERROR_SUCCESS
;
434 UINT WINAPI
MsiGetSummaryInformationW( MSIHANDLE hDatabase
,
435 LPCWSTR szDatabase
, UINT uiUpdateCount
, MSIHANDLE
*pHandle
)
437 UINT ret
= ERROR_SUCCESS
;
445 TRACE("%ld %s %d %p\n", hDatabase
, debugstr_w(szDatabase
),
446 uiUpdateCount
, pHandle
);
449 return ERROR_INVALID_PARAMETER
;
455 res
= MSI_OpenDatabaseW(szDatabase
, NULL
, &db
);
456 if( res
!= ERROR_SUCCESS
)
461 db
= msihandle2msiinfo(hDatabase
, MSIHANDLETYPE_DATABASE
);
463 return ERROR_INVALID_PARAMETER
;
466 si
= alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO
,
467 sizeof (MSISUMMARYINFO
), MSI_CloseSummaryInfo
);
470 ret
= ERROR_FUNCTION_FAILED
;
474 msiobj_addref( &db
->hdr
);
476 memset( &si
->property
, 0, sizeof si
->property
);
477 si
->update_count
= uiUpdateCount
;
479 /* read the stream... if we fail, we'll start with an empty property set */
480 grfMode
= STGM_READ
| STGM_SHARE_EXCLUSIVE
;
481 r
= IStorage_OpenStream( si
->db
->storage
, szSumInfo
, 0, grfMode
, 0, &stm
);
484 load_summary_info( si
, stm
);
485 IStream_Release( stm
);
488 handle
= alloc_msihandle( &si
->hdr
);
492 ret
= ERROR_FUNCTION_FAILED
;
493 msiobj_release( &si
->hdr
);
497 msiobj_release( &db
->hdr
);
502 UINT WINAPI
MsiGetSummaryInformationA(MSIHANDLE hDatabase
,
503 LPCSTR szDatabase
, UINT uiUpdateCount
, MSIHANDLE
*pHandle
)
505 LPWSTR szwDatabase
= NULL
;
508 TRACE("%ld %s %d %p\n", hDatabase
, debugstr_a(szDatabase
),
509 uiUpdateCount
, pHandle
);
513 szwDatabase
= strdupAtoW( szDatabase
);
515 return ERROR_FUNCTION_FAILED
;
518 ret
= MsiGetSummaryInformationW(hDatabase
, szwDatabase
, uiUpdateCount
, pHandle
);
520 HeapFree( GetProcessHeap(), 0, szwDatabase
);
525 UINT WINAPI
MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo
, UINT
*pCount
)
529 TRACE("%ld %p\n",hSummaryInfo
, pCount
);
531 si
= msihandle2msiinfo( hSummaryInfo
, MSIHANDLETYPE_SUMMARYINFO
);
533 return ERROR_INVALID_HANDLE
;
536 *pCount
= get_property_count( si
->property
);
537 msiobj_release( &si
->hdr
);
539 return ERROR_SUCCESS
;
542 static UINT
get_prop( MSIHANDLE handle
, UINT uiProperty
, UINT
*puiDataType
,
543 INT
*piValue
, FILETIME
*pftValue
, awstring
*str
, DWORD
*pcchValueBuf
)
548 TRACE("%ld %d %p %p %p %p %p\n", handle
, uiProperty
, puiDataType
,
549 piValue
, pftValue
, str
, pcchValueBuf
);
551 si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
);
553 return ERROR_INVALID_HANDLE
;
555 prop
= &si
->property
[uiProperty
];
558 *puiDataType
= prop
->vt
;
564 *piValue
= prop
->u
.iVal
;
568 *piValue
= prop
->u
.lVal
;
577 len
= MultiByteToWideChar( CP_ACP
, 0, prop
->u
.pszVal
, -1,
578 str
->str
.w
, *pcchValueBuf
);
582 len
= lstrlenA( prop
->u
.pszVal
);
584 lstrcpynA(str
->str
.a
, prop
->u
.pszVal
, *pcchValueBuf
);
591 memcpy(pftValue
, &prop
->u
.filetime
, sizeof (FILETIME
) );
596 FIXME("Unknown property variant type\n");
599 msiobj_release( &si
->hdr
);
600 return ERROR_SUCCESS
;
603 UINT WINAPI
MsiSummaryInfoGetPropertyA(
604 MSIHANDLE handle
, UINT uiProperty
, UINT
*puiDataType
, INT
*piValue
,
605 FILETIME
*pftValue
, LPSTR szValueBuf
, DWORD
*pcchValueBuf
)
609 TRACE("%ld %d %p %p %p %p %p\n", handle
, uiProperty
, puiDataType
,
610 piValue
, pftValue
, szValueBuf
, pcchValueBuf
);
613 str
.str
.a
= szValueBuf
;
615 return get_prop( handle
, uiProperty
, puiDataType
, piValue
,
616 pftValue
, &str
, pcchValueBuf
);
619 UINT WINAPI
MsiSummaryInfoGetPropertyW(
620 MSIHANDLE handle
, UINT uiProperty
, UINT
*puiDataType
, INT
*piValue
,
621 FILETIME
*pftValue
, LPWSTR szValueBuf
, DWORD
*pcchValueBuf
)
625 TRACE("%ld %d %p %p %p %p %p\n", handle
, uiProperty
, puiDataType
,
626 piValue
, pftValue
, szValueBuf
, pcchValueBuf
);
629 str
.str
.w
= szValueBuf
;
631 return get_prop( handle
, uiProperty
, puiDataType
, piValue
,
632 pftValue
, &str
, pcchValueBuf
);
635 static UINT
set_prop( MSIHANDLE handle
, UINT uiProperty
, UINT uiDataType
,
636 INT iValue
, FILETIME
* pftValue
, awcstring
*str
)
640 UINT type
, len
, ret
= ERROR_SUCCESS
;
642 TRACE("%ld %u %u %i %p %p\n", handle
, uiProperty
, uiDataType
,
643 iValue
, pftValue
, str
);
645 type
= get_type( uiProperty
);
646 if( type
== VT_EMPTY
|| type
!= uiDataType
)
647 return ERROR_DATATYPE_MISMATCH
;
649 if( uiDataType
== VT_LPSTR
&& !str
->str
.w
)
650 return ERROR_INVALID_PARAMETER
;
652 if( uiDataType
== VT_FILETIME
&& !pftValue
)
653 return ERROR_INVALID_PARAMETER
;
655 si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
);
657 return ERROR_INVALID_HANDLE
;
659 prop
= &si
->property
[uiProperty
];
661 if( prop
->vt
== VT_EMPTY
)
663 if( !si
->update_count
)
665 ret
= ERROR_FUNCTION_FAILED
;
670 else if( prop
->vt
!= type
)
678 prop
->u
.lVal
= iValue
;
681 prop
->u
.iVal
= iValue
;
684 memcpy( &prop
->u
.filetime
, pftValue
, sizeof prop
->u
.filetime
);
689 len
= WideCharToMultiByte( CP_ACP
, 0, str
->str
.w
, -1,
690 NULL
, 0, NULL
, NULL
);
691 prop
->u
.pszVal
= HeapAlloc( GetProcessHeap(), 0, len
);
692 WideCharToMultiByte( CP_ACP
, 0, str
->str
.w
, -1,
693 prop
->u
.pszVal
, len
, NULL
, NULL
);
697 len
= lstrlenA( str
->str
.a
) + 1;
698 prop
->u
.pszVal
= HeapAlloc( GetProcessHeap(), 0, len
);
699 lstrcpyA( prop
->u
.pszVal
, str
->str
.a
);
705 msiobj_release( &si
->hdr
);
709 UINT WINAPI
MsiSummaryInfoSetPropertyW( MSIHANDLE handle
, UINT uiProperty
,
710 UINT uiDataType
, INT iValue
, FILETIME
* pftValue
, LPCWSTR szValue
)
714 TRACE("%ld %u %u %i %p %s\n", handle
, uiProperty
, uiDataType
,
715 iValue
, pftValue
, debugstr_w(szValue
) );
719 return set_prop( handle
, uiProperty
, uiDataType
, iValue
, pftValue
, &str
);
722 UINT WINAPI
MsiSummaryInfoSetPropertyA( MSIHANDLE handle
, UINT uiProperty
,
723 UINT uiDataType
, INT iValue
, FILETIME
* pftValue
, LPCSTR szValue
)
727 TRACE("%ld %u %u %i %p %s\n", handle
, uiProperty
, uiDataType
,
728 iValue
, pftValue
, debugstr_a(szValue
) );
732 return set_prop( handle
, uiProperty
, uiDataType
, iValue
, pftValue
, &str
);
735 UINT WINAPI
MsiSummaryInfoPersist( MSIHANDLE handle
)
741 UINT ret
= ERROR_FUNCTION_FAILED
;
743 TRACE("%ld\n", handle
);
745 si
= msihandle2msiinfo( handle
, MSIHANDLETYPE_SUMMARYINFO
);
747 return ERROR_INVALID_HANDLE
;
749 grfMode
= STGM_CREATE
| STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
;
750 r
= IStorage_CreateStream( si
->db
->storage
, szSumInfo
, grfMode
, 0, 0, &stm
);
753 ret
= save_summary_info( si
, stm
);
754 IStream_Release( stm
);
756 msiobj_release( &si
->hdr
);