msi: Add support for exporting the _SummaryInformation table.

The _SummaryInformation table stores a lot of important information
about an MSI database.  This patch adds the ability to export that
table since, like _ForceCodepage, it is stored in a different format
than the other tables.

Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Erich E. Hoover 2019-03-15 10:03:57 +01:00 committed by Alexandre Julliard
parent 51d5242a5f
commit 79fd42fc1a
3 changed files with 133 additions and 6 deletions

View File

@ -974,24 +974,35 @@ static UINT msi_export_forcecodepage( HANDLE handle, UINT codepage )
{
static const char fmt[] = "\r\n\r\n%u\t_ForceCodepage\r\n";
char data[sizeof(fmt) + 10];
DWORD sz;
DWORD sz = sprintf( data, fmt, codepage );
sprintf( data, fmt, codepage );
sz = lstrlenA(data) + 1;
if (!WriteFile(handle, data, sz, &sz, NULL))
return ERROR_FUNCTION_FAILED;
return ERROR_SUCCESS;
}
static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
LPCWSTR folder, LPCWSTR file )
static UINT msi_export_summaryinformation( MSIDATABASE *db, HANDLE handle )
{
static const char header[] = "PropertyId\tValue\r\n"
"i2\tl255\r\n"
"_SummaryInformation\tPropertyId\r\n";
DWORD sz = ARRAY_SIZE(header) - 1;
if (!WriteFile(handle, header, sz, &sz, NULL))
return ERROR_WRITE_FAULT;
return msi_export_suminfo( db, handle );
}
static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table, LPCWSTR folder, LPCWSTR file )
{
static const WCHAR query[] = {
's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','%','s',0 };
static const WCHAR forcecodepage[] = {
'_','F','o','r','c','e','C','o','d','e','p','a','g','e',0 };
static const WCHAR summaryinformation[] = {
'_','S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',0 };
MSIRECORD *rec = NULL;
MSIQUERY *view = NULL;
LPWSTR filename;
@ -1026,6 +1037,12 @@ static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
goto done;
}
if (!strcmpW( table, summaryinformation ))
{
r = msi_export_summaryinformation( db, handle );
goto done;
}
r = MSI_OpenQuery( db, &view, query, table );
if (r == ERROR_SUCCESS)
{

View File

@ -961,6 +961,7 @@ extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) DECL
extern INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) DECLSPEC_HIDDEN;
extern LPWSTR msi_get_suminfo_product( IStorage *stg ) DECLSPEC_HIDDEN;
extern UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ) DECLSPEC_HIDDEN;
extern UINT msi_export_suminfo( MSIDATABASE *db, HANDLE handle ) DECLSPEC_HIDDEN;
extern UINT msi_load_suminfo_properties( MSIPACKAGE *package ) DECLSPEC_HIDDEN;
/* undocumented functions */

View File

@ -23,6 +23,7 @@
#define COBJMACROS
#define NONAMELESSUNION
#include "stdio.h"
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
@ -1096,6 +1097,114 @@ end:
return r;
}
static UINT save_prop( MSISUMMARYINFO *si, HANDLE handle, UINT row )
{
static const char fmt_systemtime[] = "%04u/%02u/%02u %02u:%02u:%02u";
char data[36]; /* largest string: YYYY/MM/DD hh:mm:ss */
static const char fmt_begin[] = "%u\t";
static const char data_end[] = "\r\n";
static const char fmt_int[] = "%u";
UINT r, data_type, len;
SYSTEMTIME system_time;
FILETIME file_time;
INT int_value;
awstring str;
DWORD sz;
str.unicode = FALSE;
str.str.a = NULL;
len = 0;
r = get_prop( si, row, &data_type, &int_value, &file_time, &str, &len );
if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
return r;
if (data_type == VT_EMPTY)
return ERROR_SUCCESS; /* property not set */
sz = sprintf( data, fmt_begin, row );
if (!WriteFile( handle, data, sz, &sz, NULL ))
return ERROR_WRITE_FAULT;
switch( data_type )
{
case VT_I2:
case VT_I4:
sz = sprintf( data, fmt_int, int_value );
if (!WriteFile( handle, data, sz, &sz, NULL ))
return ERROR_WRITE_FAULT;
break;
case VT_LPSTR:
len++;
if (!(str.str.a = msi_alloc( len )))
return ERROR_OUTOFMEMORY;
r = get_prop( si, row, NULL, NULL, NULL, &str, &len );
if (r != ERROR_SUCCESS)
{
msi_free( str.str.a );
return r;
}
sz = len;
if (!WriteFile( handle, str.str.a, sz, &sz, NULL ))
{
msi_free( str.str.a );
return ERROR_WRITE_FAULT;
}
msi_free( str.str.a );
break;
case VT_FILETIME:
if (!FileTimeToSystemTime( &file_time, &system_time ))
return ERROR_FUNCTION_FAILED;
sz = sprintf( data, fmt_systemtime, system_time.wYear, system_time.wMonth,
system_time.wDay, system_time.wHour, system_time.wMinute,
system_time.wSecond );
if (!WriteFile( handle, data, sz, &sz, NULL ))
return ERROR_WRITE_FAULT;
break;
case VT_EMPTY:
/* cannot reach here, property not set */
break;
default:
FIXME( "Unknown property variant type\n" );
return ERROR_FUNCTION_FAILED;
}
sz = ARRAY_SIZE(data_end) - 1;
if (!WriteFile( handle, data_end, sz, &sz, NULL ))
return ERROR_WRITE_FAULT;
return ERROR_SUCCESS;
}
UINT msi_export_suminfo( MSIDATABASE *db, HANDLE handle )
{
UINT i, r, num_rows;
MSISUMMARYINFO *si;
r = msi_get_suminfo( db->storage, 0, &si );
if (r != ERROR_SUCCESS)
r = msi_get_db_suminfo( db, 0, &si );
if (r != ERROR_SUCCESS)
return r;
num_rows = get_property_count( si->property );
if (!num_rows)
{
msiobj_release( &si->hdr );
return ERROR_FUNCTION_FAILED;
}
for (i = 0; i < num_rows; i++)
{
r = save_prop( si, handle, i );
if (r != ERROR_SUCCESS)
{
msiobj_release( &si->hdr );
return r;
}
}
msiobj_release( &si->hdr );
return ERROR_SUCCESS;
}
UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
{
MSISUMMARYINFO *si;