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))
84 typedef struct tagMSISUMMARYINFO
89 PROPVARIANT property[MSI_MAX_PROPS];
92 static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y',
93 'I','n','f','o','r','m','a','t','i','o','n',0 };
95 static void free_prop( PROPVARIANT *prop )
97 if (prop->vt == VT_LPSTR )
98 HeapFree( GetProcessHeap(), 0, prop->u.pszVal );
102 static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
104 MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg;
107 for( i = 0; i < MSI_MAX_PROPS; i++ )
108 free_prop( &si->property[i] );
109 msiobj_release( &si->db->hdr );
112 static UINT get_type( UINT uiProperty )
130 case PID_LASTPRINTED:
132 case PID_LASTSAVE_DTM:
144 static UINT get_property_count( PROPVARIANT *property )
150 for( i = 0; i < MSI_MAX_PROPS; i++ )
151 if( property[i].vt != VT_EMPTY )
156 /* FIXME: doesn't deal with endian conversion */
157 static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz )
162 PROPERTY_DATA *propdata;
163 PROPVARIANT *property;
164 PROPERTYIDOFFSET *idofs;
165 PROPERTYSECTIONHEADER *section_hdr;
167 section_hdr = (PROPERTYSECTIONHEADER*) &data[0];
168 idofs = (PROPERTYIDOFFSET*) &data[SECT_HDR_SIZE];
170 /* now set all the properties */
171 for( i = 0; i < section_hdr->cProperties; i++ )
173 type = get_type( idofs[i].propid );
174 if( type == VT_EMPTY )
176 ERR("propid %ld has unknown type\n", idofs[i].propid);
180 propdata = (PROPERTY_DATA*) &data[ idofs[i].dwOffset ];
182 /* check the type is the same as we expect */
183 if( type != propdata->type )
185 ERR("wrong type %d != %ld\n", type, propdata->type);
189 /* check we don't run off the end of the data */
190 size = sz - idofs[i].dwOffset - sizeof(DWORD);
191 if( sizeof(DWORD) > size ||
192 ( type == VT_FILETIME && sizeof(FILETIME) > size ) ||
193 ( type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) )
195 ERR("not enough data\n");
199 if( idofs[i].propid >= MSI_MAX_PROPS )
201 ERR("Unknown property ID %ld\n", idofs[i].propid );
205 property = &prop[ idofs[i].propid ];
208 if( type == VT_LPSTR )
210 LPSTR str = HeapAlloc( GetProcessHeap(), 0, propdata->u.str.len );
211 memcpy( str, propdata->u.str.str, propdata->u.str.len );
212 str[ propdata->u.str.len - 1 ] = 0;
213 property->u.pszVal = str;
215 else if( type == VT_FILETIME )
216 property->u.filetime = propdata->u.ft;
217 else if( type == VT_I2 )
218 property->u.iVal = propdata->u.i2;
219 else if( type == VT_I4 )
220 property->u.lVal = propdata->u.i4;
224 static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
226 UINT ret = ERROR_FUNCTION_FAILED;
227 PROPERTYSETHEADER set_hdr;
228 FORMATIDOFFSET format_hdr;
229 PROPERTYSECTIONHEADER section_hdr;
235 TRACE("%p %p\n", si, stm);
237 /* read the header */
239 r = IStream_Read( stm, &set_hdr, sz, &count );
240 if( FAILED(r) || count != sz )
243 if( set_hdr.wByteOrder != 0xfffe )
245 ERR("property set not big-endian %04X\n", set_hdr.wByteOrder);
249 sz = sizeof format_hdr;
250 r = IStream_Read( stm, &format_hdr, sz, &count );
251 if( FAILED(r) || count != sz )
254 /* check the format id is correct */
255 if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) )
258 /* seek to the location of the section */
259 ofs.QuadPart = format_hdr.dwOffset;
260 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL );
264 /* read the section itself */
266 r = IStream_Read( stm, §ion_hdr, sz, &count );
267 if( FAILED(r) || count != sz )
270 if( section_hdr.cProperties > MSI_MAX_PROPS )
272 ERR("too many properties %ld\n", section_hdr.cProperties);
276 data = HeapAlloc( GetProcessHeap(), 0, section_hdr.cbSection);
280 memcpy( data, §ion_hdr, SECT_HDR_SIZE );
282 /* read all the data in one go */
283 sz = section_hdr.cbSection - SECT_HDR_SIZE;
284 r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count );
285 if( SUCCEEDED(r) && count == sz )
286 read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE );
288 ERR("failed to read properties %ld %ld\n", count, sz);
290 HeapFree( GetProcessHeap(), 0, data );
294 static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val )
298 data[ofs++] = val&0xff;
299 data[ofs++] = (val>>8)&0xff;
300 data[ofs++] = (val>>16)&0xff;
301 data[ofs++] = (val>>24)&0xff;
306 static DWORD write_filetime( LPBYTE data, DWORD ofs, LPFILETIME ft )
308 write_dword( data, ofs, ft->dwLowDateTime );
309 write_dword( data, ofs + 4, ft->dwHighDateTime );
313 static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str )
315 DWORD len = lstrlenA( str ) + 1;
316 write_dword( data, ofs, len );
318 memcpy( &data[ofs + 4], str, len );
319 return (7 + len) & ~3;
322 static UINT write_property_to_data( PROPVARIANT *prop, LPBYTE data )
326 if( prop->vt == VT_EMPTY )
330 sz += write_dword( data, sz, prop->vt );
334 sz += write_dword( data, sz, prop->u.iVal );
337 sz += write_dword( data, sz, prop->u.lVal );
340 sz += write_filetime( data, sz, &prop->u.filetime );
343 sz += write_string( data, sz, prop->u.pszVal );
349 static UINT save_summary_info( MSISUMMARYINFO * si, IStream *stm )
351 UINT ret = ERROR_FUNCTION_FAILED;
352 PROPERTYSETHEADER set_hdr;
353 FORMATIDOFFSET format_hdr;
354 PROPERTYSECTIONHEADER section_hdr;
355 PROPERTYIDOFFSET idofs[MSI_MAX_PROPS];
361 /* write the header */
363 memset( &set_hdr, 0, sz );
364 set_hdr.wByteOrder = 0xfffe;
366 set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */
367 /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */
368 set_hdr.reserved = 1;
369 r = IStream_Write( stm, &set_hdr, sz, &count );
370 if( FAILED(r) || count != sz )
373 /* write the format header */
374 sz = sizeof format_hdr;
375 memcpy( &format_hdr.fmtid, &FMTID_SummaryInformation, sizeof (FMTID) );
376 format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr;
377 r = IStream_Write( stm, &format_hdr, sz, &count );
378 if( FAILED(r) || count != sz )
381 /* add up how much space the data will take and calculate the offsets */
382 section_hdr.cbSection = sizeof section_hdr;
383 section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]);
384 section_hdr.cProperties = 0;
386 for( i = 0; i < MSI_MAX_PROPS; i++ )
388 sz = write_property_to_data( &si->property[i], NULL );
391 idofs[ section_hdr.cProperties ].propid = i;
392 idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection;
393 section_hdr.cProperties++;
394 section_hdr.cbSection += sz;
397 data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, section_hdr.cbSection );
400 memcpy( &data[sz], §ion_hdr, sizeof section_hdr );
401 sz += sizeof section_hdr;
403 memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] );
404 sz += section_hdr.cProperties * sizeof idofs[0];
406 /* write out the data */
407 for( i = 0; i < MSI_MAX_PROPS; i++ )
408 sz += write_property_to_data( &si->property[i], &data[sz] );
410 r = IStream_Write( stm, data, sz, &count );
411 HeapFree( GetProcessHeap(), 0, data );
412 if( FAILED(r) || count != sz )
415 return ERROR_SUCCESS;
418 UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
419 LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
421 UINT ret = ERROR_SUCCESS;
429 TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
430 uiUpdateCount, pHandle);
433 return ERROR_INVALID_PARAMETER;
439 res = MSI_OpenDatabaseW(szDatabase, NULL, &db);
440 if( res != ERROR_SUCCESS )
445 db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
447 return ERROR_INVALID_PARAMETER;
450 si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO,
451 sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
454 ret = ERROR_FUNCTION_FAILED;
458 msiobj_addref( &db->hdr );
460 memset( &si->property, 0, sizeof si->property );
461 si->update_count = uiUpdateCount;
463 /* read the stream... if we fail, we'll start with an empty property set */
464 grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
465 r = IStorage_OpenStream( si->db->storage, szSumInfo, 0, grfMode, 0, &stm );
468 load_summary_info( si, stm );
469 IStream_Release( stm );
472 handle = alloc_msihandle( &si->hdr );
476 ret = ERROR_FUNCTION_FAILED;
477 msiobj_release( &si->hdr );
481 msiobj_release( &db->hdr );
486 UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase,
487 LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
489 LPWSTR szwDatabase = NULL;
492 TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase),
493 uiUpdateCount, pHandle);
497 szwDatabase = strdupAtoW( szDatabase );
499 return ERROR_FUNCTION_FAILED;
502 ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle);
504 HeapFree( GetProcessHeap(), 0, szwDatabase );
509 UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount)
513 TRACE("%ld %p\n",hSummaryInfo, pCount);
515 si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
517 return ERROR_INVALID_HANDLE;
520 *pCount = get_property_count( si->property );
521 msiobj_release( &si->hdr );
523 return ERROR_SUCCESS;
526 static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
527 INT *piValue, FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
531 UINT ret = ERROR_SUCCESS;
533 TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
534 piValue, pftValue, str, pcchValueBuf);
536 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
538 return ERROR_INVALID_HANDLE;
540 prop = &si->property[uiProperty];
543 *puiDataType = prop->vt;
549 *piValue = prop->u.iVal;
553 *piValue = prop->u.lVal;
562 len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1,
563 str->str.w, *pcchValueBuf );
568 len = lstrlenA( prop->u.pszVal );
570 lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf );
572 if (len >= *pcchValueBuf)
573 ret = ERROR_MORE_DATA;
579 memcpy(pftValue, &prop->u.filetime, sizeof (FILETIME) );
584 FIXME("Unknown property variant type\n");
587 msiobj_release( &si->hdr );
591 UINT WINAPI MsiSummaryInfoGetPropertyA(
592 MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
593 FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf)
597 TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
598 piValue, pftValue, szValueBuf, pcchValueBuf );
601 str.str.a = szValueBuf;
603 return get_prop( handle, uiProperty, puiDataType, piValue,
604 pftValue, &str, pcchValueBuf );
607 UINT WINAPI MsiSummaryInfoGetPropertyW(
608 MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
609 FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf)
613 TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
614 piValue, pftValue, szValueBuf, pcchValueBuf );
617 str.str.w = szValueBuf;
619 return get_prop( handle, uiProperty, puiDataType, piValue,
620 pftValue, &str, pcchValueBuf );
623 static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
624 INT iValue, FILETIME* pftValue, awcstring *str )
628 UINT type, len, ret = ERROR_SUCCESS;
630 TRACE("%ld %u %u %i %p %p\n", handle, uiProperty, uiDataType,
631 iValue, pftValue, str );
633 type = get_type( uiProperty );
634 if( type == VT_EMPTY || type != uiDataType )
635 return ERROR_DATATYPE_MISMATCH;
637 if( uiDataType == VT_LPSTR && !str->str.w )
638 return ERROR_INVALID_PARAMETER;
640 if( uiDataType == VT_FILETIME && !pftValue )
641 return ERROR_INVALID_PARAMETER;
643 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
645 return ERROR_INVALID_HANDLE;
647 prop = &si->property[uiProperty];
649 if( prop->vt == VT_EMPTY )
651 if( !si->update_count )
653 ret = ERROR_FUNCTION_FAILED;
658 else if( prop->vt != type )
666 prop->u.lVal = iValue;
669 prop->u.iVal = iValue;
672 memcpy( &prop->u.filetime, pftValue, sizeof prop->u.filetime );
677 len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
678 NULL, 0, NULL, NULL );
679 prop->u.pszVal = HeapAlloc( GetProcessHeap(), 0, len );
680 WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
681 prop->u.pszVal, len, NULL, NULL );
685 len = lstrlenA( str->str.a ) + 1;
686 prop->u.pszVal = HeapAlloc( GetProcessHeap(), 0, len );
687 lstrcpyA( prop->u.pszVal, str->str.a );
693 msiobj_release( &si->hdr );
697 UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
698 UINT uiDataType, INT iValue, FILETIME* pftValue, LPCWSTR szValue )
702 TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
703 iValue, pftValue, debugstr_w(szValue) );
707 return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str );
710 UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
711 UINT uiDataType, INT iValue, FILETIME* pftValue, LPCSTR szValue )
715 TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
716 iValue, pftValue, debugstr_a(szValue) );
720 return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str );
723 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
729 UINT ret = ERROR_FUNCTION_FAILED;
731 TRACE("%ld\n", handle );
733 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
735 return ERROR_INVALID_HANDLE;
737 grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
738 r = IStorage_CreateStream( si->db->storage, szSumInfo, grfMode, 0, 0, &stm );
741 ret = save_summary_info( si, stm );
742 IStream_Release( stm );
744 msiobj_release( &si->hdr );