Implement summary information loading and saving.
[wine/gsoc_dplay.git] / dlls / msi / suminfo.c
blob423c8286b98e1976018ce318fc99d5659b2b0129
1 /*
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
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
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 "msi.h"
33 #include "msiquery.h"
34 #include "msidefs.h"
35 #include "msipriv.h"
36 #include "objidl.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40 #define MSI_MAX_PROPS 19
42 #include "pshpack1.h"
44 typedef struct {
45 WORD wByteOrder;
46 WORD wFormat;
47 DWORD dwOSVer;
48 CLSID clsID;
49 DWORD reserved;
50 } PROPERTYSETHEADER;
52 typedef struct {
53 FMTID fmtid;
54 DWORD dwOffset;
55 } FORMATIDOFFSET;
57 typedef struct {
58 DWORD cbSection;
59 DWORD cProperties;
60 } PROPERTYSECTIONHEADER;
62 typedef struct {
63 DWORD propid;
64 DWORD dwOffset;
65 } PROPERTYIDOFFSET;
67 typedef struct {
68 DWORD type;
69 union {
70 INT i4;
71 SHORT i2;
72 FILETIME ft;
73 struct {
74 DWORD len;
75 BYTE str[1];
76 } str;
77 } u;
78 } PROPERTY_DATA;
80 #include "poppack.h"
82 typedef struct {
83 BOOL unicode;
84 union {
85 LPSTR a;
86 LPWSTR w;
87 } str;
88 } awstring;
90 typedef struct tagMSISUMMARYINFO
92 MSIOBJECTHDR hdr;
93 MSIDATABASE *db;
94 DWORD update_count;
95 PROPVARIANT property[MSI_MAX_PROPS];
96 } MSISUMMARYINFO;
98 static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y',
99 'I','n','f','o','r','m','a','t','i','o','n',0 };
101 static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
103 MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg;
104 msiobj_release( &si->db->hdr );
107 static UINT get_type( UINT uiProperty )
109 switch( uiProperty )
111 case PID_CODEPAGE:
112 return VT_I2;
114 case PID_SUBJECT:
115 case PID_AUTHOR:
116 case PID_KEYWORDS:
117 case PID_COMMENTS:
118 case PID_TEMPLATE:
119 case PID_LASTAUTHOR:
120 case PID_REVNUMBER:
121 case PID_APPNAME:
122 case PID_TITLE:
123 return VT_LPSTR;
125 case PID_LASTPRINTED:
126 case PID_CREATE_DTM:
127 case PID_LASTSAVE_DTM:
128 return VT_FILETIME;
130 case PID_WORDCOUNT:
131 case PID_CHARCOUNT:
132 case PID_SECURITY:
133 case PID_PAGECOUNT:
134 return VT_I4;
136 return VT_EMPTY;
139 static UINT get_property_count( PROPVARIANT *property )
141 UINT i, n = 0;
143 if( !property )
144 return n;
145 for( i=0; i<MSI_MAX_PROPS; i++ )
146 if( property[i].vt != VT_EMPTY )
147 n++;
148 return n;
151 /* FIXME: doesn't deal with endian conversion */
152 static void read_properties_from_data( PROPVARIANT *prop,
153 PROPERTYIDOFFSET *idofs, DWORD count, LPBYTE data, DWORD sz )
155 UINT type;
156 DWORD i;
157 int size;
158 PROPERTY_DATA *propdata;
159 PROPVARIANT *property;
161 /* now set all the properties */
162 for( i = 0; i < count; i++ )
164 type = get_type( idofs[i].propid );
165 if( type == VT_EMPTY )
167 ERR("propid %ld has unknown type\n", idofs[i].propid);
168 break;
171 propdata = (PROPERTY_DATA*) &data[idofs[i].dwOffset];
173 /* check the type is the same as we expect */
174 if( type != propdata->type )
176 ERR("wrong type\n");
177 break;
180 /* check we don't run off the end of the data */
181 size = sz - idofs[i].dwOffset - sizeof(DWORD);
182 if( sizeof(DWORD) > size ||
183 ( type == VT_FILETIME && sizeof(FILETIME) > size ) ||
184 ( type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) )
186 ERR("not enough data\n");
187 break;
190 property = &prop[ idofs[i].propid ];
191 property->vt = type;
193 if( type == VT_LPSTR )
195 LPSTR str = HeapAlloc( GetProcessHeap(), 0, propdata->u.str.len );
196 memcpy( str, propdata->u.str.str, propdata->u.str.len );
197 str[ propdata->u.str.len - 1 ] = 0;
198 property->u.pszVal = str;
200 else if( type == VT_FILETIME )
201 property->u.filetime = propdata->u.ft;
202 else if( type == VT_I2 )
203 property->u.iVal = propdata->u.i2;
204 else if( type == VT_I4 )
205 property->u.lVal = propdata->u.i4;
209 static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
211 UINT ret = ERROR_FUNCTION_FAILED;
212 PROPERTYSETHEADER set_hdr;
213 FORMATIDOFFSET format_hdr;
214 PROPERTYSECTIONHEADER section_hdr;
215 PROPERTYIDOFFSET idofs[MSI_MAX_PROPS];
216 LPBYTE data = NULL;
217 LARGE_INTEGER ofs;
218 ULONG count, sz;
219 HRESULT r;
221 TRACE("%p %p\n", si, stm);
223 /* read the header */
224 sz = sizeof set_hdr;
225 r = IStream_Read( stm, &set_hdr, sz, &count );
226 if( FAILED(r) || count != sz )
227 return ret;
229 if( set_hdr.wByteOrder != 0xfffe )
231 ERR("property set not big-endian %04X\n", set_hdr.wByteOrder);
232 return ret;
235 sz = sizeof format_hdr;
236 r = IStream_Read( stm, &format_hdr, sz, &count );
237 if( FAILED(r) || count != sz )
238 return ret;
240 /* check the format id is correct */
241 if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) )
242 return ret;
244 /* seek to the location of the section */
245 ofs.QuadPart = format_hdr.dwOffset;
246 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL );
247 if( FAILED(r) )
248 return ret;
250 /* read the section itself */
251 sz = sizeof section_hdr;
252 r = IStream_Read( stm, &section_hdr, sz, &count );
253 if( FAILED(r) || count != sz )
254 return ret;
256 if( section_hdr.cProperties > MSI_MAX_PROPS )
258 ERR("too many properties %ld\n", section_hdr.cProperties);
259 return ret;
262 /* read the offsets */
263 sz = sizeof idofs[0] * section_hdr.cProperties;
264 r = IStream_Read( stm, idofs, sz, &count );
265 if( FAILED(r) || count != sz )
266 return ret;
268 /* read all the data in one go */
269 sz = section_hdr.cbSection;
270 data = HeapAlloc( GetProcessHeap(), 0, sz );
271 if( !data )
272 return ret;
273 r = IStream_Read( stm, data, sz, &count );
274 if( SUCCEEDED(r) && count == sz )
276 read_properties_from_data( si->property, idofs,
277 section_hdr.cProperties, data, sz );
280 HeapFree( GetProcessHeap(), 0, data );
281 return ret;
284 static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val )
286 if( data )
288 data[ofs++] = val&0xff;
289 data[ofs++] = (val>>8)&0xff;
290 data[ofs++] = (val>>16)&0xff;
291 data[ofs++] = (val>>24)&0xff;
293 return 4;
296 static DWORD write_filetime( LPBYTE data, DWORD ofs, LPFILETIME ft )
298 write_dword( data, ofs, ft->dwLowDateTime );
299 write_dword( data, ofs + 4, ft->dwHighDateTime );
300 return 8;
303 static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str )
305 DWORD len = lstrlenA( str ) + 1;
306 write_dword( data, ofs, len );
307 if( data )
308 lstrcpyA( &data[ofs + 4], str );
309 return (7 + len) & ~3;
312 static UINT write_property_to_data( PROPVARIANT *prop, LPBYTE data )
314 DWORD sz = 0;
316 if( prop->vt == VT_EMPTY )
317 return sz;
319 /* add the type */
320 sz += write_dword( data, sz, prop->vt );
321 switch( prop->vt )
323 case VT_I2:
324 sz += write_dword( data, sz, prop->u.iVal );
325 break;
326 case VT_I4:
327 sz += write_dword( data, sz, prop->u.lVal );
328 break;
329 case VT_FILETIME:
330 sz += write_filetime( data, sz, &prop->u.filetime );
331 break;
332 case VT_LPSTR:
333 sz += write_string( data, sz, prop->u.pszVal );
334 break;
336 return sz;
339 static UINT save_summary_info( MSISUMMARYINFO * si, IStream *stm )
341 UINT ret = ERROR_FUNCTION_FAILED;
342 PROPERTYSETHEADER set_hdr;
343 FORMATIDOFFSET format_hdr;
344 PROPERTYSECTIONHEADER section_hdr;
345 PROPERTYIDOFFSET idofs[MSI_MAX_PROPS];
346 LPBYTE data = NULL;
347 ULONG count, sz;
348 HRESULT r;
349 int i, n;
351 /* write the header */
352 sz = sizeof set_hdr;
353 memset( &set_hdr, 0, sz );
354 set_hdr.wByteOrder = 0xfffe;
355 set_hdr.wFormat = 0;
356 set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */
357 /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */
358 set_hdr.reserved = 1;
359 r = IStream_Write( stm, &set_hdr, sz, &count );
360 if( FAILED(r) || count != sz )
361 return ret;
363 /* write the format header */
364 sz = sizeof format_hdr;
365 memcpy( &format_hdr.fmtid, &FMTID_SummaryInformation, sizeof (FMTID) );
366 format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr;
367 r = IStream_Write( stm, &format_hdr, sz, &count );
368 if( FAILED(r) || count != sz )
369 return ret;
371 /* add up how much space the data will take and calculate the offsets */
372 section_hdr.cbSection = sizeof section_hdr;
373 section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]);
374 section_hdr.cProperties = 0;
375 n = 0;
376 for( i = 0; i < MSI_MAX_PROPS; i++ )
378 sz = write_property_to_data( &si->property[i], NULL );
379 if( !sz )
380 continue;
381 idofs[ section_hdr.cProperties ].propid = i;
382 idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection;
383 section_hdr.cProperties++;
384 section_hdr.cbSection += sz;
387 data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, section_hdr.cbSection );
389 sz = 0;
390 memcpy( &data[sz], &section_hdr, sizeof section_hdr );
391 sz += sizeof section_hdr;
393 memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] );
394 sz += section_hdr.cProperties * sizeof idofs[0];
396 /* write out the data */
397 for( i = 0; i < MSI_MAX_PROPS; i++ )
398 sz += write_property_to_data( &si->property[i], &data[sz] );
400 r = IStream_Write( stm, data, sz, &count );
401 HeapFree( GetProcessHeap(), 0, data );
402 if( FAILED(r) || count != sz )
403 return ret;
405 return ERROR_SUCCESS;
408 UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
409 LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
411 UINT ret = ERROR_SUCCESS;
412 IStream *stm = NULL;
413 MSISUMMARYINFO *si;
414 MSIHANDLE handle;
415 MSIDATABASE *db;
416 DWORD grfMode;
417 HRESULT r;
419 TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
420 uiUpdateCount, pHandle);
422 if( !pHandle )
423 return ERROR_INVALID_PARAMETER;
425 if( szDatabase )
427 UINT res;
429 res = MSI_OpenDatabaseW(szDatabase, NULL, &db);
430 if( res != ERROR_SUCCESS )
431 return res;
433 else
435 db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
436 if( !db )
437 return ERROR_INVALID_PARAMETER;
440 si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO,
441 sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
442 if( !si )
444 ret = ERROR_FUNCTION_FAILED;
445 goto end;
448 msiobj_addref( &db->hdr );
449 si->db = db;
450 memset( &si->property, 0, sizeof si->property );
451 si->update_count = uiUpdateCount;
453 /* read the stream... if we fail, we'll start with an empty property set */
454 grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
455 r = IStorage_OpenStream( si->db->storage, szSumInfo, 0, grfMode, 0, &stm );
456 if( SUCCEEDED(r) )
458 load_summary_info( si, stm );
459 IStream_Release( stm );
462 handle = alloc_msihandle( &si->hdr );
463 if( handle )
464 *pHandle = handle;
465 else
466 ret = ERROR_FUNCTION_FAILED;
467 msiobj_release( &si->hdr );
469 end:
470 if( db )
471 msiobj_release(&db->hdr);
473 return ret;
476 UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase,
477 LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
479 LPWSTR szwDatabase = NULL;
480 UINT ret;
482 TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase),
483 uiUpdateCount, pHandle);
485 if( szDatabase )
487 szwDatabase = strdupAtoW( szDatabase );
488 if( !szwDatabase )
489 return ERROR_FUNCTION_FAILED;
492 ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle);
494 HeapFree( GetProcessHeap(), 0, szwDatabase );
496 return ret;
499 UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount)
501 MSISUMMARYINFO *si;
503 TRACE("%ld %p\n",hSummaryInfo, pCount);
505 si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
506 if( !si )
507 return ERROR_INVALID_HANDLE;
509 if( pCount )
510 *pCount = get_property_count( si->property );
511 msiobj_release( &si->hdr );
513 return ERROR_SUCCESS;
516 static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
517 INT *piValue, FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
519 MSISUMMARYINFO *si;
520 PROPVARIANT *prop;
521 UINT type;
523 TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
524 piValue, pftValue, str, pcchValueBuf);
526 type = get_type( uiProperty );
527 if( puiDataType )
528 *puiDataType = type;
530 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
531 if( !si )
532 return ERROR_INVALID_HANDLE;
534 prop = &si->property[uiProperty];
535 if( prop->vt != type )
536 goto end;
538 switch( type )
540 case VT_I2:
541 if( piValue )
542 *piValue = prop->u.iVal;
543 break;
544 case VT_I4:
545 if( piValue )
546 *piValue = prop->u.lVal;
547 break;
548 case VT_LPSTR:
549 if( pcchValueBuf )
551 DWORD len = 0;
553 if( str->unicode )
555 len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1,
556 str->str.w, *pcchValueBuf );
558 else
560 len = lstrlenA( prop->u.pszVal );
561 if( str->str.a )
562 lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf );
564 *pcchValueBuf = len;
566 break;
567 case VT_FILETIME:
568 if( pftValue )
569 memcpy(pftValue, &prop->u.filetime, sizeof (FILETIME) );
570 break;
571 case VT_EMPTY:
572 break;
573 default:
574 FIXME("Unknown property variant type\n");
575 break;
577 end:
578 msiobj_release( &si->hdr );
579 return ERROR_SUCCESS;
582 UINT WINAPI MsiSummaryInfoGetPropertyA(
583 MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
584 FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf)
586 awstring str;
588 TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
589 piValue, pftValue, szValueBuf, pcchValueBuf );
591 str.unicode = FALSE;
592 str.str.a = szValueBuf;
594 return get_prop( handle, uiProperty, puiDataType, piValue,
595 pftValue, &str, pcchValueBuf );
598 UINT WINAPI MsiSummaryInfoGetPropertyW(
599 MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
600 FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf)
602 awstring str;
604 TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
605 piValue, pftValue, szValueBuf, pcchValueBuf );
607 str.unicode = TRUE;
608 str.str.w = szValueBuf;
610 return get_prop( handle, uiProperty, puiDataType, piValue,
611 pftValue, &str, pcchValueBuf );
614 static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
615 INT iValue, FILETIME* pftValue, awstring *str )
617 MSISUMMARYINFO *si;
618 PROPVARIANT *prop;
619 UINT type, len, ret = ERROR_SUCCESS;
621 TRACE("%ld %u %u %i %p %p\n", handle, uiProperty, uiDataType,
622 iValue, pftValue, str );
624 type = get_type( uiProperty );
625 if( type == VT_EMPTY || type != uiDataType )
626 return ERROR_DATATYPE_MISMATCH;
628 if( uiDataType == VT_LPSTR && !str->str.w )
629 return ERROR_INVALID_PARAMETER;
631 if( uiDataType == VT_FILETIME && !pftValue )
632 return ERROR_INVALID_PARAMETER;
634 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
635 if( !si )
636 return ERROR_INVALID_HANDLE;
638 prop = &si->property[uiProperty];
640 if( prop->vt == VT_EMPTY )
642 if( !si->update_count )
644 ret = ERROR_FUNCTION_FAILED;
645 goto end;
647 si->update_count--;
648 prop->vt = type;
650 else if( prop->vt != type )
651 goto end;
653 switch( type )
655 case VT_I4:
656 prop->u.lVal = iValue;
657 break;
658 case VT_I2:
659 prop->u.iVal = iValue;
660 break;
661 case VT_FILETIME:
662 memcpy( &prop->u.filetime, pftValue, sizeof prop->u.filetime );
663 break;
664 case VT_LPSTR:
665 HeapFree( GetProcessHeap(), 0, prop->u.pszVal );
666 if( str->unicode )
668 len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
669 NULL, 0, NULL, NULL );
670 prop->u.pszVal = HeapAlloc( GetProcessHeap(), 0, len );
671 WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
672 prop->u.pszVal, len, NULL, NULL );
674 else
676 len = lstrlenA( str->str.a ) + 1;
677 prop->u.pszVal = HeapAlloc( GetProcessHeap(), 0, len );
678 lstrcpyA( prop->u.pszVal, str->str.a );
680 break;
683 end:
684 msiobj_release( &si->hdr );
685 return ret;
688 UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
689 UINT uiDataType, INT iValue, FILETIME* pftValue, LPWSTR szValue )
691 awstring str;
693 TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
694 iValue, pftValue, debugstr_w(szValue) );
696 str.unicode = TRUE;
697 str.str.w = szValue;
698 return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str );
701 UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
702 UINT uiDataType, INT iValue, FILETIME* pftValue, LPSTR szValue )
704 awstring str;
706 TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
707 iValue, pftValue, debugstr_a(szValue) );
709 str.unicode = FALSE;
710 str.str.a = szValue;
711 return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str );
714 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
716 IStream *stm = NULL;
717 MSISUMMARYINFO *si;
718 DWORD grfMode;
719 HRESULT r;
720 UINT ret = ERROR_FUNCTION_FAILED;
722 TRACE("%ld\n", handle );
724 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
725 if( !si )
726 return ERROR_INVALID_HANDLE;
728 grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
729 r = IStorage_CreateStream( si->db->storage, szSumInfo, grfMode, 0, 0, &stm );
730 if( SUCCEEDED(r) )
732 ret = save_summary_info( si, stm );
733 IStream_Release( stm );
735 msiobj_release( &si->hdr );
737 return ret;