[MSI] Sync with Wine Staging 1.7.47. CORE-9924

svn path=/trunk/; revision=68461
This commit is contained in:
Amine Khaldi 2015-07-19 23:04:25 +00:00
parent 98c7de7d7a
commit 3acd6eee67
20 changed files with 986 additions and 633 deletions

View file

@ -65,7 +65,7 @@ set_module_type(msi win32dll)
target_link_libraries(msi uuid ${PSEH_LIB} wine)
add_dependencies(msi msi_idlheader)
add_delay_importlibs(msi odbccp32 crypt32 wintrust)
add_importlibs(msi advapi32 cabinet comctl32 gdi32 ole32 oleaut32 shell32 shlwapi urlmon user32 version wininet
add_importlibs(msi advapi32 cabinet comctl32 gdi32 ole32 oleaut32 shell32 shlwapi urlmon user32 version wininet mspatcha
#FIXME : should be in delayed imports
imagehlp
msvcrt

View file

@ -1262,7 +1262,7 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
load_file_hash(package, file);
load_file_disk_id(package, file);
TRACE("File Loaded (%s)\n",debugstr_w(file->File));
TRACE("File loaded (file %s sequence %u)\n", debugstr_w(file->File), file->Sequence);
list_add_tail( &package->files, &file->entry );
@ -1297,9 +1297,10 @@ static UINT load_media( MSIRECORD *row, LPVOID param )
const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
/* FIXME: load external cabinets and directory sources too */
if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
return ERROR_SUCCESS;
if (!cabinet || cabinet[0] != '#' || disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
return ERROR_SUCCESS;
return msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
}
static UINT load_all_media( MSIPACKAGE *package )
@ -1320,21 +1321,38 @@ static UINT load_all_media( MSIPACKAGE *package )
return r;
}
static UINT load_patch_disk_id( MSIPACKAGE *package, MSIFILEPATCH *patch )
{
static const WCHAR query[] =
{'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
'`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
'`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','u',0};
MSIRECORD *rec;
if (!(rec = MSI_QueryGetRecord( package->db, query, patch->Sequence )))
{
WARN("query failed\n");
return ERROR_FUNCTION_FAILED;
}
patch->disk_id = MSI_RecordGetInteger( rec, 1 );
msiobj_release( &rec->hdr );
return ERROR_SUCCESS;
}
static UINT load_patch(MSIRECORD *row, LPVOID param)
{
MSIPACKAGE *package = param;
MSIFILEPATCH *patch;
LPWSTR file_key;
const WCHAR *file_key;
patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
if (!patch)
return ERROR_NOT_ENOUGH_MEMORY;
file_key = msi_dup_record_field( row, 1 );
file_key = MSI_RecordGetString( row, 1 );
patch->File = msi_get_loaded_file( package, file_key );
msi_free(file_key);
if( !patch->File )
if (!patch->File)
{
ERR("Failed to find target for patch in File table\n");
msi_free(patch);
@ -1342,20 +1360,17 @@ static UINT load_patch(MSIRECORD *row, LPVOID param)
}
patch->Sequence = MSI_RecordGetInteger( row, 2 );
/* FIXME: The database should be properly transformed */
patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
patch->PatchSize = MSI_RecordGetInteger( row, 3 );
patch->Attributes = MSI_RecordGetInteger( row, 4 );
patch->IsApplied = FALSE;
/* FIXME:
* Header field - for patch validation.
* _StreamRef - External key into MsiPatchHeaders (instead of the header field)
*/
TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
load_patch_disk_id( package, patch );
TRACE("Patch loaded (file %s sequence %u)\n", debugstr_w(patch->File->File), patch->Sequence);
list_add_tail( &package->filepatches, &patch->entry );
@ -2060,7 +2075,6 @@ DWORD msi_get_disk_file_size( LPCWSTR filename )
return INVALID_FILE_SIZE;
size = GetFileSize( file, NULL );
TRACE("size is %u\n", size);
CloseHandle( file );
return size;
}
@ -2071,25 +2085,45 @@ BOOL msi_file_hash_matches( MSIFILE *file )
MSIFILEHASHINFO hash;
hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
r = MsiGetFileHashW( file->TargetPath, 0, &hash );
r = msi_get_filehash( file->TargetPath, &hash );
if (r != ERROR_SUCCESS)
return FALSE;
return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
}
static WCHAR *get_temp_dir( void )
static WCHAR *create_temp_dir( MSIDATABASE *db )
{
static UINT id;
WCHAR tmp[MAX_PATH], dir[MAX_PATH];
WCHAR *ret;
GetTempPathW( MAX_PATH, tmp );
for (;;)
if (!db->tempfolder)
{
if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
if (CreateDirectoryW( dir, NULL )) break;
WCHAR tmp[MAX_PATH];
UINT len = sizeof(tmp)/sizeof(tmp[0]);
if (msi_get_property( db, szTempFolder, tmp, &len ) ||
GetFileAttributesW( tmp ) != FILE_ATTRIBUTE_DIRECTORY)
{
GetTempPathW( MAX_PATH, tmp );
}
if (!(db->tempfolder = strdupW( tmp ))) return NULL;
}
return strdupW( dir );
if ((ret = msi_alloc( (strlenW( db->tempfolder ) + 20) * sizeof(WCHAR) )))
{
for (;;)
{
if (!GetTempFileNameW( db->tempfolder, szMsi, ++id, ret ))
{
msi_free( ret );
return NULL;
}
if (CreateDirectoryW( ret, NULL )) break;
}
}
return ret;
}
/*
@ -2140,18 +2174,20 @@ WCHAR *msi_build_directory_name( DWORD count, ... )
return dir;
}
BOOL msi_is_global_assembly( MSICOMPONENT *comp )
{
return comp->assembly && !comp->assembly->application;
}
static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
{
MSIASSEMBLY *assembly = file->Component->assembly;
TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
msi_free( file->TargetPath );
if (assembly && !assembly->application)
if (msi_is_global_assembly( file->Component ))
{
if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
MSIASSEMBLY *assembly = file->Component->assembly;
if (!assembly->tempdir) assembly->tempdir = create_temp_dir( package->db );
file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
msi_track_tempfile( package, file->TargetPath );
}
else
{
@ -2159,7 +2195,7 @@ static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
}
TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
}
static UINT calculate_file_cost( MSIPACKAGE *package )
@ -2187,6 +2223,7 @@ static UINT calculate_file_cost( MSIPACKAGE *package )
continue;
}
file_size = msi_get_disk_file_size( file->TargetPath );
TRACE("%s (size %u)\n", debugstr_w(file->TargetPath), file_size);
if (file->Version)
{

View file

@ -29,6 +29,8 @@ static HRESULT (WINAPI *pCreateAssemblyCacheNet40)( IAssemblyCache **, DWORD );
static HRESULT (WINAPI *pCreateAssemblyCacheSxs)( IAssemblyCache **, DWORD );
static HRESULT (WINAPI *pLoadLibraryShim)( LPCWSTR, LPCWSTR, LPVOID, HMODULE * );
static HRESULT (WINAPI *pGetFileVersion)( LPCWSTR, LPWSTR, DWORD, DWORD * );
static HRESULT (WINAPI *pCreateAssemblyNameObject)( IAssemblyName **, LPCWSTR, DWORD, LPVOID );
static HRESULT (WINAPI *pCreateAssemblyEnum)( IAssemblyEnum **, IUnknown *, IAssemblyName *, DWORD, LPVOID );
static HMODULE hfusion10, hfusion11, hfusion20, hfusion40, hmscoree, hsxs;
@ -70,8 +72,11 @@ static BOOL init_function_pointers( void )
pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" );
if (!pLoadLibraryShim( szFusion, szVersion40, NULL, &hfusion40 ))
{
pCreateAssemblyCacheNet40 = (void *)GetProcAddress( hfusion40, "CreateAssemblyCache" );
pCreateAssemblyNameObject = (void *)GetProcAddress( hfusion40, "CreateAssemblyNameObject" );
pCreateAssemblyEnum = (void *)GetProcAddress( hfusion40, "CreateAssemblyEnum" );
}
return TRUE;
}
@ -250,6 +255,70 @@ static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_n
return FALSE;
}
WCHAR *msi_get_assembly_path( MSIPACKAGE *package, const WCHAR *displayname )
{
HRESULT hr;
ASSEMBLY_INFO info;
IAssemblyCache *cache = package->cache_net[CLR_VERSION_V40];
if (!cache) return NULL;
memset( &info, 0, sizeof(info) );
info.cbAssemblyInfo = sizeof(info);
hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info );
if (hr != E_NOT_SUFFICIENT_BUFFER) return NULL;
if (!(info.pszCurrentAssemblyPathBuf = msi_alloc( info.cchBuf * sizeof(WCHAR) ))) return NULL;
hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info );
if (FAILED( hr ))
{
msi_free( info.pszCurrentAssemblyPathBuf );
return NULL;
}
TRACE("returning %s\n", debugstr_w(info.pszCurrentAssemblyPathBuf));
return info.pszCurrentAssemblyPathBuf;
}
IAssemblyEnum *msi_create_assembly_enum( MSIPACKAGE *package, const WCHAR *displayname )
{
HRESULT hr;
IAssemblyName *name;
IAssemblyEnum *ret;
WCHAR *str;
UINT len = 0;
if (!pCreateAssemblyNameObject || !pCreateAssemblyEnum) return NULL;
hr = pCreateAssemblyNameObject( &name, displayname, CANOF_PARSE_DISPLAY_NAME, NULL );
if (FAILED( hr )) return NULL;
hr = IAssemblyName_GetName( name, &len, NULL );
if (hr != E_NOT_SUFFICIENT_BUFFER || !(str = msi_alloc( len * sizeof(WCHAR) )))
{
IAssemblyName_Release( name );
return NULL;
}
hr = IAssemblyName_GetName( name, &len, str );
IAssemblyName_Release( name );
if (FAILED( hr ))
{
msi_free( str );
return NULL;
}
hr = pCreateAssemblyNameObject( &name, str, 0, NULL );
msi_free( str );
if (FAILED( hr )) return NULL;
hr = pCreateAssemblyEnum( &ret, NULL, name, ASM_CACHE_GAC, NULL );
IAssemblyName_Release( name );
if (FAILED( hr )) return NULL;
return ret;
}
static const WCHAR clr_version_v10[] = {'v','1','.','0','.','3','7','0','5',0};
static const WCHAR clr_version_v11[] = {'v','1','.','1','.','4','3','2','2',0};
static const WCHAR clr_version_v20[] = {'v','2','.','0','.','5','0','7','2','7',0};

View file

@ -1350,7 +1350,7 @@ static HRESULT session_invoke(
{
SessionObject *session = (SessionObject*)This;
WCHAR *szString;
DWORD dwLen;
DWORD dwLen = 0;
MSIHANDLE msiHandle;
LANGID langId;
UINT ret;

View file

@ -189,6 +189,35 @@ static void set_deferred_action_props( MSIPACKAGE *package, const WCHAR *deferre
msi_set_property( package->db, szProductCode, beg, end - beg );
}
WCHAR *msi_create_temp_file( MSIDATABASE *db )
{
WCHAR *ret;
if (!db->tempfolder)
{
WCHAR tmp[MAX_PATH];
UINT len = sizeof(tmp)/sizeof(tmp[0]);
if (msi_get_property( db, szTempFolder, tmp, &len ) ||
GetFileAttributesW( tmp ) != FILE_ATTRIBUTE_DIRECTORY)
{
GetTempPathW( MAX_PATH, tmp );
}
if (!(db->tempfolder = strdupW( tmp ))) return NULL;
}
if ((ret = msi_alloc( (strlenW( db->tempfolder ) + 20) * sizeof(WCHAR) )))
{
if (!GetTempFileNameW( db->tempfolder, szMsi, 0, ret ))
{
msi_free( ret );
return NULL;
}
}
return ret;
}
static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll )
{
static const WCHAR query[] = {
@ -196,38 +225,21 @@ static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL
'`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ',
'`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
MSIRECORD *row;
MSIBINARY *binary;
MSIBINARY *binary = NULL;
HANDLE file;
CHAR buffer[1024];
WCHAR fmt[MAX_PATH], tmpfile[MAX_PATH];
DWORD sz = MAX_PATH, write;
WCHAR *tmpfile;
DWORD sz, write;
UINT r;
if (msi_get_property(package->db, szTempFolder, fmt, &sz) != ERROR_SUCCESS ||
GetFileAttributesW(fmt) == INVALID_FILE_ATTRIBUTES) GetTempPathW(MAX_PATH, fmt);
if (!(tmpfile = msi_create_temp_file( package->db ))) return NULL;
if (!GetTempFileNameW( fmt, szMsi, 0, tmpfile ))
{
TRACE("unable to create temp file %s (%u)\n", debugstr_w(tmpfile), GetLastError());
return NULL;
}
if (!(row = MSI_QueryGetRecord( package->db, query, source ))) goto error;
if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) ))) goto error;
row = MSI_QueryGetRecord(package->db, query, source);
if (!row)
return NULL;
file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if (file == INVALID_HANDLE_VALUE) goto error;
if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) )))
{
msiobj_release( &row->hdr );
return NULL;
}
file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if (file == INVALID_HANDLE_VALUE)
{
msiobj_release( &row->hdr );
msi_free( binary );
return NULL;
}
do
{
sz = sizeof(buffer);
@ -241,13 +253,7 @@ static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL
} while (sz == sizeof buffer);
CloseHandle( file );
msiobj_release( &row->hdr );
if (r != ERROR_SUCCESS)
{
DeleteFileW( tmpfile );
msi_free( binary );
return NULL;
}
if (r != ERROR_SUCCESS) goto error;
/* keep a reference to prevent the dll from being unloaded */
if (dll && !(binary->module = LoadLibraryW( tmpfile )))
@ -255,9 +261,18 @@ static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL
WARN( "failed to load dll %s (%u)\n", debugstr_w( tmpfile ), GetLastError() );
}
binary->source = strdupW( source );
binary->tmpfile = strdupW( tmpfile );
binary->tmpfile = tmpfile;
list_add_tail( &package->binaries, &binary->entry );
msiobj_release( &row->hdr );
return binary;
error:
if (row) msiobj_release( &row->hdr );
DeleteFileW( tmpfile );
msi_free( tmpfile );
msi_free( binary );
return NULL;
}
static MSIBINARY *get_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll )
@ -1443,7 +1458,7 @@ HRESULT create_msi_custom_remote( IUnknown *pOuter, LPVOID *ppObj )
This->IWineMsiRemoteCustomAction_iface.lpVtbl = &msi_custom_remote_vtbl;
This->refs = 1;
*ppObj = This;
*ppObj = &This->IWineMsiRemoteCustomAction_iface;
return S_OK;
}

