Release 20050930.
[wine/gsoc-2012-control.git] / dlls / msi / suminfo.c
blob1dbee575b0afa2bfee2336710c70aa281c8e84f3
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 20
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 #define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER))
84 typedef struct tagMSISUMMARYINFO
86 MSIOBJECTHDR hdr;
87 MSIDATABASE *db;
88 DWORD update_count;
89 PROPVARIANT property[MSI_MAX_PROPS];
90 } MSISUMMARYINFO;
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 msi_free( prop->u.pszVal );
99 prop->vt = VT_EMPTY;
102 static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
104 MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg;
105 DWORD i;
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 )
114 switch( uiProperty )
116 case PID_CODEPAGE:
117 return VT_I2;
119 case PID_SUBJECT:
120 case PID_AUTHOR:
121 case PID_KEYWORDS:
122 case PID_COMMENTS:
123 case PID_TEMPLATE:
124 case PID_LASTAUTHOR:
125 case PID_REVNUMBER:
126 case PID_APPNAME:
127 case PID_TITLE:
128 return VT_LPSTR;
130 case PID_LASTPRINTED:
131 case PID_CREATE_DTM:
132 case PID_LASTSAVE_DTM:
133 return VT_FILETIME;
135 case PID_WORDCOUNT:
136 case PID_CHARCOUNT:
137 case PID_SECURITY:
138 case PID_PAGECOUNT:
139 return VT_I4;
141 return VT_EMPTY;
144 static UINT get_property_count( PROPVARIANT *property )
146 UINT i, n = 0;
148 if( !property )
149 return n;
150 for( i = 0; i < MSI_MAX_PROPS; i++ )
151 if( property[i].vt != VT_EMPTY )
152 n++;
153 return n;
156 /* FIXME: doesn't deal with endian conversion */
157 static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz )
159 UINT type;
160 DWORD i;
161 int size;
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);
177 break;
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);
186 break;
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");
196 break;
199 if( idofs[i].propid >= MSI_MAX_PROPS )
201 ERR("Unknown property ID %ld\n", idofs[i].propid );
202 break;
205 property = &prop[ idofs[i].propid ];
206 property->vt = type;
208 if( type == VT_LPSTR )
210 LPSTR str = msi_alloc( 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;
230 LPBYTE data = NULL;
231 LARGE_INTEGER ofs;
232 ULONG count, sz;
233 HRESULT r;
235 TRACE("%p %p\n", si, stm);
237 /* read the header */
238 sz = sizeof set_hdr;
239 r = IStream_Read( stm, &set_hdr, sz, &count );
240 if( FAILED(r) || count != sz )
241 return ret;
243 if( set_hdr.wByteOrder != 0xfffe )
245 ERR("property set not big-endian %04X\n", set_hdr.wByteOrder);
246 return ret;
249 sz = sizeof format_hdr;
250 r = IStream_Read( stm, &format_hdr, sz, &count );
251 if( FAILED(r) || count != sz )
252 return ret;
254 /* check the format id is correct */
255 if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) )
256 return ret;
258 /* seek to the location of the section */
259 ofs.QuadPart = format_hdr.dwOffset;
260 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL );
261 if( FAILED(r) )
262 return ret;
264 /* read the section itself */
265 sz = SECT_HDR_SIZE;
266 r = IStream_Read( stm, &section_hdr, sz, &count );
267 if( FAILED(r) || count != sz )
268 return ret;
270 if( section_hdr.cProperties > MSI_MAX_PROPS )
272 ERR("too many properties %ld\n", section_hdr.cProperties);
273 return ret;
276 data = msi_alloc( section_hdr.cbSection);
277 if( !data )
278 return ret;
280 memcpy( data, &section_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 );
287 else
288 ERR("failed to read properties %ld %ld\n", count, sz);
290 msi_free( data );
291 return ret;
294 static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val )
296 if( data )
298 data[ofs++] = val&0xff;
299 data[ofs++] = (val>>8)&0xff;
300 data[ofs++] = (val>>16)&0xff;
301 data[ofs++] = (val>>24)&0xff;
303 return 4;
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 );
310 return 8;
313 static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str )
315 DWORD len = lstrlenA( str ) + 1;
316 write_dword( data, ofs, len );
317 if( data )
318 memcpy( &data[ofs + 4], str, len );
319 return (7 + len) & ~3;
322 static UINT write_property_to_data( PROPVARIANT *prop, LPBYTE data )
324 DWORD sz = 0;
326 if( prop->vt == VT_EMPTY )
327 return sz;
329 /* add the type */
330 sz += write_dword( data, sz, prop->vt );
331 switch( prop->vt )
333 case VT_I2:
334 sz += write_dword( data, sz, prop->u.iVal );
335 break;
336 case VT_I4:
337 sz += write_dword( data, sz, prop->u.lVal );
338 break;
339 case VT_FILETIME:
340 sz += write_filetime( data, sz, &prop->u.filetime );
341 break;
342 case VT_LPSTR:
343 sz += write_string( data, sz, prop->u.pszVal );
344 break;
346 return sz;
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];
356 LPBYTE data = NULL;
357 ULONG count, sz;
358 HRESULT r;
359 int i, n;
361 /* write the header */
362 sz = sizeof set_hdr;
363 memset( &set_hdr, 0, sz );
364 set_hdr.wByteOrder = 0xfffe;
365 set_hdr.wFormat = 0;
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 )
371 return ret;
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 )
379 return ret;
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;
385 n = 0;
386 for( i = 0; i < MSI_MAX_PROPS; i++ )
388 sz = write_property_to_data( &si->property[i], NULL );
389 if( !sz )
390 continue;
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 = msi_alloc_zero( section_hdr.cbSection );
399 sz = 0;
400 memcpy( &data[sz], &section_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 msi_free( data );
412 if( FAILED(r) || count != sz )
413 return ret;
415 return ERROR_SUCCESS;
418 UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
419 LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
421 UINT ret = ERROR_SUCCESS;
422 IStream *stm = NULL;
423 MSISUMMARYINFO *si;
424 MSIHANDLE handle;
425 MSIDATABASE *db;
426 DWORD grfMode;
427 HRESULT r;
429 TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
430 uiUpdateCount, pHandle);
432 if( !pHandle )
433 return ERROR_INVALID_PARAMETER;
435 if( szDatabase )
437 UINT res;
439 res = MSI_OpenDatabaseW(szDatabase, NULL, &db);
440 if( res != ERROR_SUCCESS )
441 return res;
443 else
445 db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
446 if( !db )
447 return ERROR_INVALID_PARAMETER;
450 si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO,
451 sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
452 if( !si )
454 ret = ERROR_FUNCTION_FAILED;
455 goto end;
458 msiobj_addref( &db->hdr );
459 si->db = db;
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 );
466 if( SUCCEEDED(r) )
468 load_summary_info( si, stm );
469 IStream_Release( stm );
472 handle = alloc_msihandle( &si->hdr );
473 if( handle )
474 *pHandle = handle;
475 else
476 ret = ERROR_FUNCTION_FAILED;
477 msiobj_release( &si->hdr );
479 end:
480 if( db )
481 msiobj_release( &db->hdr );
483 return ret;
486 UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase,
487 LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
489 LPWSTR szwDatabase = NULL;
490 UINT ret;
492 TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase),
493 uiUpdateCount, pHandle);
495 if( szDatabase )
497 szwDatabase = strdupAtoW( szDatabase );
498 if( !szwDatabase )
499 return ERROR_FUNCTION_FAILED;
502 ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle);
504 msi_free( szwDatabase );
506 return ret;
509 UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount)
511 MSISUMMARYINFO *si;
513 TRACE("%ld %p\n",hSummaryInfo, pCount);
515 si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
516 if( !si )
517 return ERROR_INVALID_HANDLE;
519 if( pCount )
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)
529 MSISUMMARYINFO *si;
530 PROPVARIANT *prop;
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 );
537 if( !si )
538 return ERROR_INVALID_HANDLE;
540 prop = &si->property[uiProperty];
542 if( puiDataType )
543 *puiDataType = prop->vt;
545 switch( prop->vt )
547 case VT_I2:
548 if( piValue )
549 *piValue = prop->u.iVal;
550 break;
551 case VT_I4:
552 if( piValue )
553 *piValue = prop->u.lVal;
554 break;
555 case VT_LPSTR:
556 if( pcchValueBuf )
558 DWORD len = 0;
560 if( str->unicode )
562 len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1,
563 str->str.w, *pcchValueBuf );
564 len--;
566 else
568 len = lstrlenA( prop->u.pszVal );
569 if( str->str.a )
570 lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf );
572 if (len >= *pcchValueBuf)
573 ret = ERROR_MORE_DATA;
574 *pcchValueBuf = len;
576 break;
577 case VT_FILETIME:
578 if( pftValue )
579 memcpy(pftValue, &prop->u.filetime, sizeof (FILETIME) );
580 break;
581 case VT_EMPTY:
582 break;
583 default:
584 FIXME("Unknown property variant type\n");
585 break;
587 msiobj_release( &si->hdr );
588 return ret;
591 UINT WINAPI MsiSummaryInfoGetPropertyA(
592 MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
593 FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf)
595 awstring str;
597 TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
598 piValue, pftValue, szValueBuf, pcchValueBuf );
600 str.unicode = FALSE;
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)
611 awstring str;
613 TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
614 piValue, pftValue, szValueBuf, pcchValueBuf );
616 str.unicode = TRUE;
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 )
626 MSISUMMARYINFO *si;
627 PROPVARIANT *prop;
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 );
644 if( !si )
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;
654 goto end;
656 si->update_count--;
658 else if( prop->vt != type )
659 goto end;
661 free_prop( prop );
662 prop->vt = type;
663 switch( type )
665 case VT_I4:
666 prop->u.lVal = iValue;
667 break;
668 case VT_I2:
669 prop->u.iVal = iValue;
670 break;
671 case VT_FILETIME:
672 memcpy( &prop->u.filetime, pftValue, sizeof prop->u.filetime );
673 break;
674 case VT_LPSTR:
675 if( str->unicode )
677 len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
678 NULL, 0, NULL, NULL );
679 prop->u.pszVal = msi_alloc( len );
680 WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
681 prop->u.pszVal, len, NULL, NULL );
683 else
685 len = lstrlenA( str->str.a ) + 1;
686 prop->u.pszVal = msi_alloc( len );
687 lstrcpyA( prop->u.pszVal, str->str.a );
689 break;
692 end:
693 msiobj_release( &si->hdr );
694 return ret;
697 UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
698 UINT uiDataType, INT iValue, FILETIME* pftValue, LPCWSTR szValue )
700 awcstring str;
702 TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
703 iValue, pftValue, debugstr_w(szValue) );
705 str.unicode = TRUE;
706 str.str.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 )
713 awcstring str;
715 TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
716 iValue, pftValue, debugstr_a(szValue) );
718 str.unicode = FALSE;
719 str.str.a = szValue;
720 return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str );
723 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
725 IStream *stm = NULL;
726 MSISUMMARYINFO *si;
727 DWORD grfMode;
728 HRESULT r;
729 UINT ret = ERROR_FUNCTION_FAILED;
731 TRACE("%ld\n", handle );
733 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
734 if( !si )
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 );
739 if( SUCCEEDED(r) )
741 ret = save_summary_info( si, stm );
742 IStream_Release( stm );
744 msiobj_release( &si->hdr );
746 return ret;