schedsvc: Print an error if the service couldn't start monitoring the tasks directory.
[wine.git] / dlls / msi / suminfo.c
blob288ba402dc596fcad170c06813fdd39cc15cc068
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "wine/unicode.h"
33 #include "msi.h"
34 #include "msiquery.h"
35 #include "msidefs.h"
36 #include "objidl.h"
37 #include "propvarutil.h"
39 #include "msipriv.h"
40 #include "winemsi.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44 #include "pshpack1.h"
46 typedef struct {
47 WORD wByteOrder;
48 WORD wFormat;
49 DWORD dwOSVer;
50 CLSID clsID;
51 DWORD reserved;
52 } PROPERTYSETHEADER;
54 typedef struct {
55 FMTID fmtid;
56 DWORD dwOffset;
57 } FORMATIDOFFSET;
59 typedef struct {
60 DWORD cbSection;
61 DWORD cProperties;
62 } PROPERTYSECTIONHEADER;
64 typedef struct {
65 DWORD propid;
66 DWORD dwOffset;
67 } PROPERTYIDOFFSET;
69 typedef struct {
70 DWORD type;
71 union {
72 INT i4;
73 SHORT i2;
74 FILETIME ft;
75 struct {
76 DWORD len;
77 BYTE str[1];
78 } str;
79 } u;
80 } PROPERTY_DATA;
82 #include "poppack.h"
84 static HRESULT (WINAPI *pPropVariantChangeType)
85 (PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc,
86 PROPVAR_CHANGE_FLAGS flags, VARTYPE vt);
88 #define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER))
90 static void free_prop( PROPVARIANT *prop )
92 if (prop->vt == VT_LPSTR )
93 msi_free( prop->u.pszVal );
94 prop->vt = VT_EMPTY;
97 static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
99 MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg;
100 DWORD i;
102 for( i = 0; i < MSI_MAX_PROPS; i++ )
103 free_prop( &si->property[i] );
104 IStorage_Release( si->storage );
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( const 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 static UINT propvar_changetype(PROPVARIANT *changed, PROPVARIANT *property, VARTYPE vt)
153 HRESULT hr;
154 HMODULE propsys = LoadLibraryA("propsys.dll");
155 pPropVariantChangeType = (void *)GetProcAddress(propsys, "PropVariantChangeType");
157 if (!pPropVariantChangeType)
159 ERR("PropVariantChangeType function missing!\n");
160 return ERROR_FUNCTION_FAILED;
163 hr = pPropVariantChangeType(changed, property, 0, vt);
164 return (hr == S_OK) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
167 /* FIXME: doesn't deal with endian conversion */
168 static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz )
170 UINT type;
171 DWORD i, size;
172 PROPERTY_DATA *propdata;
173 PROPVARIANT property, *ptr;
174 PROPVARIANT changed;
175 PROPERTYIDOFFSET *idofs;
176 PROPERTYSECTIONHEADER *section_hdr;
178 section_hdr = (PROPERTYSECTIONHEADER*) &data[0];
179 idofs = (PROPERTYIDOFFSET*) &data[SECT_HDR_SIZE];
181 /* now set all the properties */
182 for( i = 0; i < section_hdr->cProperties; i++ )
184 if( idofs[i].propid >= MSI_MAX_PROPS )
186 ERR("Unknown property ID %d\n", idofs[i].propid );
187 break;
190 type = get_type( idofs[i].propid );
191 if( type == VT_EMPTY )
193 ERR("propid %d has unknown type\n", idofs[i].propid);
194 break;
197 propdata = (PROPERTY_DATA*) &data[ idofs[i].dwOffset ];
199 /* check we don't run off the end of the data */
200 size = sz - idofs[i].dwOffset - sizeof(DWORD);
201 if( sizeof(DWORD) > size ||
202 ( propdata->type == VT_FILETIME && sizeof(FILETIME) > size ) ||
203 ( propdata->type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) )
205 ERR("not enough data\n");
206 break;
209 property.vt = propdata->type;
210 if( propdata->type == VT_LPSTR )
212 LPSTR str = msi_alloc( propdata->u.str.len );
213 memcpy( str, propdata->u.str.str, propdata->u.str.len );
214 str[ propdata->u.str.len - 1 ] = 0;
215 property.u.pszVal = str;
217 else if( propdata->type == VT_FILETIME )
218 property.u.filetime = propdata->u.ft;
219 else if( propdata->type == VT_I2 )
220 property.u.iVal = propdata->u.i2;
221 else if( propdata->type == VT_I4 )
222 property.u.lVal = propdata->u.i4;
224 /* check the type is the same as we expect */
225 if( type != propdata->type )
227 propvar_changetype(&changed, &property, type);
228 ptr = &changed;
230 else
231 ptr = &property;
233 prop[ idofs[i].propid ] = *ptr;
237 static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
239 PROPERTYSETHEADER set_hdr;
240 FORMATIDOFFSET format_hdr;
241 PROPERTYSECTIONHEADER section_hdr;
242 LPBYTE data = NULL;
243 LARGE_INTEGER ofs;
244 ULONG count, sz;
245 HRESULT r;
247 TRACE("%p %p\n", si, stm);
249 /* read the header */
250 sz = sizeof set_hdr;
251 r = IStream_Read( stm, &set_hdr, sz, &count );
252 if( FAILED(r) || count != sz )
253 return ERROR_FUNCTION_FAILED;
255 if( set_hdr.wByteOrder != 0xfffe )
257 ERR("property set not big-endian %04X\n", set_hdr.wByteOrder);
258 return ERROR_FUNCTION_FAILED;
261 sz = sizeof format_hdr;
262 r = IStream_Read( stm, &format_hdr, sz, &count );
263 if( FAILED(r) || count != sz )
264 return ERROR_FUNCTION_FAILED;
266 /* check the format id is correct */
267 if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) )
268 return ERROR_FUNCTION_FAILED;
270 /* seek to the location of the section */
271 ofs.QuadPart = format_hdr.dwOffset;
272 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL );
273 if( FAILED(r) )
274 return ERROR_FUNCTION_FAILED;
276 /* read the section itself */
277 sz = SECT_HDR_SIZE;
278 r = IStream_Read( stm, &section_hdr, sz, &count );
279 if( FAILED(r) || count != sz )
280 return ERROR_FUNCTION_FAILED;
282 if( section_hdr.cProperties > MSI_MAX_PROPS )
284 ERR("too many properties %d\n", section_hdr.cProperties);
285 return ERROR_FUNCTION_FAILED;
288 data = msi_alloc( section_hdr.cbSection);
289 if( !data )
290 return ERROR_FUNCTION_FAILED;
292 memcpy( data, &section_hdr, SECT_HDR_SIZE );
294 /* read all the data in one go */
295 sz = section_hdr.cbSection - SECT_HDR_SIZE;
296 r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count );
297 if( SUCCEEDED(r) && count == sz )
298 read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE );
299 else
300 ERR("failed to read properties %d %d\n", count, sz);
302 msi_free( data );
303 return ERROR_SUCCESS;
306 static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val )
308 if( data )
310 data[ofs++] = val&0xff;
311 data[ofs++] = (val>>8)&0xff;
312 data[ofs++] = (val>>16)&0xff;
313 data[ofs++] = (val>>24)&0xff;
315 return 4;
318 static DWORD write_filetime( LPBYTE data, DWORD ofs, const FILETIME *ft )
320 write_dword( data, ofs, ft->dwLowDateTime );
321 write_dword( data, ofs + 4, ft->dwHighDateTime );
322 return 8;
325 static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str )
327 DWORD len = lstrlenA( str ) + 1;
328 write_dword( data, ofs, len );
329 if( data )
330 memcpy( &data[ofs + 4], str, len );
331 return (7 + len) & ~3;
334 static UINT write_property_to_data( const PROPVARIANT *prop, LPBYTE data )
336 DWORD sz = 0;
338 if( prop->vt == VT_EMPTY )
339 return sz;
341 /* add the type */
342 sz += write_dword( data, sz, prop->vt );
343 switch( prop->vt )
345 case VT_I2:
346 sz += write_dword( data, sz, prop->u.iVal );
347 break;
348 case VT_I4:
349 sz += write_dword( data, sz, prop->u.lVal );
350 break;
351 case VT_FILETIME:
352 sz += write_filetime( data, sz, &prop->u.filetime );
353 break;
354 case VT_LPSTR:
355 sz += write_string( data, sz, prop->u.pszVal );
356 break;
358 return sz;
361 static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm )
363 UINT ret = ERROR_FUNCTION_FAILED;
364 PROPERTYSETHEADER set_hdr;
365 FORMATIDOFFSET format_hdr;
366 PROPERTYSECTIONHEADER section_hdr;
367 PROPERTYIDOFFSET idofs[MSI_MAX_PROPS];
368 LPBYTE data = NULL;
369 ULONG count, sz;
370 HRESULT r;
371 int i;
373 /* write the header */
374 sz = sizeof set_hdr;
375 memset( &set_hdr, 0, sz );
376 set_hdr.wByteOrder = 0xfffe;
377 set_hdr.wFormat = 0;
378 set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */
379 /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */
380 set_hdr.reserved = 1;
381 r = IStream_Write( stm, &set_hdr, sz, &count );
382 if( FAILED(r) || count != sz )
383 return ret;
385 /* write the format header */
386 sz = sizeof format_hdr;
387 format_hdr.fmtid = FMTID_SummaryInformation;
388 format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr;
389 r = IStream_Write( stm, &format_hdr, sz, &count );
390 if( FAILED(r) || count != sz )
391 return ret;
393 /* add up how much space the data will take and calculate the offsets */
394 section_hdr.cbSection = sizeof section_hdr;
395 section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]);
396 section_hdr.cProperties = 0;
397 for( i = 0; i < MSI_MAX_PROPS; i++ )
399 sz = write_property_to_data( &si->property[i], NULL );
400 if( !sz )
401 continue;
402 idofs[ section_hdr.cProperties ].propid = i;
403 idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection;
404 section_hdr.cProperties++;
405 section_hdr.cbSection += sz;
408 data = msi_alloc_zero( section_hdr.cbSection );
410 sz = 0;
411 memcpy( &data[sz], &section_hdr, sizeof section_hdr );
412 sz += sizeof section_hdr;
414 memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] );
415 sz += section_hdr.cProperties * sizeof idofs[0];
417 /* write out the data */
418 for( i = 0; i < MSI_MAX_PROPS; i++ )
419 sz += write_property_to_data( &si->property[i], &data[sz] );
421 r = IStream_Write( stm, data, sz, &count );
422 msi_free( data );
423 if( FAILED(r) || count != sz )
424 return ret;
426 return ERROR_SUCCESS;
429 static MSISUMMARYINFO *create_suminfo( IStorage *stg, UINT update_count )
431 MSISUMMARYINFO *si;
433 if (!(si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, sizeof(MSISUMMARYINFO), MSI_CloseSummaryInfo )))
434 return NULL;
436 si->update_count = update_count;
437 IStorage_AddRef( stg );
438 si->storage = stg;
440 return si;
443 UINT msi_get_suminfo( IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **ret )
445 IStream *stm;
446 MSISUMMARYINFO *si;
447 HRESULT hr;
448 UINT r;
450 TRACE("%p, %u\n", stg, uiUpdateCount);
452 if (!(si = create_suminfo( stg, uiUpdateCount ))) return ERROR_OUTOFMEMORY;
454 hr = IStorage_OpenStream( si->storage, szSumInfo, 0, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stm );
455 if (FAILED( hr ))
457 msiobj_release( &si->hdr );
458 return ERROR_FUNCTION_FAILED;
461 r = load_summary_info( si, stm );
462 IStream_Release( stm );
463 if (r != ERROR_SUCCESS)
465 msiobj_release( &si->hdr );
466 return r;
469 *ret = si;
470 return ERROR_SUCCESS;
473 UINT msi_get_db_suminfo( MSIDATABASE *db, UINT uiUpdateCount, MSISUMMARYINFO **ret )
475 IStream *stm;
476 MSISUMMARYINFO *si;
477 UINT r;
479 if (!(si = create_suminfo( db->storage, uiUpdateCount ))) return ERROR_OUTOFMEMORY;
481 r = msi_get_stream( db, szSumInfo, &stm );
482 if (r != ERROR_SUCCESS)
484 msiobj_release( &si->hdr );
485 return r;
488 r = load_summary_info( si, stm );
489 IStream_Release( stm );
490 if (r != ERROR_SUCCESS)
492 msiobj_release( &si->hdr );
493 return r;
496 *ret = si;
497 return ERROR_SUCCESS;
500 UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
501 LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
503 MSISUMMARYINFO *si;
504 MSIDATABASE *db;
505 UINT ret;
507 TRACE("%d %s %d %p\n", hDatabase, debugstr_w(szDatabase),
508 uiUpdateCount, pHandle);
510 if( !pHandle )
511 return ERROR_INVALID_PARAMETER;
513 if( szDatabase && szDatabase[0] )
515 LPCWSTR persist = uiUpdateCount ? MSIDBOPEN_TRANSACT : MSIDBOPEN_READONLY;
517 ret = MSI_OpenDatabaseW( szDatabase, persist, &db );
518 if( ret != ERROR_SUCCESS )
519 return ret;
521 else
523 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
524 if( !db )
526 MSIHANDLE remote, remote_suminfo;
528 if (!(remote = msi_get_remote(hDatabase)))
529 return ERROR_INVALID_HANDLE;
531 ret = remote_DatabaseGetSummaryInformation(remote, uiUpdateCount, &remote_suminfo);
532 if (!ret)
533 *pHandle = alloc_msi_remote_handle(remote_suminfo);
535 return ret;
539 ret = msi_get_suminfo( db->storage, uiUpdateCount, &si );
540 if (ret != ERROR_SUCCESS)
541 ret = msi_get_db_suminfo( db, uiUpdateCount, &si );
542 if (ret != ERROR_SUCCESS)
544 if ((si = create_suminfo( db->storage, uiUpdateCount )))
545 ret = ERROR_SUCCESS;
548 if (ret == ERROR_SUCCESS)
550 *pHandle = alloc_msihandle( &si->hdr );
551 if( *pHandle )
552 ret = ERROR_SUCCESS;
553 else
554 ret = ERROR_NOT_ENOUGH_MEMORY;
555 msiobj_release( &si->hdr );
558 msiobj_release( &db->hdr );
559 return ret;
562 UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase,
563 LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
565 LPWSTR szwDatabase = NULL;
566 UINT ret;
568 TRACE("%d %s %d %p\n", hDatabase, debugstr_a(szDatabase),
569 uiUpdateCount, pHandle);
571 if( szDatabase )
573 szwDatabase = strdupAtoW( szDatabase );
574 if( !szwDatabase )
575 return ERROR_FUNCTION_FAILED;
578 ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle);
580 msi_free( szwDatabase );
582 return ret;
585 UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, PUINT pCount)
587 MSISUMMARYINFO *si;
589 TRACE("%d %p\n", hSummaryInfo, pCount);
591 si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
592 if( !si )
593 return ERROR_INVALID_HANDLE;
595 if( pCount )
596 *pCount = get_property_count( si->property );
597 msiobj_release( &si->hdr );
599 return ERROR_SUCCESS;
602 static UINT get_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT *puiDataType, INT *piValue,
603 FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
605 PROPVARIANT *prop;
606 UINT ret = ERROR_SUCCESS;
608 prop = &si->property[uiProperty];
610 if( puiDataType )
611 *puiDataType = prop->vt;
613 switch( prop->vt )
615 case VT_I2:
616 if( piValue )
617 *piValue = prop->u.iVal;
618 break;
619 case VT_I4:
620 if( piValue )
621 *piValue = prop->u.lVal;
622 break;
623 case VT_LPSTR:
624 if( pcchValueBuf )
626 DWORD len = 0;
628 if( str->unicode )
630 len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, NULL, 0 ) - 1;
631 MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, str->str.w, *pcchValueBuf );
633 else
635 len = lstrlenA( prop->u.pszVal );
636 if( str->str.a )
637 lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf );
639 if (len >= *pcchValueBuf)
640 ret = ERROR_MORE_DATA;
641 *pcchValueBuf = len;
643 break;
644 case VT_FILETIME:
645 if( pftValue )
646 *pftValue = prop->u.filetime;
647 break;
648 case VT_EMPTY:
649 break;
650 default:
651 FIXME("Unknown property variant type\n");
652 break;
654 return ret;
657 LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty )
659 PROPVARIANT *prop;
661 if ( uiProperty >= MSI_MAX_PROPS )
662 return NULL;
663 prop = &si->property[uiProperty];
664 if( prop->vt != VT_LPSTR )
665 return NULL;
666 return strdupAtoW( prop->u.pszVal );
669 INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty )
671 PROPVARIANT *prop;
673 if ( uiProperty >= MSI_MAX_PROPS )
674 return -1;
675 prop = &si->property[uiProperty];
676 if( prop->vt != VT_I4 )
677 return -1;
678 return prop->u.lVal;
681 LPWSTR msi_get_suminfo_product( IStorage *stg )
683 MSISUMMARYINFO *si;
684 LPWSTR prod;
685 UINT r;
687 r = msi_get_suminfo( stg, 0, &si );
688 if (r != ERROR_SUCCESS)
690 ERR("no summary information!\n");
691 return NULL;
693 prod = msi_suminfo_dup_string( si, PID_REVNUMBER );
694 msiobj_release( &si->hdr );
695 return prod;
698 UINT WINAPI MsiSummaryInfoGetPropertyA(
699 MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
700 FILETIME *pftValue, LPSTR szValueBuf, LPDWORD pcchValueBuf)
702 MSISUMMARYINFO *si;
703 awstring str;
704 UINT r;
706 TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType,
707 piValue, pftValue, szValueBuf, pcchValueBuf );
709 if (uiProperty >= MSI_MAX_PROPS)
711 if (puiDataType) *puiDataType = VT_EMPTY;
712 return ERROR_UNKNOWN_PROPERTY;
715 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
716 return ERROR_INVALID_HANDLE;
718 str.unicode = FALSE;
719 str.str.a = szValueBuf;
721 r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf );
722 msiobj_release( &si->hdr );
723 return r;
726 UINT WINAPI MsiSummaryInfoGetPropertyW(
727 MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
728 FILETIME *pftValue, LPWSTR szValueBuf, LPDWORD pcchValueBuf)
730 MSISUMMARYINFO *si;
731 awstring str;
732 UINT r;
734 TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType,
735 piValue, pftValue, szValueBuf, pcchValueBuf );
737 if (uiProperty >= MSI_MAX_PROPS)
739 if (puiDataType) *puiDataType = VT_EMPTY;
740 return ERROR_UNKNOWN_PROPERTY;
743 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
744 return ERROR_INVALID_HANDLE;
746 str.unicode = TRUE;
747 str.str.w = szValueBuf;
749 r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf );
750 msiobj_release( &si->hdr );
751 return r;
754 static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type,
755 INT iValue, FILETIME *pftValue, awcstring *str )
757 PROPVARIANT *prop;
758 UINT len;
760 TRACE("%p, %u, %u, %d, %p, %p\n", si, uiProperty, type, iValue, pftValue, str );
762 prop = &si->property[uiProperty];
764 if( prop->vt == VT_EMPTY )
766 if( !si->update_count )
767 return ERROR_FUNCTION_FAILED;
769 si->update_count--;
771 else if( prop->vt != type )
772 return ERROR_SUCCESS;
774 free_prop( prop );
775 prop->vt = type;
776 switch( type )
778 case VT_I4:
779 prop->u.lVal = iValue;
780 break;
781 case VT_I2:
782 prop->u.iVal = iValue;
783 break;
784 case VT_FILETIME:
785 prop->u.filetime = *pftValue;
786 break;
787 case VT_LPSTR:
788 if( str->unicode )
790 len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
791 NULL, 0, NULL, NULL );
792 prop->u.pszVal = msi_alloc( len );
793 WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
794 prop->u.pszVal, len, NULL, NULL );
796 else
798 len = lstrlenA( str->str.a ) + 1;
799 prop->u.pszVal = msi_alloc( len );
800 lstrcpyA( prop->u.pszVal, str->str.a );
802 break;
805 return ERROR_SUCCESS;
808 UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
809 INT iValue, FILETIME *pftValue, LPCWSTR szValue )
811 awcstring str;
812 MSISUMMARYINFO *si;
813 UINT type, ret;
815 TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue,
816 debugstr_w(szValue) );
818 type = get_type( uiProperty );
819 if( type == VT_EMPTY || type != uiDataType )
820 return ERROR_DATATYPE_MISMATCH;
822 if( uiDataType == VT_LPSTR && !szValue )
823 return ERROR_INVALID_PARAMETER;
825 if( uiDataType == VT_FILETIME && !pftValue )
826 return ERROR_INVALID_PARAMETER;
828 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
829 return ERROR_INVALID_HANDLE;
831 str.unicode = TRUE;
832 str.str.w = szValue;
834 ret = set_prop( si, uiProperty, type, iValue, pftValue, &str );
835 msiobj_release( &si->hdr );
836 return ret;
839 UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
840 INT iValue, FILETIME *pftValue, LPCSTR szValue )
842 awcstring str;
843 MSISUMMARYINFO *si;
844 UINT type, ret;
846 TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue,
847 debugstr_a(szValue) );
849 type = get_type( uiProperty );
850 if( type == VT_EMPTY || type != uiDataType )
851 return ERROR_DATATYPE_MISMATCH;
853 if( uiDataType == VT_LPSTR && !szValue )
854 return ERROR_INVALID_PARAMETER;
856 if( uiDataType == VT_FILETIME && !pftValue )
857 return ERROR_INVALID_PARAMETER;
859 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
860 return ERROR_INVALID_HANDLE;
862 str.unicode = FALSE;
863 str.str.a = szValue;
865 ret = set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str );
866 msiobj_release( &si->hdr );
867 return ret;
870 static UINT suminfo_persist( MSISUMMARYINFO *si )
872 UINT ret = ERROR_FUNCTION_FAILED;
873 IStream *stm = NULL;
874 DWORD grfMode;
875 HRESULT r;
877 grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
878 r = IStorage_CreateStream( si->storage, szSumInfo, grfMode, 0, 0, &stm );
879 if( SUCCEEDED(r) )
881 ret = save_summary_info( si, stm );
882 IStream_Release( stm );
884 return ret;
887 static void parse_filetime( LPCWSTR str, FILETIME *ft )
889 SYSTEMTIME lt, utc;
890 const WCHAR *p = str;
891 WCHAR *end;
893 memset( &lt, 0, sizeof(lt) );
895 /* YYYY/MM/DD hh:mm:ss */
897 while (isspaceW( *p )) p++;
899 lt.wYear = strtolW( p, &end, 10 );
900 if (*end != '/') return;
901 p = end + 1;
903 lt.wMonth = strtolW( p, &end, 10 );
904 if (*end != '/') return;
905 p = end + 1;
907 lt.wDay = strtolW( p, &end, 10 );
908 if (*end != ' ') return;
909 p = end + 1;
911 while (isspaceW( *p )) p++;
913 lt.wHour = strtolW( p, &end, 10 );
914 if (*end != ':') return;
915 p = end + 1;
917 lt.wMinute = strtolW( p, &end, 10 );
918 if (*end != ':') return;
919 p = end + 1;
921 lt.wSecond = strtolW( p, &end, 10 );
923 TzSpecificLocalTimeToSystemTime( NULL, &lt, &utc );
924 SystemTimeToFileTime( &utc, ft );
927 static UINT parse_prop( LPCWSTR prop, LPCWSTR value, UINT *pid, INT *int_value,
928 FILETIME *ft_value, awcstring *str_value )
930 *pid = atoiW( prop );
931 switch (*pid)
933 case PID_CODEPAGE:
934 case PID_WORDCOUNT:
935 case PID_CHARCOUNT:
936 case PID_SECURITY:
937 case PID_PAGECOUNT:
938 *int_value = atoiW( value );
939 break;
941 case PID_LASTPRINTED:
942 case PID_CREATE_DTM:
943 case PID_LASTSAVE_DTM:
944 parse_filetime( value, ft_value );
945 break;
947 case PID_SUBJECT:
948 case PID_AUTHOR:
949 case PID_KEYWORDS:
950 case PID_COMMENTS:
951 case PID_TEMPLATE:
952 case PID_LASTAUTHOR:
953 case PID_REVNUMBER:
954 case PID_APPNAME:
955 case PID_TITLE:
956 str_value->str.w = value;
957 str_value->unicode = TRUE;
958 break;
960 default:
961 WARN("unhandled prop id %u\n", *pid);
962 return ERROR_FUNCTION_FAILED;
965 return ERROR_SUCCESS;
968 UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns )
970 UINT r;
971 int i, j;
972 MSISUMMARYINFO *si;
974 r = msi_get_suminfo( db->storage, num_records * (num_columns / 2), &si );
975 if (r != ERROR_SUCCESS)
977 if (!(si = create_suminfo( db->storage, num_records * (num_columns / 2) )))
978 return ERROR_OUTOFMEMORY;
979 r = ERROR_SUCCESS;
982 for (i = 0; i < num_records; i++)
984 for (j = 0; j < num_columns; j += 2)
986 UINT pid;
987 INT int_value = 0;
988 FILETIME ft_value;
989 awcstring str_value;
991 r = parse_prop( records[i][j], records[i][j + 1], &pid, &int_value, &ft_value, &str_value );
992 if (r != ERROR_SUCCESS)
993 goto end;
995 r = set_prop( si, pid, get_type(pid), int_value, &ft_value, &str_value );
996 if (r != ERROR_SUCCESS)
997 goto end;
1001 end:
1002 if (r == ERROR_SUCCESS)
1003 r = suminfo_persist( si );
1005 msiobj_release( &si->hdr );
1006 return r;
1009 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
1011 MSISUMMARYINFO *si;
1012 UINT ret;
1014 TRACE("%d\n", handle );
1016 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
1017 if( !si )
1018 return ERROR_INVALID_HANDLE;
1020 ret = suminfo_persist( si );
1022 msiobj_release( &si->hdr );
1023 return ret;
1026 UINT WINAPI MsiCreateTransformSummaryInfoA( MSIHANDLE db, MSIHANDLE db_ref, LPCSTR transform, int error, int validation )
1028 UINT r;
1029 WCHAR *transformW = NULL;
1031 TRACE("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_a(transform), error, validation);
1033 if (transform && !(transformW = strdupAtoW( transform )))
1034 return ERROR_OUTOFMEMORY;
1036 r = MsiCreateTransformSummaryInfoW( db, db_ref, transformW, error, validation );
1037 msi_free( transformW );
1038 return r;
1041 UINT WINAPI MsiCreateTransformSummaryInfoW( MSIHANDLE db, MSIHANDLE db_ref, LPCWSTR transform, int error, int validation )
1043 FIXME("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_w(transform), error, validation);
1044 return ERROR_FUNCTION_FAILED;
1047 UINT msi_load_suminfo_properties( MSIPACKAGE *package )
1049 static const WCHAR packagecodeW[] = {'P','a','c','k','a','g','e','C','o','d','e',0};
1050 MSISUMMARYINFO *si;
1051 WCHAR *package_code;
1052 UINT r, len;
1053 awstring str;
1054 INT count;
1056 r = msi_get_suminfo( package->db->storage, 0, &si );
1057 if (r != ERROR_SUCCESS)
1059 r = msi_get_db_suminfo( package->db, 0, &si );
1060 if (r != ERROR_SUCCESS)
1062 ERR("Unable to open summary information stream %u\n", r);
1063 return r;
1067 str.unicode = TRUE;
1068 str.str.w = NULL;
1069 len = 0;
1070 r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len );
1071 if (r != ERROR_MORE_DATA)
1073 WARN("Unable to query revision number %u\n", r);
1074 msiobj_release( &si->hdr );
1075 return ERROR_FUNCTION_FAILED;
1078 len++;
1079 if (!(package_code = msi_alloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
1080 str.str.w = package_code;
1082 r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len );
1083 if (r != ERROR_SUCCESS)
1085 msi_free( package_code );
1086 msiobj_release( &si->hdr );
1087 return r;
1090 r = msi_set_property( package->db, packagecodeW, package_code, len );
1091 msi_free( package_code );
1093 count = 0;
1094 get_prop( si, PID_WORDCOUNT, NULL, &count, NULL, NULL, NULL );
1095 package->WordCount = count;
1097 msiobj_release( &si->hdr );
1098 return r;