View file

@ -82,6 +82,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
DeleteFileW( db->deletefile );
msi_free( db->deletefile );
}
msi_free( db->tempfolder );
}
static HRESULT db_initialize( IStorage *stg, const GUID *clsid )
@ -137,8 +138,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
if( !pdb )
return ERROR_INVALID_PARAMETER;
if (szPersist - MSIDBOPEN_PATCHFILE >= MSIDBOPEN_READONLY &&
szPersist - MSIDBOPEN_PATCHFILE <= MSIDBOPEN_CREATEDIRECT)
if (szPersist - MSIDBOPEN_PATCHFILE <= MSIDBOPEN_CREATEDIRECT)
{
TRACE("Database is a patch\n");
szPersist -= MSIDBOPEN_PATCHFILE;
@ -2004,7 +2004,7 @@ HRESULT create_msi_remote_database( IUnknown *pOuter, LPVOID *ppObj )
This->database = 0;
This->refs = 1;
*ppObj = This;
*ppObj = &This->IWineMsiRemoteDatabase_iface;
return S_OK;
}

View file

@ -102,7 +102,6 @@ typedef struct
{
msi_dialog* dialog;
msi_control *parent;
DWORD attributes;
LPWSTR propval;
} radio_button_group_descr;
@ -476,42 +475,17 @@ static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name )
return MSI_QueryGetRecord( db, query, name );
}
static LPWSTR msi_create_tmp_path(void)
{
WCHAR tmp[MAX_PATH];
LPWSTR path = NULL;
DWORD len, r;
r = GetTempPathW( MAX_PATH, tmp );
if( !r )
return path;
len = lstrlenW( tmp ) + 20;
path = msi_alloc( len * sizeof (WCHAR) );
if( path )
{
r = GetTempFileNameW( tmp, szMsi, 0, path );
if (!r)
{
msi_free( path );
path = NULL;
}
}
return path;
}
static HANDLE msi_load_image( MSIDATABASE *db, LPCWSTR name, UINT type,
UINT cx, UINT cy, UINT flags )
{
MSIRECORD *rec = NULL;
MSIRECORD *rec;
HANDLE himage = NULL;
LPWSTR tmp;
UINT r;
TRACE("%p %s %u %u %08x\n", db, debugstr_w(name), cx, cy, flags);
tmp = msi_create_tmp_path();
if( !tmp )
return himage;
if (!(tmp = msi_create_temp_file( db ))) return NULL;
rec = msi_get_binary_record( db, name );
if( rec )
@ -2267,15 +2241,10 @@ static UINT msi_dialog_create_radiobutton( MSIRECORD *rec, LPVOID param )
msi_dialog *dialog = group->dialog;
msi_control *control;
LPCWSTR prop, text, name;
DWORD style, attributes = group->attributes;
DWORD style = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTORADIOBUTTON | BS_MULTILINE;
style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE | WS_TABSTOP;
name = MSI_RecordGetString( rec, 3 );
text = MSI_RecordGetString( rec, 8 );
if( attributes & msidbControlAttributesVisible )
style |= WS_VISIBLE;
if( ~attributes & msidbControlAttributesEnabled )
style |= WS_DISABLED;
control = dialog_create_window( dialog, rec, 0, szButton, name, text, style,
group->parent->hwnd );
@ -2338,6 +2307,10 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
TRACE("%p %p %s\n", dialog, rec, debugstr_w( prop ));
attr = MSI_RecordGetInteger( rec, 8 );
if (attr & msidbControlAttributesVisible)
style |= WS_VISIBLE;
if (~attr & msidbControlAttributesEnabled)
style |= WS_DISABLED;
if (attr & msidbControlAttributesHasBorder)
style |= BS_GROUPBOX;
else
@ -2367,7 +2340,6 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
group.dialog = dialog;
group.parent = control;
group.attributes = MSI_RecordGetInteger( rec, 8 );
group.propval = msi_dup_property( dialog->package->db, control->property );
r = MSI_IterateRecords( view, 0, msi_dialog_create_radiobutton, &group );

View file

@ -32,10 +32,9 @@
#include "msipriv.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
#include <patchapi.h>
static HMODULE hmspatcha;
static BOOL (WINAPI *ApplyPatchToFileW)(LPCWSTR, LPCWSTR, LPCWSTR, ULONG);
WINE_DEFAULT_DEBUG_CHANNEL(msi);
static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *action )
{
@ -50,40 +49,71 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *ac
msi_ui_progress( package, 2, f->FileSize, 0, 0 );
}
static BOOL is_registered_patch_media( MSIPACKAGE *package, UINT disk_id )
{
MSIPATCHINFO *patch;
LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
{
if (patch->disk_id == disk_id && patch->registered) return TRUE;
}
return FALSE;
}
static BOOL is_obsoleted_by_patch( MSIPACKAGE *package, MSIFILE *file )
{
if (!list_empty( &package->patches ) && file->disk_id < MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
{
if (!msi_get_property_int( package->db, szInstalled, 0 )) return FALSE;
return TRUE;
}
if (is_registered_patch_media( package, file->disk_id )) return TRUE;
return FALSE;
}
static msi_file_state calculate_install_state( MSIPACKAGE *package, MSIFILE *file )
{
MSICOMPONENT *comp = file->Component;
VS_FIXEDFILEINFO *file_version;
WCHAR *font_version;
msi_file_state state;
DWORD size;
comp->Action = msi_get_component_action( package, comp );
if (comp->Action != INSTALLSTATE_LOCAL || (comp->assembly && comp->assembly->installed))
if (!comp->Enabled || comp->Action != INSTALLSTATE_LOCAL || (comp->assembly && comp->assembly->installed))
{
TRACE("file %s is not scheduled for install\n", debugstr_w(file->File));
TRACE("skipping %s (not scheduled for install)\n", debugstr_w(file->File));
return msifs_skipped;
}
if ((comp->assembly && !comp->assembly->application && !comp->assembly->installed) ||
if (is_obsoleted_by_patch( package, file ))
{
TRACE("skipping %s (obsoleted by patch)\n", debugstr_w(file->File));
return msifs_skipped;
}
if ((msi_is_global_assembly( comp ) && !comp->assembly->installed) ||
GetFileAttributesW( file->TargetPath ) == INVALID_FILE_ATTRIBUTES)
{
TRACE("file %s is missing\n", debugstr_w(file->File));
TRACE("installing %s (missing)\n", debugstr_w(file->File));
return msifs_missing;
}
if (file->Version)
{
if ((file_version = msi_get_disk_file_version( file->TargetPath )))
{
TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
HIWORD(file_version->dwFileVersionMS),
LOWORD(file_version->dwFileVersionMS),
HIWORD(file_version->dwFileVersionLS),
LOWORD(file_version->dwFileVersionLS));
if (msi_compare_file_versions( file_version, file->Version ) < 0)
{
TRACE("overwriting %s (new version %s old version %u.%u.%u.%u)\n",
debugstr_w(file->File), debugstr_w(file->Version),
HIWORD(file_version->dwFileVersionMS), LOWORD(file_version->dwFileVersionMS),
HIWORD(file_version->dwFileVersionLS), LOWORD(file_version->dwFileVersionLS));
state = msifs_overwrite;
}
else
{
TRACE("destination file version equal or greater, not overwriting\n");
TRACE("keeping %s (new version %s old version %u.%u.%u.%u)\n",
debugstr_w(file->File), debugstr_w(file->Version),
HIWORD(file_version->dwFileVersionMS), LOWORD(file_version->dwFileVersionMS),
HIWORD(file_version->dwFileVersionLS), LOWORD(file_version->dwFileVersionLS));
state = msifs_present;
}
msi_free( file_version );
@ -91,37 +121,42 @@ static msi_file_state calculate_install_state( MSIPACKAGE *package, MSIFILE *fil
}
else if ((font_version = msi_font_version_from_file( file->TargetPath )))
{
TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(font_version));
if (msi_compare_font_versions( font_version, file->Version ) < 0)
{
TRACE("overwriting %s (new version %s old version %s)\n",
debugstr_w(file->File), debugstr_w(file->Version), debugstr_w(font_version));
state = msifs_overwrite;
}
else
{
TRACE("destination file version equal or greater, not overwriting\n");
TRACE("keeping %s (new version %s old version %s)\n",
debugstr_w(file->File), debugstr_w(file->Version), debugstr_w(font_version));
state = msifs_present;
}
msi_free( font_version );
return state;
}
}
if (msi_get_disk_file_size( file->TargetPath ) != file->FileSize)
if ((size = msi_get_disk_file_size( file->TargetPath )) != file->FileSize)
{
TRACE("overwriting %s (old size %u new size %u)\n", debugstr_w(file->File), size, file->FileSize);
return msifs_overwrite;
}
if (file->hash.dwFileHashInfoSize)
{
if (msi_file_hash_matches( file ))
{
TRACE("file hashes match, not overwriting\n");
TRACE("keeping %s (hash match)\n", debugstr_w(file->File));
return msifs_hashmatch;
}
else
{
TRACE("file hashes do not match, overwriting\n");
TRACE("overwriting %s (hash mismatch)\n", debugstr_w(file->File));
return msifs_overwrite;
}
}
/* assume present */
TRACE("keeping %s\n", debugstr_w(file->File));
return msifs_present;
}
@ -246,33 +281,32 @@ static MSIFILE *find_file( MSIPACKAGE *package, UINT disk_id, const WCHAR *filen
return NULL;
}
static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR filename, DWORD action,
LPWSTR *path, DWORD *attrs, PVOID user)
{
static MSIFILE *f = NULL;
UINT_PTR disk_id = (UINT_PTR)user;
MSIFILE *file = *(MSIFILE **)user;
if (action == MSICABEXTRACT_BEGINEXTRACT)
{
if (!(f = find_file( package, disk_id, file )))
if (!(file = find_file( package, file->disk_id, filename )))
{
TRACE("unknown file in cabinet (%s)\n", debugstr_w(file));
TRACE("unknown file in cabinet (%s)\n", debugstr_w(filename));
return FALSE;
}
if (f->disk_id != disk_id || (f->state != msifs_missing && f->state != msifs_overwrite))
if (file->state != msifs_missing && file->state != msifs_overwrite)
return FALSE;
if (!f->Component->assembly || f->Component->assembly->application)
if (!msi_is_global_assembly( file->Component ))
{
msi_create_directory(package, f->Component->Directory);
msi_create_directory( package, file->Component->Directory );
}
*path = strdupW(f->TargetPath);
*attrs = f->Attributes;
*path = strdupW( file->TargetPath );
*attrs = file->Attributes;
*(MSIFILE **)user = file;
}
else if (action == MSICABEXTRACT_FILEEXTRACTED)
{
f->state = msifs_installed;
f = NULL;
if (!msi_is_global_assembly( file->Component )) file->state = msifs_installed;
}
return TRUE;
@ -309,7 +343,6 @@ WCHAR *msi_resolve_file_source( MSIPACKAGE *package, MSIFILE *file )
UINT ACTION_InstallFiles(MSIPACKAGE *package)
{
MSIMEDIAINFO *mi;
MSICOMPONENT *comp;
UINT rc = ERROR_SUCCESS;
MSIFILE *file;
@ -327,7 +360,6 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
rc = ERROR_FUNCTION_FAILED;
goto done;
}
if (!file->Component->Enabled) continue;
if (file->state != msifs_hashmatch &&
file->state != msifs_skipped &&
@ -345,14 +377,14 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
(file->IsCompressed && !mi->is_extracted))
{
MSICABDATA data;
MSIFILE *cursor = file;
data.mi = mi;
data.package = package;
data.cb = installfiles_cb;
data.user = (PVOID)(UINT_PTR)mi->disk_id;
data.user = &cursor;
if (file->IsCompressed &&
!msi_cabextract(package, mi, &data))
if (file->IsCompressed && !msi_cabextract(package, mi, &data))
{
ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
rc = ERROR_INSTALL_FAILURE;
@ -366,41 +398,43 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
TRACE("copying %s to %s\n", debugstr_w(source), debugstr_w(file->TargetPath));
if (!file->Component->assembly || file->Component->assembly->application)
if (!msi_is_global_assembly( file->Component ))
{
msi_create_directory(package, file->Component->Directory);
}
rc = copy_install_file(package, file, source);
if (rc != ERROR_SUCCESS)
{
ERR("Failed to copy %s to %s (%d)\n", debugstr_w(source),
debugstr_w(file->TargetPath), rc);
ERR("Failed to copy %s to %s (%u)\n", debugstr_w(source), debugstr_w(file->TargetPath), rc);
rc = ERROR_INSTALL_FAILURE;
msi_free(source);
goto done;
}
msi_free(source);
}
else if (file->state != msifs_installed && !(file->Attributes & msidbFileAttributesPatchAdded))
else if (!msi_is_global_assembly( file->Component ) &&
file->state != msifs_installed && !(file->Attributes & msidbFileAttributesPatchAdded))
{
ERR("compressed file wasn't installed (%s)\n", debugstr_w(file->File));
rc = ERROR_INSTALL_FAILURE;
goto done;
}
}
LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
{
comp->Action = msi_get_component_action( package, comp );
if (comp->Action == INSTALLSTATE_LOCAL && comp->assembly && !comp->assembly->installed)
MSICOMPONENT *comp = file->Component;
if (!msi_is_global_assembly( comp ) || comp->assembly->installed ||
(file->state != msifs_missing && file->state != msifs_overwrite)) continue;
rc = msi_install_assembly( package, comp );
if (rc != ERROR_SUCCESS)
{
rc = msi_install_assembly( package, comp );
if (rc != ERROR_SUCCESS)
{
ERR("Failed to install assembly\n");
rc = ERROR_INSTALL_FAILURE;
break;
}
ERR("Failed to install assembly\n");
rc = ERROR_INSTALL_FAILURE;
break;
}
file->state = msifs_installed;
}
done:
@ -408,37 +442,14 @@ done:
return rc;
}
static BOOL load_mspatcha(void)
{
hmspatcha = LoadLibraryA("mspatcha.dll");
if (!hmspatcha)
{
ERR("Failed to load mspatcha.dll: %d\n", GetLastError());
return FALSE;
}
ApplyPatchToFileW = (void*)GetProcAddress(hmspatcha, "ApplyPatchToFileW");
if(!ApplyPatchToFileW)
{
ERR("GetProcAddress(ApplyPatchToFileW) failed: %d.\n", GetLastError());
return FALSE;
}
return TRUE;
}
static void unload_mspatch(void)
{
FreeLibrary(hmspatcha);
}
static MSIFILEPATCH *get_next_filepatch( MSIPACKAGE *package, const WCHAR *key )
static MSIFILEPATCH *find_filepatch( MSIPACKAGE *package, UINT disk_id, const WCHAR *key )
{
MSIFILEPATCH *patch;
LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
{
if (!patch->IsApplied && !strcmpW( key, patch->File->File )) return patch;
if (!patch->extracted && patch->disk_id == disk_id && !strcmpW( key, patch->File->File ))
return patch;
}
return NULL;
}
@ -446,61 +457,121 @@ static MSIFILEPATCH *get_next_filepatch( MSIPACKAGE *package, const WCHAR *key )
static BOOL patchfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
LPWSTR *path, DWORD *attrs, PVOID user)
{
static MSIFILEPATCH *p = NULL;
static WCHAR patch_path[MAX_PATH] = {0};
static WCHAR temp_folder[MAX_PATH] = {0};
MSIFILEPATCH *patch = *(MSIFILEPATCH **)user;
if (action == MSICABEXTRACT_BEGINEXTRACT)
{
if (temp_folder[0] == '\0')
GetTempPathW(MAX_PATH, temp_folder);
MSICOMPONENT *comp;
if (!(p = get_next_filepatch(package, file)) || !p->File->Component->Enabled)
if (is_registered_patch_media( package, patch->disk_id ) ||
!(patch = find_filepatch( package, patch->disk_id, file ))) return FALSE;
comp = patch->File->Component;
comp->Action = msi_get_component_action( package, comp );
if (!comp->Enabled || comp->Action != INSTALLSTATE_LOCAL)
{
TRACE("file %s component %s not installed or disabled\n",
debugstr_w(patch->File->File), debugstr_w(comp->Component));
return FALSE;
}
GetTempFileNameW(temp_folder, NULL, 0, patch_path);
*path = strdupW(patch_path);
*attrs = p->File->Attributes;
patch->path = msi_create_temp_file( package->db );
*path = strdupW( patch->path );
*attrs = patch->File->Attributes;
*(MSIFILEPATCH **)user = patch;
}
else if (action == MSICABEXTRACT_FILEEXTRACTED)
{
WCHAR patched_file[MAX_PATH];
BOOL br;
GetTempFileNameW(temp_folder, NULL, 0, patched_file);
br = ApplyPatchToFileW(patch_path, p->File->TargetPath, patched_file, 0);
if (br)
{
/* FIXME: baseline cache */
DeleteFileW( p->File->TargetPath );
MoveFileW( patched_file, p->File->TargetPath );
p->IsApplied = TRUE;
}
else
ERR("Failed patch %s: %d.\n", debugstr_w(p->File->TargetPath), GetLastError());
DeleteFileW(patch_path);
p = NULL;
patch->extracted = TRUE;
}
return TRUE;
}
static UINT patch_file( MSIPACKAGE *package, MSIFILEPATCH *patch )
{
UINT r = ERROR_SUCCESS;
WCHAR *tmpfile = msi_create_temp_file( package->db );
if (!tmpfile) return ERROR_INSTALL_FAILURE;
if (ApplyPatchToFileW( patch->path, patch->File->TargetPath, tmpfile, 0 ))
{
DeleteFileW( patch->File->TargetPath );
MoveFileW( tmpfile, patch->File->TargetPath );
}
else
{
WARN("failed to patch %s: %08x\n", debugstr_w(patch->File->TargetPath), GetLastError());
r = ERROR_INSTALL_FAILURE;
}
DeleteFileW( patch->path );
DeleteFileW( tmpfile );
msi_free( tmpfile );
return r;
}
static UINT patch_assembly( MSIPACKAGE *package, MSIASSEMBLY *assembly, MSIFILEPATCH *patch )
{
UINT r = ERROR_FUNCTION_FAILED;
IAssemblyName *name;
IAssemblyEnum *iter;
if (!(iter = msi_create_assembly_enum( package, assembly->display_name )))
return ERROR_FUNCTION_FAILED;
while ((IAssemblyEnum_GetNextAssembly( iter, NULL, &name, 0 ) == S_OK))
{
WCHAR *displayname, *path;
UINT len = 0;
HRESULT hr;
hr = IAssemblyName_GetDisplayName( name, NULL, &len, 0 );
if (hr != E_NOT_SUFFICIENT_BUFFER || !(displayname = msi_alloc( len * sizeof(WCHAR) )))
break;
hr = IAssemblyName_GetDisplayName( name, displayname, &len, 0 );
if (FAILED( hr ))
{
msi_free( displayname );
break;
}
if ((path = msi_get_assembly_path( package, displayname )))
{
if (!CopyFileW( path, patch->File->TargetPath, FALSE ))
{
ERR("Failed to copy file %s -> %s (%u)\n", debugstr_w(path),
debugstr_w(patch->File->TargetPath), GetLastError() );
msi_free( path );
msi_free( displayname );
IAssemblyName_Release( name );
break;
}
r = patch_file( package, patch );
msi_free( path );
}
msi_free( displayname );
IAssemblyName_Release( name );
if (r == ERROR_SUCCESS) break;
}
IAssemblyEnum_Release( iter );
return r;
}
UINT ACTION_PatchFiles( MSIPACKAGE *package )
{
MSIFILEPATCH *patch;
MSIMEDIAINFO *mi;
UINT rc = ERROR_SUCCESS;
BOOL mspatcha_loaded = FALSE;
TRACE("%p\n", package);
mi = msi_alloc_zero( sizeof(MSIMEDIAINFO) );
TRACE("extracting files\n");
LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
{
MSIFILE *file = patch->File;
@ -516,9 +587,10 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package )
comp->Action = msi_get_component_action( package, comp );
if (!comp->Enabled || comp->Action != INSTALLSTATE_LOCAL) continue;
if (!patch->IsApplied)
if (!patch->extracted)
{
MSICABDATA data;
MSIFILEPATCH *cursor = patch;
rc = ready_media( package, TRUE, mi );
if (rc != ERROR_SUCCESS)
@ -526,39 +598,51 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package )
ERR("Failed to ready media for %s\n", debugstr_w(file->File));
goto done;
}
if (!mspatcha_loaded && !load_mspatcha())
{
rc = ERROR_FUNCTION_FAILED;
goto done;
}
mspatcha_loaded = TRUE;
data.mi = mi;
data.mi = mi;
data.package = package;
data.cb = patchfiles_cb;
data.user = (PVOID)(UINT_PTR)mi->disk_id;
data.cb = patchfiles_cb;
data.user = &cursor;
if (!msi_cabextract(package, mi, &data))
if (!msi_cabextract( package, mi, &data ))
{
ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
rc = ERROR_INSTALL_FAILURE;
goto done;
}
}
}
if (!patch->IsApplied && !(patch->Attributes & msidbPatchAttributesNonVital))
TRACE("applying patches\n");
LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
{
MSICOMPONENT *comp = patch->File->Component;
if (!patch->path) continue;
if (msi_is_global_assembly( comp ))
rc = patch_assembly( package, comp->assembly, patch );
else
rc = patch_file( package, patch );
if (rc && !(patch->Attributes & msidbPatchAttributesNonVital))
{
ERR("Failed to apply patch to file: %s\n", debugstr_w(file->File));
rc = ERROR_INSTALL_FAILURE;
goto done;
ERR("Failed to apply patch to file: %s\n", debugstr_w(patch->File->File));
break;
}
if (msi_is_global_assembly( comp ))
{
if ((rc = msi_install_assembly( package, comp )))
{
ERR("Failed to install patched assembly\n");
break;
}
}
}
done:
msi_free_media_info(mi);
if (mspatcha_loaded)
unload_mspatch();
return rc;
}

