From: "Erich E. Hoover" erich.e.hoover@gmail.com
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.
v2: Avoid lstrlenA calls.
Signed-off-by: Erich E. Hoover erich.e.hoover@gmail.com Signed-off-by: Hans Leidekker hans@codeweavers.com --- dlls/msi/database.c | 29 +++++++++--- dlls/msi/msipriv.h | 1 + dlls/msi/suminfo.c | 109 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 6 deletions(-)
diff --git a/dlls/msi/database.c b/dlls/msi/database.c index b8ec39322b..589dce510d 100644 --- a/dlls/msi/database.c +++ b/dlls/msi/database.c @@ -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; - - sprintf( data, fmt, codepage ); + DWORD sz = 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) { diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 4b2b65a13b..39219a646f 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -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 */ diff --git a/dlls/msi/suminfo.c b/dlls/msi/suminfo.c index 98f6330d9f..c812ae09a4 100644 --- a/dlls/msi/suminfo.c +++ b/dlls/msi/suminfo.c @@ -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;