View file

@ -165,7 +165,6 @@ static WCHAR *load_ttf_name_id( const WCHAR *filename, DWORD id )
end:
CloseHandle(handle);
TRACE("Returning %s\n", debugstr_w(ret));
return ret;
}

View file

@ -573,7 +573,7 @@ UINT MSI_SetTargetPathW( MSIPACKAGE *package, LPCWSTR szFolder, LPCWSTR szFolder
const WCHAR *dir;
MSICOMPONENT *comp = file->Component;
if (!comp->Enabled || (comp->assembly && !comp->assembly->application)) continue;
if (!comp->Enabled || msi_is_global_assembly( comp )) continue;
dir = msi_get_target_folder( package, comp->Directory );
msi_free( file->TargetPath );

View file

@ -43,8 +43,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPCWSTR source_root)
{
WCHAR volume_name[MAX_PATH + 1];
WCHAR root[MAX_PATH + 1];
WCHAR volume_name[MAX_PATH + 1], root[MAX_PATH + 1];
const WCHAR *p;
int len, len2;
strcpyW(root, source_root);
PathStripToRootW(root);
@ -55,7 +56,13 @@ static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPCWSTR source_root)
WARN("failed to get volume information for %s (%u)\n", debugstr_w(root), GetLastError());
return FALSE;
}
return !strcmpiW( mi->volume_label, volume_name );
len = strlenW( volume_name );
len2 = strlenW( mi->volume_label );
if (len2 > len) return FALSE;
p = volume_name + len - len2;
return !strcmpiW( mi->volume_label, p );
}
static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
@ -202,28 +209,39 @@ static INT_PTR CDECL cabinet_open_stream( char *pszFile, int oflag, int pmode )
{
MSICABINETSTREAM *cab;
IStream *stream;
WCHAR *encoded;
HRESULT hr;
cab = msi_get_cabinet_stream( package_disk.package, package_disk.id );
if (!cab)
if (!(cab = msi_get_cabinet_stream( package_disk.package, package_disk.id )))
{
WARN("failed to get cabinet stream\n");
return -1;
}
if (!cab->stream[0] || !(encoded = encode_streamname( FALSE, cab->stream + 1 )))
if (cab->storage == package_disk.package->db->storage)
{
WARN("failed to encode stream name\n");
return -1;
UINT r = msi_get_stream( package_disk.package->db, cab->stream + 1, &stream );
if (r != ERROR_SUCCESS)
{
WARN("failed to get stream %u\n", r);
return -1;
}
}
hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream );
if (FAILED(hr))
else /* patch storage */
{
WARN("failed to open stream 0x%08x\n", hr);
HRESULT hr;
WCHAR *encoded;
if (!(encoded = encode_streamname( FALSE, cab->stream + 1 )))
{
WARN("failed to encode stream name\n");
return -1;
}
hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream );
msi_free( encoded );
return -1;
if (FAILED(hr))
{
WARN("failed to open stream 0x%08x\n", hr);
return -1;
}
}
msi_free( encoded );
return (INT_PTR)stream;
}

View file

@ -463,7 +463,7 @@ UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages,
r = MSI_ApplyPatchW(patch, szProductCode, szPropertiesList);
msi_free(patch);
if (r != ERROR_SUCCESS)
if (r != ERROR_SUCCESS || !*end)
break;
beg = ++end;
@ -533,7 +533,7 @@ static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
{
MSISUMMARYINFO *si;
MSIDATABASE *patch_db;
UINT r = ERROR_SUCCESS;
UINT r;
r = MSI_OpenDatabaseW( patch, MSIDBOPEN_READONLY, &patch_db );
if (r != ERROR_SUCCESS)
@ -542,8 +542,8 @@ static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
return r;
}
si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
if (!si)
r = msi_get_suminfo( patch_db->storage, 0, &si );
if (r != ERROR_SUCCESS)
{
msiobj_release( &patch_db->hdr );
return ERROR_FUNCTION_FAILED;
@ -2024,7 +2024,7 @@ UINT WINAPI MsiEnumComponentCostsW( MSIHANDLE handle, LPCWSTR component, DWORD i
GetWindowsDirectoryW( path, MAX_PATH );
if (component && component[0])
{
if (comp->assembly && !comp->assembly->application) *temp = comp->Cost;
if (msi_is_global_assembly( comp )) *temp = comp->Cost;
if (!comp->Enabled || !comp->KeyPath)
{
*cost = 0;
@ -3989,17 +3989,55 @@ extern VOID WINAPI MD5Init( MD5_CTX *);
extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
extern VOID WINAPI MD5Final( MD5_CTX *);
/***********************************************************************
* MsiGetFileHashW [MSI.@]
*/
UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
PMSIFILEHASHINFO pHash )
UINT msi_get_filehash( const WCHAR *path, MSIFILEHASHINFO *hash )
{
HANDLE handle, mapping;
void *p;
DWORD length;
UINT r = ERROR_FUNCTION_FAILED;
handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
if (handle == INVALID_HANDLE_VALUE)
{
WARN("can't open file %u\n", GetLastError());
return ERROR_FILE_NOT_FOUND;
}
if ((length = GetFileSize( handle, NULL )))
{
if ((mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL )))
{
if ((p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length )))
{
MD5_CTX ctx;
MD5Init( &ctx );
MD5Update( &ctx, p, length );
MD5Final( &ctx );
UnmapViewOfFile( p );
memcpy( hash->dwData, ctx.digest, sizeof(hash->dwData) );
r = ERROR_SUCCESS;
}
CloseHandle( mapping );
}
}
else
{
/* Empty file -> set hash to 0 */
memset( hash->dwData, 0, sizeof(hash->dwData) );
r = ERROR_SUCCESS;
}
CloseHandle( handle );
return r;
}
/***********************************************************************
* MsiGetFileHashW [MSI.@]
*/
UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
PMSIFILEHASHINFO pHash )
{
TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
if (!szFilePath)
@ -4015,46 +4053,7 @@ UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
if (pHash->dwFileHashInfoSize < sizeof *pHash)
return ERROR_INVALID_PARAMETER;
handle = CreateFileW( szFilePath, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
if (handle == INVALID_HANDLE_VALUE)
{
WARN("can't open file %u\n", GetLastError());
return ERROR_FILE_NOT_FOUND;
}
length = GetFileSize( handle, NULL );
if (length)
{
mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
if (mapping)
{
p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
if (p)
{
MD5_CTX ctx;
MD5Init( &ctx );
MD5Update( &ctx, p, length );
MD5Final( &ctx );
UnmapViewOfFile( p );
memcpy( pHash->dwData, ctx.digest, sizeof pHash->dwData );
r = ERROR_SUCCESS;
}
CloseHandle( mapping );
}
}
else
{
/* Empty file -> set hash to 0 */
memset( pHash->dwData, 0, sizeof pHash->dwData );
r = ERROR_SUCCESS;
}
CloseHandle( handle );
return r;
return msi_get_filehash( szFilePath, pHash );
}
/***********************************************************************
@ -4178,7 +4177,7 @@ UINT WINAPI MsiProvideComponentA( LPCSTR product, LPCSTR feature, LPCSTR compone
{
WCHAR *productW = NULL, *componentW = NULL, *featureW = NULL, *bufW = NULL;
UINT r = ERROR_OUTOFMEMORY;
DWORD lenW;
DWORD lenW = 0;
int len;
TRACE("%s, %s, %s, %x, %p, %p\n", debugstr_a(product), debugstr_a(component), debugstr_a(feature), mode, buf, buflen);

View file

@ -53,7 +53,7 @@
#include <wine/unicode.h>
static const BOOL is_64bit = sizeof(void *) > sizeof(int);
BOOL is_wow64;
BOOL is_wow64 DECLSPEC_HIDDEN;
#define MSI_DATASIZEMASK 0x00ff
#define MSITYPE_VALID 0x0100
@ -114,6 +114,7 @@ typedef struct tagMSIDATABASE
UINT bytes_per_strref;
LPWSTR path;
LPWSTR deletefile;
LPWSTR tempfolder;
LPCWSTR mode;
UINT media_transform_offset;
UINT media_transform_disk_id;
@ -206,6 +207,8 @@ typedef struct tagMSIPATCHINFO
LPWSTR localfile;
MSIPATCHSTATE state;
BOOL delete_on_close;
BOOL registered;
UINT disk_id;
} MSIPATCHINFO;
typedef struct tagMSIBINARY
@ -593,12 +596,6 @@ typedef struct tagMSIFILE
UINT disk_id;
} MSIFILE;
typedef struct tagMSITEMPFILE
{
struct list entry;
LPWSTR Path;
} MSITEMPFILE;
typedef struct tagMSIFILEPATCH
{
struct list entry;
@ -606,7 +603,9 @@ typedef struct tagMSIFILEPATCH
INT Sequence;
INT PatchSize;
INT Attributes;
BOOL IsApplied;
BOOL extracted;
UINT disk_id;
WCHAR *path;
} MSIFILEPATCH;
typedef struct tagMSIAPPID
@ -949,6 +948,7 @@ extern int msi_compare_file_versions(VS_FIXEDFILEINFO *, const WCHAR *) DECLSPEC
extern int msi_compare_font_versions(const WCHAR *, const WCHAR *) DECLSPEC_HIDDEN;
extern DWORD msi_get_disk_file_size(LPCWSTR) DECLSPEC_HIDDEN;
extern BOOL msi_file_hash_matches(MSIFILE *) DECLSPEC_HIDDEN;
extern UINT msi_get_filehash(const WCHAR *, MSIFILEHASHINFO *) DECLSPEC_HIDDEN;
extern LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value ) DECLSPEC_HIDDEN;
extern LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value ) DECLSPEC_HIDDEN;
@ -962,12 +962,14 @@ extern void msi_dialog_unregister_class( void ) DECLSPEC_HIDDEN;
extern UINT msi_spawn_error_dialog( MSIPACKAGE*, LPWSTR, LPWSTR ) DECLSPEC_HIDDEN;
/* summary information */
extern MSISUMMARYINFO *MSI_GetSummaryInformationW( IStorage *stg, UINT uiUpdateCount ) DECLSPEC_HIDDEN;
extern UINT msi_get_suminfo( IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **si ) DECLSPEC_HIDDEN;
extern UINT msi_get_db_suminfo( MSIDATABASE *db, UINT uiUpdateCount, MSISUMMARYINFO **si ) DECLSPEC_HIDDEN;
extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) DECLSPEC_HIDDEN;
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 enum platform parse_platform( const WCHAR *str ) DECLSPEC_HIDDEN;
extern UINT msi_load_suminfo_properties( MSIPACKAGE *package ) DECLSPEC_HIDDEN;
/* undocumented functions */
UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD );
@ -1033,7 +1035,7 @@ extern MSICOMPONENT *msi_get_loaded_component(MSIPACKAGE *package, const WCHAR *
extern MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE *package, const WCHAR *Feature) DECLSPEC_HIDDEN;
extern MSIFILE *msi_get_loaded_file(MSIPACKAGE *package, const WCHAR *file) DECLSPEC_HIDDEN;
extern MSIFOLDER *msi_get_loaded_folder(MSIPACKAGE *package, const WCHAR *dir) DECLSPEC_HIDDEN;
extern int msi_track_tempfile(MSIPACKAGE *package, const WCHAR *path) DECLSPEC_HIDDEN;
extern WCHAR *msi_create_temp_file(MSIDATABASE *db) DECLSPEC_HIDDEN;
extern void msi_free_action_script(MSIPACKAGE *package, UINT script) DECLSPEC_HIDDEN;
extern WCHAR *msi_build_icon_path(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
extern WCHAR *msi_build_directory_name(DWORD , ...) DECLSPEC_HIDDEN;
@ -1053,6 +1055,9 @@ extern UINT msi_install_assembly(MSIPACKAGE *, MSICOMPONENT *) DECLSPEC_HIDDEN;
extern UINT msi_uninstall_assembly(MSIPACKAGE *, MSICOMPONENT *) DECLSPEC_HIDDEN;
extern BOOL msi_init_assembly_caches(MSIPACKAGE *) DECLSPEC_HIDDEN;
extern void msi_destroy_assembly_caches(MSIPACKAGE *) DECLSPEC_HIDDEN;
extern BOOL msi_is_global_assembly(MSICOMPONENT *) DECLSPEC_HIDDEN;
extern IAssemblyEnum *msi_create_assembly_enum(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
extern WCHAR *msi_get_assembly_path(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
extern WCHAR *msi_font_version_from_file(const WCHAR *) DECLSPEC_HIDDEN;
extern WCHAR **msi_split_string(const WCHAR *, WCHAR) DECLSPEC_HIDDEN;
extern UINT msi_set_original_database_property(MSIDATABASE *, const WCHAR *) DECLSPEC_HIDDEN;

View file

@ -24,22 +24,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(msi);
static void remove_tracked_tempfiles( MSIPACKAGE *package )
{
struct list *item, *cursor;
LIST_FOR_EACH_SAFE( item, cursor, &package->tempfiles )
{
MSITEMPFILE *temp = LIST_ENTRY( item, MSITEMPFILE, entry );
list_remove( &temp->entry );
TRACE("deleting temp file %s\n", debugstr_w( temp->Path ));
DeleteFileW( temp->Path );
msi_free( temp->Path );
msi_free( temp );
}
}
static void free_feature( MSIFEATURE *feature )
{
struct list *item, *cursor;
@ -145,6 +129,22 @@ static void free_package_structures( MSIPACKAGE *package )
free_folder( folder );
}
LIST_FOR_EACH_SAFE( item, cursor, &package->files )
{
MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );
list_remove( &file->entry );
msi_free( file->File );
msi_free( file->FileName );
msi_free( file->ShortName );
msi_free( file->LongName );
msi_free( file->Version );
msi_free( file->Language );
if (msi_is_global_assembly( file->Component )) DeleteFileW( file->TargetPath );
msi_free( file->TargetPath );
msi_free( file );
}
LIST_FOR_EACH_SAFE( item, cursor, &package->components )
{
MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry );
@ -160,19 +160,13 @@ static void free_package_structures( MSIPACKAGE *package )
msi_free( comp );
}
LIST_FOR_EACH_SAFE( item, cursor, &package->files )
LIST_FOR_EACH_SAFE( item, cursor, &package->filepatches )
{
MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );
MSIFILEPATCH *patch = LIST_ENTRY( item, MSIFILEPATCH, entry );
list_remove( &file->entry );
msi_free( file->File );
msi_free( file->FileName );
msi_free( file->ShortName );
msi_free( file->LongName );
msi_free( file->Version );
msi_free( file->Language );
msi_free( file->TargetPath );
msi_free( file );
list_remove( &patch->entry );
msi_free( patch->path );
msi_free( patch );
}
/* clean up extension, progid, class and verb structures */
@ -313,8 +307,6 @@ static void free_package_structures( MSIPACKAGE *package )
msi_free( package->LastAction );
msi_free( package->langids );
remove_tracked_tempfiles(package);
/* cleanup control event subscriptions */
msi_event_cleanup_all_subscriptions( package );
}
@ -1002,74 +994,6 @@ static VOID set_installer_properties(MSIPACKAGE *package)
msi_set_property( package->db, szBrowseProperty, szInstallDir, -1 );
}
static UINT msi_load_summary_properties( MSIPACKAGE *package )
{
UINT rc;
MSIHANDLE suminfo;
MSIHANDLE hdb = alloc_msihandle( &package->db->hdr );
INT count;
DWORD len;
LPWSTR package_code;
static const WCHAR szPackageCode[] = {
'P','a','c','k','a','g','e','C','o','d','e',0};
if (!hdb) {
ERR("Unable to allocate handle\n");
return ERROR_OUTOFMEMORY;
}
rc = MsiGetSummaryInformationW( hdb, NULL, 0, &suminfo );
MsiCloseHandle(hdb);
if (rc != ERROR_SUCCESS)
{
ERR("Unable to open Summary Information\n");
return rc;
}
rc = MsiSummaryInfoGetPropertyW( suminfo, PID_PAGECOUNT, NULL,
&count, NULL, NULL, NULL );
if (rc != ERROR_SUCCESS)
{
WARN("Unable to query page count: %d\n", rc);
goto done;
}
/* load package code property */
len = 0;
rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
NULL, NULL, NULL, &len );
if (rc != ERROR_MORE_DATA)
{
WARN("Unable to query revision number: %d\n", rc);
rc = ERROR_FUNCTION_FAILED;
goto done;
}
len++;
package_code = msi_alloc( len * sizeof(WCHAR) );
rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
NULL, NULL, package_code, &len );
if (rc != ERROR_SUCCESS)
{
WARN("Unable to query rev number: %d\n", rc);
msi_free( package_code );
goto done;
}
msi_set_property( package->db, szPackageCode, package_code, len );
msi_free( package_code );
/* load package attributes */
count = 0;
MsiSummaryInfoGetPropertyW( suminfo, PID_WORDCOUNT, NULL,
&count, NULL, NULL, NULL );
package->WordCount = count;
done:
MsiCloseHandle(suminfo);
return rc;
}
static MSIPACKAGE *msi_alloc_package( void )
{
MSIPACKAGE *package;
@ -1162,7 +1086,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
len = sprintfW( uilevel, fmtW, gUILevel & INSTALLUILEVEL_MASK );
msi_set_property( package->db, szUILevel, uilevel, len );
r = msi_load_summary_properties( package );
r = msi_load_suminfo_properties( package );
if (r != ERROR_SUCCESS)
{
msiobj_release( &package->hdr );
@ -1255,7 +1179,7 @@ enum platform parse_platform( const WCHAR *str )
return PLATFORM_UNKNOWN;
}
static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package )
static UINT parse_suminfo( MSISUMMARYINFO *si, MSIPACKAGE *package )
{
WCHAR *template, *p, *q, *platform;
DWORD i, count;
@ -1363,22 +1287,6 @@ static UINT validate_package( MSIPACKAGE *package )
return ERROR_INSTALL_LANGUAGE_UNSUPPORTED;
}
int msi_track_tempfile( MSIPACKAGE *package, const WCHAR *path )
{
MSITEMPFILE *temp;
TRACE("%s\n", debugstr_w(path));
LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry )
{
if (!strcmpW( path, temp->Path )) return 0;
}
if (!(temp = msi_alloc_zero( sizeof (MSITEMPFILE) ))) return -1;
list_add_head( &package->tempfiles, &temp->entry );
temp->Path = strdupW( path );
return 0;
}
static WCHAR *get_product_code( MSIDATABASE *db )
{
static const WCHAR query[] = {
@ -1458,11 +1366,17 @@ static WCHAR *get_package_code( MSIDATABASE *db )
{
WCHAR *ret;
MSISUMMARYINFO *si;
UINT r;
if (!(si = MSI_GetSummaryInformationW( db->storage, 0 )))
r = msi_get_suminfo( db->storage, 0, &si );
if (r != ERROR_SUCCESS)
{
WARN("failed to load summary info\n");
return NULL;
r = msi_get_db_suminfo( db, 0, &si );
if (r != ERROR_SUCCESS)
{
WARN("failed to load summary info %u\n", r);
return NULL;
}
}
ret = msi_suminfo_dup_string( si, PID_REVNUMBER );
msiobj_release( &si->hdr );
@ -1608,14 +1522,18 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
package->localfile = strdupW( localfile );
package->delete_on_close = delete_on_close;
si = MSI_GetSummaryInformationW( db->storage, 0 );
if (!si)
r = msi_get_suminfo( db->storage, 0, &si );
if (r != ERROR_SUCCESS)
{
WARN("failed to load summary info\n");
msiobj_release( &package->hdr );
return ERROR_INSTALL_PACKAGE_INVALID;
r = msi_get_db_suminfo( db, 0, &si );
if (r != ERROR_SUCCESS)
{
WARN("failed to load summary info\n");
msiobj_release( &package->hdr );
return ERROR_INSTALL_PACKAGE_INVALID;
}
}
r = msi_parse_summary( si, package );
r = parse_suminfo( si, package );
msiobj_release( &si->hdr );
if (r != ERROR_SUCCESS)
{
@ -2633,7 +2551,7 @@ HRESULT create_msi_remote_package( IUnknown *pOuter, LPVOID *ppObj )
This->package = 0;
This->refs = 1;
*ppObj = This;
*ppObj = &This->IWineMsiRemotePackage_iface;
return S_OK;
}

View file

@ -115,15 +115,16 @@ static UINT check_transform_applicable( MSIPACKAGE *package, IStorage *transform
MSITRANSFORM_VALIDATE_PRODUCT | MSITRANSFORM_VALIDATE_LANGUAGE |
MSITRANSFORM_VALIDATE_PLATFORM | MSITRANSFORM_VALIDATE_MAJORVERSION |
MSITRANSFORM_VALIDATE_MINORVERSION | MSITRANSFORM_VALIDATE_UPGRADECODE;
MSISUMMARYINFO *si = MSI_GetSummaryInformationW( transform, 0 );
UINT valid_flags = 0, wanted_flags = 0;
MSISUMMARYINFO *si;
UINT r, valid_flags = 0, wanted_flags = 0;
WCHAR *template, *product, *p;
struct transform_desc *desc;
if (!si)
r = msi_get_suminfo( transform, 0, &si );
if (r != ERROR_SUCCESS)
{
WARN("no summary information!\n");
return ERROR_FUNCTION_FAILED;
return r;
}
wanted_flags = msi_suminfo_get_int32( si, PID_CHARCOUNT );
wanted_flags &= 0xffff; /* mask off error condition flags */
@ -402,6 +403,7 @@ struct patch_offset
struct patch_offset_list
{
struct list files;
struct list patches;
UINT count, min, max;
UINT offset_to_apply;
};
@ -410,6 +412,7 @@ static struct patch_offset_list *patch_offset_list_create( void )
{
struct patch_offset_list *pos = msi_alloc( sizeof(struct patch_offset_list) );
list_init( &pos->files );
list_init( &pos->patches );
pos->count = pos->max = 0;
pos->min = 999999;
return pos;
@ -424,10 +427,15 @@ static void patch_offset_list_free( struct patch_offset_list *pos )
msi_free( po->name );
msi_free( po );
}
LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->patches, struct patch_offset, entry )
{
msi_free( po->name );
msi_free( po );
}
msi_free( pos );
}
static void patch_offset_get_patches( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
static void patch_offset_get_filepatches( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
{
static const WCHAR query[] = {
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ',
@ -451,12 +459,15 @@ static void patch_offset_get_patches( MSIDATABASE *db, UINT last_sequence, struc
while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
{
UINT sequence = MSI_RecordGetInteger( rec, 2 );
struct patch_offset *po = msi_alloc( sizeof(struct patch_offset) );
/* FIXME: we only use the max/min sequence numbers for now */
pos->min = min( pos->min, sequence );
pos->max = max( pos->max, sequence );
po->name = msi_dup_record_field( rec, 1 );
po->sequence = MSI_RecordGetInteger( rec, 2 );
pos->min = min( pos->min, po->sequence );
pos->max = max( pos->max, po->sequence );
list_add_tail( &pos->patches, &po->entry );
pos->count++;
msiobj_release( &rec->hdr );
}
msiobj_release( &view->hdr );
@ -503,58 +514,137 @@ static void patch_offset_get_files( MSIDATABASE *db, UINT last_sequence, struct
msiobj_release( &view->hdr );
}
static UINT patch_update_file_sequence( MSIDATABASE *db, const struct patch_offset_list *pos,
MSIQUERY *view, MSIRECORD *rec )
{
struct patch_offset *po;
const WCHAR *file = MSI_RecordGetString( rec, 1 );
UINT r = ERROR_SUCCESS, seq = MSI_RecordGetInteger( rec, 8 );
LIST_FOR_EACH_ENTRY( po, &pos->files, struct patch_offset, entry )
{
if (!strcmpiW( file, po->name ))
{
MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
if (r != ERROR_SUCCESS)
ERR("Failed to update offset for file %s (%u)\n", debugstr_w(file), r);
break;
}
}
return r;
}
static UINT patch_update_filepatch_sequence( MSIDATABASE *db, const struct patch_offset_list *pos,
MSIQUERY *view, MSIRECORD *rec )
{
static const WCHAR delete_query[] = {
'D','E','L','E','T','E',' ','F','R','O','M',' ','`','P','a','t','c','h','`',' ',
'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','?',' ',
'A','N','D',' ','`','S','e','q','u','e','n','c','e','`',' ','=',' ','?',0};
static const WCHAR insert_query[] = {
'I','N','S','E','R','T',' ','I','N','T','O',' ','`','P','a','t','c','h','`',' ',
'(','`','F','i','l','e','_','`',',','`','S','e','q','u','e','n','c','e','`',',',
'`','P','a','t','c','h','S','i','z','e','`',',','`','A','t','t','r','i','b','u','t','e','s','`',',',
'`','H','e','a','d','e','r','`',',','`','S','t','r','e','a','m','R','e','f','_','`',')',' ',
'V','A','L','U','E','S',' ','(','?',',','?',',','?',',','?',',','?',',','?',')',0};
struct patch_offset *po;
const WCHAR *file = MSI_RecordGetString( rec, 1 );
UINT r = ERROR_SUCCESS, seq = MSI_RecordGetInteger( rec, 2 );
LIST_FOR_EACH_ENTRY( po, &pos->patches, struct patch_offset, entry )
{
if (seq == po->sequence && !strcmpiW( file, po->name ))
{
MSIQUERY *delete_view, *insert_view;
MSIRECORD *rec2;
r = MSI_DatabaseOpenViewW( db, delete_query, &delete_view );
if (r != ERROR_SUCCESS) return r;
rec2 = MSI_CreateRecord( 2 );
MSI_RecordSetStringW( rec2, 1, po->name );
MSI_RecordSetInteger( rec2, 2, po->sequence );
r = MSI_ViewExecute( delete_view, rec2 );
msiobj_release( &delete_view->hdr );
msiobj_release( &rec2->hdr );
if (r != ERROR_SUCCESS) return r;
r = MSI_DatabaseOpenViewW( db, insert_query, &insert_view );
if (r != ERROR_SUCCESS) return r;
MSI_RecordSetInteger( rec, 2, po->sequence + pos->offset_to_apply );
r = MSI_ViewExecute( insert_view, rec );
msiobj_release( &insert_view->hdr );
if (r != ERROR_SUCCESS)
ERR("Failed to update offset for filepatch %s (%u)\n", debugstr_w(file), r);
break;
}
}
return r;
}
static UINT patch_offset_modify_db( MSIDATABASE *db, struct patch_offset_list *pos )
{
static const WCHAR query[] = {
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','>','=',' ','?',' ',
'A','N','D',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
struct patch_offset *po;
static const WCHAR file_query[] = {
'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','F','i','l','e','`',' ',
'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>','=',' ','?',' ',
'A','N','D',' ','`','S','e','q','u','e','n','c','e','`',' ','<','=',' ','?',' ',
'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
static const WCHAR patch_query[] = {
'S','E','L','E','C','T',' ','*','F','R','O','M',' ','`','P','a','t','c','h','`',' ',
'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>','=',' ','?',' ',
'A','N','D',' ','`','S','e','q','u','e','n','c','e','`',' ','<','=',' ','?',' ',
'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
MSIRECORD *rec;
MSIQUERY *view;
UINT r;
UINT r, min = pos->min, max = pos->max, r_fetch;
r = MSI_DatabaseOpenViewW( db, query, &view );
r = MSI_DatabaseOpenViewW( db, file_query, &view );
if (r != ERROR_SUCCESS)
return ERROR_SUCCESS;
rec = MSI_CreateRecord( 2 );
MSI_RecordSetInteger( rec, 1, pos->min );
MSI_RecordSetInteger( rec, 2, pos->max );
MSI_RecordSetInteger( rec, 1, min );
MSI_RecordSetInteger( rec, 2, max );
r = MSI_ViewExecute( view, rec );
msiobj_release( &rec->hdr );
if (r != ERROR_SUCCESS)
goto done;
LIST_FOR_EACH_ENTRY( po, &pos->files, struct patch_offset, entry )
while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
{
UINT r_fetch;
while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
{
const WCHAR *file = MSI_RecordGetString( rec, 1 );
UINT seq;
r = patch_update_file_sequence( db, pos, view, rec );
msiobj_release( &rec->hdr );
if (r != ERROR_SUCCESS) goto done;
}
msiobj_release( &view->hdr );
if (!strcmpiW( file, po->name ))
{
/* update record */
seq = MSI_RecordGetInteger( rec, 8 );
MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
if (r != ERROR_SUCCESS)
ERR("Failed to update offset for file %s\n", debugstr_w(file));
msiobj_release( &rec->hdr );
break;
}
msiobj_release( &rec->hdr );
}
if (r_fetch != ERROR_SUCCESS) break;
r = MSI_DatabaseOpenViewW( db, patch_query, &view );
if (r != ERROR_SUCCESS)
return ERROR_SUCCESS;
rec = MSI_CreateRecord( 2 );
MSI_RecordSetInteger( rec, 1, min );
MSI_RecordSetInteger( rec, 2, max );
r = MSI_ViewExecute( view, rec );
msiobj_release( &rec->hdr );
if (r != ERROR_SUCCESS)
goto done;
while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
{
r = patch_update_filepatch_sequence( db, pos, view, rec );
msiobj_release( &rec->hdr );
if (r != ERROR_SUCCESS) goto done;
}
done:
msiobj_release( &view->hdr );
return ERROR_SUCCESS;
return r;
}
static const WCHAR patch_media_query[] = {
@ -574,7 +664,7 @@ struct patch_media
WCHAR *source;
};
static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
static UINT patch_add_media( MSIPACKAGE *package, IStorage *storage, MSIPATCHINFO *patch )
{
static const WCHAR delete_query[] = {
'D','E','L','E','T','E',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
@ -611,7 +701,10 @@ static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
msiobj_release( &rec->hdr );
continue;
}
if (!(media = msi_alloc( sizeof( *media )))) goto done;
if (!(media = msi_alloc( sizeof( *media )))) {
msiobj_release( &rec->hdr );
goto done;
}
media->disk_id = disk_id;
media->last_sequence = MSI_RecordGetInteger( rec, 2 );
media->prompt = msi_dup_record_field( rec, 3 );
@ -661,9 +754,13 @@ static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
msiobj_release( &rec->hdr );
if (r != ERROR_SUCCESS) goto done;
r = msi_add_cabinet_stream( package, disk_id, patch, media->cabinet );
if (r != ERROR_SUCCESS) WARN("failed to add cabinet stream %u\n", r);
package->db->media_transform_disk_id++;
r = msi_add_cabinet_stream( package, disk_id, storage, media->cabinet );
if (r != ERROR_SUCCESS) ERR("failed to add cabinet stream %u\n", r);
else
{
patch->disk_id = disk_id;
package->db->media_transform_disk_id++;
}
}
done:
@ -680,7 +777,7 @@ done:
return r;
}
static UINT set_patch_offsets( MSIDATABASE *db )
static UINT patch_set_offsets( MSIDATABASE *db, MSIPATCHINFO *patch )
{
MSIQUERY *view;
MSIRECORD *rec;
@ -696,7 +793,7 @@ static UINT set_patch_offsets( MSIDATABASE *db )
while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
{
UINT last_sequence = MSI_RecordGetInteger( rec, 2 );
UINT offset, last_sequence = MSI_RecordGetInteger( rec, 2 );
struct patch_offset_list *pos;
/* FIXME: set/check Source field instead? */
@ -707,23 +804,26 @@ static UINT set_patch_offsets( MSIDATABASE *db )
}
pos = patch_offset_list_create();
patch_offset_get_files( db, last_sequence, pos );
patch_offset_get_patches( db, last_sequence, pos );
patch_offset_get_filepatches( db, last_sequence, pos );
offset = db->media_transform_offset - pos->min;
last_sequence = offset + pos->max;
last_sequence += pos->min;
pos->offset_to_apply = offset;
if (pos->count)
{
UINT offset = db->media_transform_offset - pos->min;
last_sequence = offset + pos->max;
/* FIXME: this is for the patch table, which is not yet properly transformed */
last_sequence += pos->min;
pos->offset_to_apply = offset;
if (pos->count)
patch_offset_modify_db( db, pos );
MSI_RecordSetInteger( rec, 2, last_sequence );
r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
r = patch_offset_modify_db( db, pos );
if (r != ERROR_SUCCESS)
ERR("Failed to update Media table entry, expect breakage (%u)\n", r);
db->media_transform_offset = last_sequence + 1;
ERR("Failed to set offsets, expect breakage (%u)\n", r);
}
MSI_RecordSetInteger( rec, 2, last_sequence );
r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
if (r != ERROR_SUCCESS)
ERR("Failed to update Media table entry, expect breakage (%u)\n", r);
db->media_transform_offset = last_sequence + 1;
patch_offset_list_free( pos );
msiobj_release( &rec->hdr );
}
@ -745,15 +845,18 @@ static UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIP
r = apply_substorage_transform( package, patch_db, substorage[i] );
if (r == ERROR_SUCCESS)
{
add_patch_media( package, patch_db->storage );
set_patch_offsets( package->db );
r = patch_set_offsets( package->db, patch );
if (r == ERROR_SUCCESS)
r = patch_add_media( package, patch_db->storage, patch );
}
}
msi_free( substorage );
if (r != ERROR_SUCCESS)
return r;
patch_set_media_source_prop( package );
r = patch_set_media_source_prop( package );
if (r != ERROR_SUCCESS)
return r;
patch->state = MSIPATCHSTATE_APPLIED;
list_add_tail( &package->patches, &patch->entry );
@ -777,9 +880,9 @@ static UINT msi_apply_patch_package( MSIPACKAGE *package, const WCHAR *file )
WCHAR localfile[MAX_PATH];
MSISUMMARYINFO *si;
MSIPATCHINFO *patch = NULL;
UINT r = ERROR_SUCCESS;
UINT r;
TRACE("%p %s\n", package, debugstr_w(file));
TRACE("%p, %s\n", package, debugstr_w(file));
r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
if (r != ERROR_SUCCESS)
@ -787,10 +890,11 @@ static UINT msi_apply_patch_package( MSIPACKAGE *package, const WCHAR *file )
ERR("failed to open patch collection %s\n", debugstr_w( file ) );
return r;
}
if (!(si = MSI_GetSummaryInformationW( patch_db->storage, 0 )))
r = msi_get_suminfo( patch_db->storage, 0, &si );
if (r != ERROR_SUCCESS)
{
msiobj_release( &patch_db->hdr );
return ERROR_FUNCTION_FAILED;
return r;
}
r = msi_check_patch_applicable( package, si );
if (r != ERROR_SUCCESS)
@ -808,6 +912,7 @@ static UINT msi_apply_patch_package( MSIPACKAGE *package, const WCHAR *file )
goto done;
r = ERROR_OUTOFMEMORY;
patch->registered = FALSE;
if (!(patch->filename = strdupW( file ))) goto done;
if (!(patch->localfile = strdupW( localfile ))) goto done;
@ -894,6 +999,8 @@ UINT msi_apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code )
MSIPATCHINFO *patch_info;
MSISUMMARYINFO *si;
TRACE("%p, %s\n", package, debugstr_w(patch_code));
len = sizeof(patch_file) / sizeof(WCHAR);
r = MsiGetPatchInfoExW( patch_code, package->ProductCode, NULL, package->Context,
INSTALLPROPERTY_LOCALPACKAGEW, patch_file, &len );
@ -908,11 +1015,11 @@ UINT msi_apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code )
ERR("failed to open patch database %s\n", debugstr_w( patch_file ));
return r;
}
si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
if (!si)
r = msi_get_suminfo( patch_db->storage, 0, &si );
if (r != ERROR_SUCCESS)
{
msiobj_release( &patch_db->hdr );
return ERROR_FUNCTION_FAILED;
return r;
}
r = msi_parse_patch_summary( si, &patch_info );
msiobj_release( &si->hdr );
@ -922,6 +1029,7 @@ UINT msi_apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code )
msiobj_release( &patch_db->hdr );
return r;
}
patch_info->registered = TRUE;
patch_info->localfile = strdupW( patch_file );
if (!patch_info->localfile)
{

View file

@ -241,13 +241,6 @@ UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
return ERROR_NO_MORE_ITEMS;
}
if (!pcchVolumeLabel && !pcchDiskPrompt)
{
r = RegEnumValueW(media, dwIndex, NULL, NULL, NULL,
&type, NULL, NULL);
goto done;
}
res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL,
NULL, &numvals, &valuesz, &datasz, NULL, NULL);
if (res != ERROR_SUCCESS)

View file

@ -411,23 +411,22 @@ static MSISTREAM *find_stream( MSIDATABASE *db, const WCHAR *name )
static UINT append_stream( MSIDATABASE *db, const WCHAR *name, IStream *stream )
{
WCHAR decoded[MAX_STREAM_NAME_LEN + 1];
UINT i = db->num_streams;
if (!streams_resize_table( db, db->num_streams + 1 ))
return ERROR_OUTOFMEMORY;
decode_streamname( name, decoded );
db->streams[i].str_index = msi_add_string( db->strings, decoded, -1, StringNonPersistent );
db->streams[i].str_index = msi_add_string( db->strings, name, -1, StringNonPersistent );
db->streams[i].stream = stream;
db->num_streams++;
TRACE("added %s\n", debugstr_w( decoded ));
TRACE("added %s\n", debugstr_w( name ));
return ERROR_SUCCESS;
}
static UINT load_streams( MSIDATABASE *db )
{
WCHAR decoded[MAX_STREAM_NAME_LEN + 1];
IEnumSTATSTG *stgenum;
STATSTG stat;
HRESULT hr;
@ -446,25 +445,29 @@ static UINT load_streams( MSIDATABASE *db )
break;
/* table streams are not in the _Streams table */
if (stat.type != STGTY_STREAM || *stat.pwcsName == 0x4840 ||
find_stream( db, stat.pwcsName ))
if (stat.type != STGTY_STREAM || *stat.pwcsName == 0x4840)
{
CoTaskMemFree( stat.pwcsName );
continue;
}
TRACE("found new stream %s\n", debugstr_w( stat.pwcsName ));
decode_streamname( stat.pwcsName, decoded );
if (find_stream( db, decoded ))
{
CoTaskMemFree( stat.pwcsName );
continue;
}
TRACE("found new stream %s\n", debugstr_w( decoded ));
hr = open_stream( db, stat.pwcsName, &stream );
CoTaskMemFree( stat.pwcsName );
if (FAILED( hr ))
{
ERR("unable to open stream %08x\n", hr);
CoTaskMemFree( stat.pwcsName );
r = ERROR_FUNCTION_FAILED;
break;
}
r = append_stream( db, stat.pwcsName, stream );
CoTaskMemFree( stat.pwcsName );
r = append_stream( db, decoded, stream );
if (r != ERROR_SUCCESS)
break;
}
@ -596,16 +599,9 @@ UINT msi_commit_streams( MSIDATABASE *db )
name = msi_string_lookup( db->strings, db->streams[i].str_index, NULL );
if (!(encname = encode_streamname( FALSE, name ))) return ERROR_OUTOFMEMORY;
hr = open_stream( db, encname, &stream );
if (FAILED( hr )) /* new stream */
hr = IStorage_CreateStream( db->storage, encname, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stream );
if (SUCCEEDED( hr ))
{
hr = IStorage_CreateStream( db->storage, encname, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stream );
if (FAILED( hr ))
{
ERR("failed to create stream %s (hr = %08x)\n", debugstr_w(encname), hr);
msi_free( encname );
return ERROR_FUNCTION_FAILED;
}
hr = write_stream( stream, db->streams[i].stream );
if (FAILED( hr ))
{
@ -614,12 +610,18 @@ UINT msi_commit_streams( MSIDATABASE *db )
IStream_Release( stream );
return ERROR_FUNCTION_FAILED;
}
hr = IStream_Commit( stream, 0 );
IStream_Release( stream );
if (FAILED( hr ))
{
ERR("failed to commit stream %s (hr = %08x)\n", debugstr_w(encname), hr);
msi_free( encname );
return ERROR_FUNCTION_FAILED;
}
}
hr = IStream_Commit( stream, 0 );
IStream_Release( stream );
if (FAILED( hr ))
else if (hr != STG_E_FILEALREADYEXISTS)
{
WARN("failed to commit stream %s (hr = %08x)\n", debugstr_w(encname), hr);
ERR("failed to create stream %s (hr = %08x)\n", debugstr_w(encname), hr);
msi_free( encname );
return ERROR_FUNCTION_FAILED;
}

View file

@ -219,7 +219,6 @@ static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz
static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
{
UINT ret = ERROR_FUNCTION_FAILED;
PROPERTYSETHEADER set_hdr;
FORMATIDOFFSET format_hdr;
PROPERTYSECTIONHEADER section_hdr;
@ -234,44 +233,44 @@ static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
sz = sizeof set_hdr;
r = IStream_Read( stm, &set_hdr, sz, &count );
if( FAILED(r) || count != sz )
return ret;
return ERROR_FUNCTION_FAILED;
if( set_hdr.wByteOrder != 0xfffe )
{
ERR("property set not big-endian %04X\n", set_hdr.wByteOrder);
return ret;
return ERROR_FUNCTION_FAILED;
}
sz = sizeof format_hdr;
r = IStream_Read( stm, &format_hdr, sz, &count );
if( FAILED(r) || count != sz )
return ret;
return ERROR_FUNCTION_FAILED;
/* check the format id is correct */
if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) )
return ret;
return ERROR_FUNCTION_FAILED;
/* seek to the location of the section */
ofs.QuadPart = format_hdr.dwOffset;
r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL );
if( FAILED(r) )
return ret;
return ERROR_FUNCTION_FAILED;
/* read the section itself */
sz = SECT_HDR_SIZE;
r = IStream_Read( stm, &section_hdr, sz, &count );
if( FAILED(r) || count != sz )
return ret;
return ERROR_FUNCTION_FAILED;
if( section_hdr.cProperties > MSI_MAX_PROPS )
{
ERR("too many properties %d\n", section_hdr.cProperties);
return ret;
return ERROR_FUNCTION_FAILED;
}
data = msi_alloc( section_hdr.cbSection);
if( !data )
return ret;
return ERROR_FUNCTION_FAILED;
memcpy( data, &section_hdr, SECT_HDR_SIZE );
@ -284,7 +283,7 @@ static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
ERR("failed to read properties %d %d\n", count, sz);
msi_free( data );
return ret;
return ERROR_SUCCESS;
}
static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val )
@ -410,34 +409,75 @@ static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm )
return ERROR_SUCCESS;
}
MSISUMMARYINFO *MSI_GetSummaryInformationW( IStorage *stg, UINT uiUpdateCount )
static MSISUMMARYINFO *create_suminfo( IStorage *stg, UINT update_count )
{
IStream *stm = NULL;
MSISUMMARYINFO *si;
DWORD grfMode;
HRESULT r;
TRACE("%p %d\n", stg, uiUpdateCount );
if (!(si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, sizeof(MSISUMMARYINFO), MSI_CloseSummaryInfo )))
return NULL;
si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO,
sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
if( !si )
return si;
si->update_count = uiUpdateCount;
si->update_count = update_count;
IStorage_AddRef( stg );
si->storage = stg;
/* read the stream... if we fail, we'll start with an empty property set */
grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
r = IStorage_OpenStream( si->storage, szSumInfo, 0, grfMode, 0, &stm );
if( SUCCEEDED(r) )
return si;
}
UINT msi_get_suminfo( IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **ret )
{
IStream *stm;
MSISUMMARYINFO *si;
HRESULT hr;
UINT r;
TRACE("%p, %u\n", stg, uiUpdateCount);
if (!(si = create_suminfo( stg, uiUpdateCount ))) return ERROR_OUTOFMEMORY;
hr = IStorage_OpenStream( si->storage, szSumInfo, 0, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stm );
if (FAILED( hr ))
{
load_summary_info( si, stm );
IStream_Release( stm );
msiobj_release( &si->hdr );
return ERROR_FUNCTION_FAILED;
}
return si;
r = load_summary_info( si, stm );
IStream_Release( stm );
if (r != ERROR_SUCCESS)
{
msiobj_release( &si->hdr );
return r;
}
*ret = si;
return ERROR_SUCCESS;
}
UINT msi_get_db_suminfo( MSIDATABASE *db, UINT uiUpdateCount, MSISUMMARYINFO **ret )
{
IStream *stm;
MSISUMMARYINFO *si;
UINT r;
if (!(si = create_suminfo( db->storage, uiUpdateCount ))) return ERROR_OUTOFMEMORY;
r = msi_get_stream( db, szSumInfo, &stm );
if (r != ERROR_SUCCESS)
{
msiobj_release( &si->hdr );
return r;
}
r = load_summary_info( si, stm );
IStream_Release( stm );
if (r != ERROR_SUCCESS)
{
msiobj_release( &si->hdr );
return r;
}
*ret = si;
return ERROR_SUCCESS;
}
UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
@ -445,7 +485,7 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
{
MSISUMMARYINFO *si;
MSIDATABASE *db;
UINT ret = ERROR_FUNCTION_FAILED;
UINT ret;
TRACE("%d %s %d %p\n", hDatabase, debugstr_w(szDatabase),
uiUpdateCount, pHandle);
@ -489,8 +529,16 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
}
}
si = MSI_GetSummaryInformationW( db->storage, uiUpdateCount );
if (si)
ret = msi_get_suminfo( db->storage, uiUpdateCount, &si );
if (ret != ERROR_SUCCESS)
ret = msi_get_db_suminfo( db, uiUpdateCount, &si );
if (ret != ERROR_SUCCESS)
{
if ((si = create_suminfo( db->storage, uiUpdateCount )))
ret = ERROR_SUCCESS;
}
if (ret == ERROR_SUCCESS)
{
*pHandle = alloc_msihandle( &si->hdr );
if( *pHandle )
@ -544,26 +592,12 @@ UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, PUINT pCount)
return ERROR_SUCCESS;
}
static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
INT *piValue, FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
static UINT get_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT *puiDataType, INT *piValue,
FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
{
MSISUMMARYINFO *si;
PROPVARIANT *prop;
UINT ret = ERROR_SUCCESS;
TRACE("%d %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
piValue, pftValue, str, pcchValueBuf);
if ( uiProperty >= MSI_MAX_PROPS )
{
if (puiDataType) *puiDataType = VT_EMPTY;
return ERROR_UNKNOWN_PROPERTY;
}
si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
if( !si )
return ERROR_INVALID_HANDLE;
prop = &si->property[uiProperty];
if( puiDataType )
@ -610,7 +644,6 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
FIXME("Unknown property variant type\n");
break;
}
msiobj_release( &si->hdr );
return ret;
}
@ -642,9 +675,10 @@ LPWSTR msi_get_suminfo_product( IStorage *stg )
{
MSISUMMARYINFO *si;
LPWSTR prod;
UINT r;
si = MSI_GetSummaryInformationW( stg, 0 );
if (!si)
r = msi_get_suminfo( stg, 0, &si );
if (r != ERROR_SUCCESS)
{
ERR("no summary information!\n");
return NULL;
@ -658,42 +692,65 @@ UINT WINAPI MsiSummaryInfoGetPropertyA(
MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
FILETIME *pftValue, LPSTR szValueBuf, LPDWORD pcchValueBuf)
{
MSISUMMARYINFO *si;
awstring str;
UINT r;
TRACE("%d %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType,
piValue, pftValue, szValueBuf, pcchValueBuf );
if (uiProperty >= MSI_MAX_PROPS)
{
if (puiDataType) *puiDataType = VT_EMPTY;
return ERROR_UNKNOWN_PROPERTY;
}
if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
return ERROR_INVALID_HANDLE;
str.unicode = FALSE;
str.str.a = szValueBuf;
return get_prop( handle, uiProperty, puiDataType, piValue,
pftValue, &str, pcchValueBuf );
r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf );
msiobj_release( &si->hdr );
return r;
}
UINT WINAPI MsiSummaryInfoGetPropertyW(
MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
FILETIME *pftValue, LPWSTR szValueBuf, LPDWORD pcchValueBuf)
{
MSISUMMARYINFO *si;
awstring str;
UINT r;
TRACE("%d %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType,
piValue, pftValue, szValueBuf, pcchValueBuf );
if (uiProperty >= MSI_MAX_PROPS)
{
if (puiDataType) *puiDataType = VT_EMPTY;
return ERROR_UNKNOWN_PROPERTY;
}
if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
return ERROR_INVALID_HANDLE;
str.unicode = TRUE;
str.str.w = szValueBuf;
return get_prop( handle, uiProperty, puiDataType, piValue,
pftValue, &str, pcchValueBuf );
r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf );
msiobj_release( &si->hdr );
return r;
}
static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type,
INT iValue, FILETIME* pftValue, awcstring *str )
INT iValue, FILETIME *pftValue, awcstring *str )
{
PROPVARIANT *prop;
UINT len;
TRACE("%p %u %u %i %p %p\n", si, uiProperty, type, iValue,
pftValue, str );
TRACE("%p, %u, %u, %d, %p, %p\n", si, uiProperty, type, iValue, pftValue, str );
prop = &si->property[uiProperty];
@ -741,15 +798,15 @@ static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type,
return ERROR_SUCCESS;
}
UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
UINT uiDataType, INT iValue, FILETIME* pftValue, LPCWSTR szValue )
UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
INT iValue, FILETIME *pftValue, LPCWSTR szValue )
{
awcstring str;
MSISUMMARYINFO *si;
UINT type, ret;
TRACE("%d %u %u %i %p %s\n", handle, uiProperty, uiDataType,
iValue, pftValue, debugstr_w(szValue) );
TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue,
debugstr_w(szValue) );
type = get_type( uiProperty );
if( type == VT_EMPTY || type != uiDataType )
@ -761,27 +818,26 @@ UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
if( uiDataType == VT_FILETIME && !pftValue )
return ERROR_INVALID_PARAMETER;
si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
if( !si )
if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
return ERROR_INVALID_HANDLE;
str.unicode = TRUE;
str.str.w = szValue;
ret = set_prop( si, uiProperty, type, iValue, pftValue, &str );
ret = set_prop( si, uiProperty, type, iValue, pftValue, &str );
msiobj_release( &si->hdr );
return ret;
}
UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
UINT uiDataType, INT iValue, FILETIME* pftValue, LPCSTR szValue )
UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
INT iValue, FILETIME *pftValue, LPCSTR szValue )
{
awcstring str;
MSISUMMARYINFO *si;
UINT type, ret;
TRACE("%d %u %u %i %p %s\n", handle, uiProperty, uiDataType,
iValue, pftValue, debugstr_a(szValue) );
TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue,
debugstr_a(szValue) );
type = get_type( uiProperty );
if( type == VT_EMPTY || type != uiDataType )
@ -793,14 +849,13 @@ UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
if( uiDataType == VT_FILETIME && !pftValue )
return ERROR_INVALID_PARAMETER;
si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
if( !si )
if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
return ERROR_INVALID_HANDLE;
str.unicode = FALSE;
str.str.a = szValue;
ret = set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str );
ret = set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str );
msiobj_release( &si->hdr );
return ret;
}
@ -905,15 +960,16 @@ static UINT parse_prop( LPCWSTR prop, LPCWSTR value, UINT *pid, INT *int_value,
UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns )
{
UINT r = ERROR_FUNCTION_FAILED;
UINT r;
int i, j;
MSISUMMARYINFO *si;
si = MSI_GetSummaryInformationW( db->storage, num_records * (num_columns / 2) );
if (!si)
r = msi_get_suminfo( db->storage, num_records * (num_columns / 2), &si );
if (r != ERROR_SUCCESS)
{
ERR("no summary information!\n");
return ERROR_FUNCTION_FAILED;
if (!(si = create_suminfo( db->storage, num_records * (num_columns / 2) )))
return ERROR_OUTOFMEMORY;
r = ERROR_SUCCESS;
}
for (i = 0; i < num_records; i++)
@ -980,3 +1036,57 @@ UINT WINAPI MsiCreateTransformSummaryInfoW( MSIHANDLE db, MSIHANDLE db_ref, LPCW
FIXME("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_w(transform), error, validation);
return ERROR_FUNCTION_FAILED;
}
UINT msi_load_suminfo_properties( MSIPACKAGE *package )
{
static const WCHAR packagecodeW[] = {'P','a','c','k','a','g','e','C','o','d','e',0};
MSISUMMARYINFO *si;
WCHAR *package_code;
UINT r, len;
awstring str;
INT count;
r = msi_get_suminfo( package->db->storage, 0, &si );
if (r != ERROR_SUCCESS)
{
r = msi_get_db_suminfo( package->db, 0, &si );
if (r != ERROR_SUCCESS)
{
ERR("Unable to open summary information stream %u\n", r);
return r;
}
}
str.unicode = TRUE;
str.str.w = NULL;
len = 0;
r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len );
if (r != ERROR_MORE_DATA)
{
WARN("Unable to query revision number %u\n", r);
msiobj_release( &si->hdr );
return ERROR_FUNCTION_FAILED;
}
len++;
if (!(package_code = msi_alloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
str.str.w = package_code;
r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len );
if (r != ERROR_SUCCESS)
{
msi_free( package_code );
msiobj_release( &si->hdr );
return r;
}
r = msi_set_property( package->db, packagecodeW, package_code, len );
msi_free( package_code );
count = 0;
get_prop( si, PID_WORDCOUNT, NULL, &count, NULL, NULL, NULL );
package->WordCount = count;
msiobj_release( &si->hdr );
return r;
}

View file

@ -1035,7 +1035,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
return ERROR_SUCCESS;
}
static UINT msi_stream_name( const MSITABLEVIEW *tv, UINT row, LPWSTR *pstname )
static UINT get_stream_name( const MSITABLEVIEW *tv, UINT row, WCHAR **pstname )
{
LPWSTR p, stname = NULL;
UINT i, r, type, ival;
@ -1135,7 +1135,7 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
if( !view->ops->fetch_int )
return ERROR_INVALID_PARAMETER;
r = msi_stream_name( tv, row, &name );
r = get_stream_name( tv, row, &name );
if (r != ERROR_SUCCESS)
{
ERR("fetching stream, error = %u\n", r);
@ -1197,39 +1197,63 @@ static UINT TABLE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
return msi_view_get_row(tv->db, view, row, rec);
}
static UINT msi_addstreamW( MSIDATABASE *db, LPCWSTR name, IStream *data )
static UINT add_stream( MSIDATABASE *db, const WCHAR *name, IStream *data )
{
static const WCHAR insert[] = {
'I','N','S','E','R','T',' ','I','N','T','O',' ',
'`','_','S','t','r','e','a','m','s','`',' ',
'(','`','N','a','m','e','`',',','`','D','a','t','a','`',')',' ',
'V','A','L','U','E','S',' ','(','?',',','?',')',0};
MSIQUERY *query = NULL;
static const WCHAR update[] = {
'U','P','D','A','T','E',' ','`','_','S','t','r','e','a','m','s','`',' ',
'S','E','T',' ','`','D','a','t','a','`',' ','=',' ','?',' ',
'W','H','E','R','E',' ','`','N','a','m','e','`',' ','=',' ','?',0};
MSIQUERY *query;
MSIRECORD *rec;
UINT r;
TRACE("%p %s %p\n", db, debugstr_w(name), data);
rec = MSI_CreateRecord( 2 );
if ( !rec )
if (!(rec = MSI_CreateRecord( 2 )))
return ERROR_OUTOFMEMORY;
r = MSI_RecordSetStringW( rec, 1, name );
if ( r != ERROR_SUCCESS )
goto err;
if (r != ERROR_SUCCESS)
goto done;
r = MSI_RecordSetIStream( rec, 2, data );
if ( r != ERROR_SUCCESS )
goto err;
if (r != ERROR_SUCCESS)
goto done;
r = MSI_DatabaseOpenViewW( db, insert, &query );
if ( r != ERROR_SUCCESS )
goto err;
if (r != ERROR_SUCCESS)
goto done;
r = MSI_ViewExecute( query, rec );
err:
msiobj_release( &query->hdr );
if (r == ERROR_SUCCESS)
goto done;
msiobj_release( &rec->hdr );
if (!(rec = MSI_CreateRecord( 2 )))
return ERROR_OUTOFMEMORY;
r = MSI_RecordSetIStream( rec, 1, data );
if (r != ERROR_SUCCESS)
goto done;
r = MSI_RecordSetStringW( rec, 2, name );
if (r != ERROR_SUCCESS)
goto done;
r = MSI_DatabaseOpenViewW( db, update, &query );
if (r != ERROR_SUCCESS)
goto done;
r = MSI_ViewExecute( query, rec );
msiobj_release( &query->hdr );
done:
msiobj_release( &rec->hdr );
return r;
}
@ -1326,14 +1350,14 @@ static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UI
if ( r != ERROR_SUCCESS )
return r;
r = msi_stream_name( tv, row, &stname );
r = get_stream_name( tv, row, &stname );
if ( r != ERROR_SUCCESS )
{
IStream_Release( stm );
return r;
}
r = msi_addstreamW( tv->db, stname, stm );
r = add_stream( tv->db, stname, stm );
IStream_Release( stm );
msi_free ( stname );

View file

@ -117,7 +117,7 @@ reactos/dll/win32/msg711.acm # Synced to WineStaging-1.7.47
reactos/dll/win32/msgsm32.acm # Synced to WineStaging-1.7.47
reactos/dll/win32/mshtml # Synced to WineStaging-1.7.37
reactos/dll/win32/mshtml.tlb # Synced to WineStaging-1.7.37
reactos/dll/win32/msi # Synced to WineStaging-1.7.37
reactos/dll/win32/msi # Synced to WineStaging-1.7.47
reactos/dll/win32/msimg32 # Synced to WineStaging-1.7.37
reactos/dll/win32/msimtf # Synced to WineStaging-1.7.37
reactos/dll/win32/msisip # Synced to WineStaging-1.7.37