From 3acd6eee67fcd311ca0b12cc121452e0e5114add Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Sun, 19 Jul 2015 23:04:25 +0000 Subject: [PATCH] [MSI] Sync with Wine Staging 1.7.47. CORE-9924 svn path=/trunk/; revision=68461 --- reactos/dll/win32/msi/CMakeLists.txt | 2 +- reactos/dll/win32/msi/action.c | 101 ++++++--- reactos/dll/win32/msi/assembly.c | 71 +++++- reactos/dll/win32/msi/automation.c | 2 +- reactos/dll/win32/msi/custom.c | 83 ++++--- reactos/dll/win32/msi/database.c | 6 +- reactos/dll/win32/msi/dialog.c | 42 +--- reactos/dll/win32/msi/files.c | 328 +++++++++++++++++---------- reactos/dll/win32/msi/font.c | 1 - reactos/dll/win32/msi/install.c | 2 +- reactos/dll/win32/msi/media.c | 48 ++-- reactos/dll/win32/msi/msi.c | 75 +++--- reactos/dll/win32/msi/msipriv.h | 25 +- reactos/dll/win32/msi/package.c | 168 ++++---------- reactos/dll/win32/msi/patch.c | 248 ++++++++++++++------ reactos/dll/win32/msi/source.c | 7 - reactos/dll/win32/msi/streams.c | 44 ++-- reactos/dll/win32/msi/suminfo.c | 266 +++++++++++++++------- reactos/dll/win32/msi/table.c | 54 +++-- reactos/media/doc/README.WINE | 2 +- 20 files changed, 964 insertions(+), 611 deletions(-) diff --git a/reactos/dll/win32/msi/CMakeLists.txt b/reactos/dll/win32/msi/CMakeLists.txt index 3e5247790f2..daca0f37c4b 100644 --- a/reactos/dll/win32/msi/CMakeLists.txt +++ b/reactos/dll/win32/msi/CMakeLists.txt @@ -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 diff --git a/reactos/dll/win32/msi/action.c b/reactos/dll/win32/msi/action.c index 0816eacb092..c1baa829458 100644 --- a/reactos/dll/win32/msi/action.c +++ b/reactos/dll/win32/msi/action.c @@ -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; } -static void set_target_path( MSIPACKAGE *package, MSIFILE *file ) +BOOL msi_is_global_assembly( MSICOMPONENT *comp ) { - MSIASSEMBLY *assembly = file->Component->assembly; - - TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName)); + return comp->assembly && !comp->assembly->application; +} +static void set_target_path( MSIPACKAGE *package, MSIFILE *file ) +{ 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) { diff --git a/reactos/dll/win32/msi/assembly.c b/reactos/dll/win32/msi/assembly.c index cb8130d5422..84026c29e09 100644 --- a/reactos/dll/win32/msi/assembly.c +++ b/reactos/dll/win32/msi/assembly.c @@ -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}; diff --git a/reactos/dll/win32/msi/automation.c b/reactos/dll/win32/msi/automation.c index dda94301aa1..01a1ac8657a 100644 --- a/reactos/dll/win32/msi/automation.c +++ b/reactos/dll/win32/msi/automation.c @@ -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; diff --git a/reactos/dll/win32/msi/custom.c b/reactos/dll/win32/msi/custom.c index a750c7a3fe7..ad241010042 100644 --- a/reactos/dll/win32/msi/custom.c +++ b/reactos/dll/win32/msi/custom.c @@ -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; } diff --git a/reactos/dll/win32/msi/database.c b/reactos/dll/win32/msi/database.c index e170472b2bb..b815b72e33e 100644 --- a/reactos/dll/win32/msi/database.c +++ b/reactos/dll/win32/msi/database.c @@ -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; } diff --git a/reactos/dll/win32/msi/dialog.c b/reactos/dll/win32/msi/dialog.c index b4c18d68209..3f5c7c55465 100644 --- a/reactos/dll/win32/msi/dialog.c +++ b/reactos/dll/win32/msi/dialog.c @@ -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 ); diff --git a/reactos/dll/win32/msi/files.c b/reactos/dll/win32/msi/files.c index 943bc7b9131..981d568bd83 100644 --- a/reactos/dll/win32/msi/files.c +++ b/reactos/dll/win32/msi/files.c @@ -32,10 +32,9 @@ #include "msipriv.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +#include -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,48 +457,107 @@ 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) - return FALSE; + if (is_registered_patch_media( package, patch->disk_id ) || + !(patch = find_filepatch( package, patch->disk_id, file ))) return FALSE; - GetTempFileNameW(temp_folder, NULL, 0, patch_path); + 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; + } - *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; + patch->extracted = TRUE; + } + + return TRUE; +} - GetTempFileNameW(temp_folder, NULL, 0, patched_file); +static UINT patch_file( MSIPACKAGE *package, MSIFILEPATCH *patch ) +{ + UINT r = ERROR_SUCCESS; + WCHAR *tmpfile = msi_create_temp_file( package->db ); - br = ApplyPatchToFileW(patch_path, p->File->TargetPath, patched_file, 0); - if (br) - { - /* FIXME: baseline cache */ + 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; - DeleteFileW( p->File->TargetPath ); - MoveFileW( patched_file, p->File->TargetPath ); + 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; - p->IsApplied = TRUE; + hr = IAssemblyName_GetDisplayName( name, displayname, &len, 0 ); + if (FAILED( hr )) + { + msi_free( displayname ); + break; } - else - ERR("Failed patch %s: %d.\n", debugstr_w(p->File->TargetPath), GetLastError()); - DeleteFileW(patch_path); - p = NULL; + 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; } - return TRUE; + IAssemblyEnum_Release( iter ); + return r; } UINT ACTION_PatchFiles( MSIPACKAGE *package ) @@ -495,12 +565,13 @@ 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; } } + } + + TRACE("applying patches\n"); - if (!patch->IsApplied && !(patch->Attributes & msidbPatchAttributesNonVital)) + 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; } diff --git a/reactos/dll/win32/msi/font.c b/reactos/dll/win32/msi/font.c index e2a7734aa73..999f884b280 100644 --- a/reactos/dll/win32/msi/font.c +++ b/reactos/dll/win32/msi/font.c @@ -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; } diff --git a/reactos/dll/win32/msi/install.c b/reactos/dll/win32/msi/install.c index da21ad3a04c..5414715df8f 100644 --- a/reactos/dll/win32/msi/install.c +++ b/reactos/dll/win32/msi/install.c @@ -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 ); diff --git a/reactos/dll/win32/msi/media.c b/reactos/dll/win32/msi/media.c index 0b6408d17cd..e7f24c4f6d9 100644 --- a/reactos/dll/win32/msi/media.c +++ b/reactos/dll/win32/msi/media.c @@ -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; } diff --git a/reactos/dll/win32/msi/msi.c b/reactos/dll/win32/msi/msi.c index 0a3e4aa5b90..c7124de3044 100644 --- a/reactos/dll/win32/msi/msi.c +++ b/reactos/dll/win32/msi/msi.c @@ -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,48 +3989,24 @@ 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; - TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash ); - - if (!szFilePath) - return ERROR_INVALID_PARAMETER; - - if (!*szFilePath) - return ERROR_PATH_NOT_FOUND; - - if (dwOptions) - return ERROR_INVALID_PARAMETER; - if (!pHash) - return ERROR_INVALID_PARAMETER; - 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 ); + 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; } - length = GetFileSize( handle, NULL ); - - if (length) + if ((length = GetFileSize( handle, NULL ))) { - mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL ); - if (mapping) + if ((mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL ))) { - p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length ); - if (p) + if ((p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length ))) { MD5_CTX ctx; @@ -4039,7 +4015,7 @@ UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions, MD5Final( &ctx ); UnmapViewOfFile( p ); - memcpy( pHash->dwData, ctx.digest, sizeof pHash->dwData ); + memcpy( hash->dwData, ctx.digest, sizeof(hash->dwData) ); r = ERROR_SUCCESS; } CloseHandle( mapping ); @@ -4048,15 +4024,38 @@ UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions, else { /* Empty file -> set hash to 0 */ - memset( pHash->dwData, 0, sizeof pHash->dwData ); + 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) + return ERROR_INVALID_PARAMETER; + + if (!*szFilePath) + return ERROR_PATH_NOT_FOUND; + + if (dwOptions) + return ERROR_INVALID_PARAMETER; + if (!pHash) + return ERROR_INVALID_PARAMETER; + if (pHash->dwFileHashInfoSize < sizeof *pHash) + return ERROR_INVALID_PARAMETER; + + return msi_get_filehash( szFilePath, pHash ); +} + /*********************************************************************** * MsiGetFileHashA [MSI.@] */ @@ -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); diff --git a/reactos/dll/win32/msi/msipriv.h b/reactos/dll/win32/msi/msipriv.h index a3f9df4c2ae..3dea4866c15 100644 --- a/reactos/dll/win32/msi/msipriv.h +++ b/reactos/dll/win32/msi/msipriv.h @@ -53,7 +53,7 @@ #include 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; diff --git a/reactos/dll/win32/msi/package.c b/reactos/dll/win32/msi/package.c index 69698b73b56..37afba890be 100644 --- a/reactos/dll/win32/msi/package.c +++ b/reactos/dll/win32/msi/package.c @@ -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; } diff --git a/reactos/dll/win32/msi/patch.c b/reactos/dll/win32/msi/patch.c index 6025c9780a4..d18ee53815c 100644 --- a/reactos/dll/win32/msi/patch.c +++ b/reactos/dll/win32/msi/patch.c @@ -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_offset_modify_db( MSIDATABASE *db, struct patch_offset_list *pos ) +static UINT patch_update_file_sequence( MSIDATABASE *db, const struct patch_offset_list *pos, + MSIQUERY *view, MSIRECORD *rec ) { - 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; + 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 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 ); - { - UINT offset = db->media_transform_offset - pos->min; - last_sequence = offset + pos->max; + patch_offset_get_filepatches( db, last_sequence, pos ); - /* 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 ); + offset = db->media_transform_offset - pos->min; + last_sequence = offset + pos->max; - MSI_RecordSetInteger( rec, 2, last_sequence ); - r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec ); + last_sequence += pos->min; + pos->offset_to_apply = offset; + if (pos->count) + { + 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) { diff --git a/reactos/dll/win32/msi/source.c b/reactos/dll/win32/msi/source.c index ecfcde4c6d0..adb5a8659dd 100644 --- a/reactos/dll/win32/msi/source.c +++ b/reactos/dll/win32/msi/source.c @@ -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) diff --git a/reactos/dll/win32/msi/streams.c b/reactos/dll/win32/msi/streams.c index bca1c0125a0..642093e92cc 100644 --- a/reactos/dll/win32/msi/streams.c +++ b/reactos/dll/win32/msi/streams.c @@ -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; + } + decode_streamname( stat.pwcsName, decoded ); + if (find_stream( db, decoded )) { CoTaskMemFree( stat.pwcsName ); continue; } - TRACE("found new stream %s\n", debugstr_w( stat.pwcsName )); + 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,30 +599,29 @@ 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 ); + hr = write_stream( stream, db->streams[i].stream ); if (FAILED( hr )) { - ERR("failed to create stream %s (hr = %08x)\n", debugstr_w(encname), hr); + ERR("failed to write stream %s (hr = %08x)\n", debugstr_w(encname), hr); msi_free( encname ); + IStream_Release( stream ); return ERROR_FUNCTION_FAILED; } - hr = write_stream( stream, db->streams[i].stream ); + hr = IStream_Commit( stream, 0 ); + IStream_Release( stream ); if (FAILED( hr )) { - ERR("failed to write stream %s (hr = %08x)\n", debugstr_w(encname), hr); + ERR("failed to commit stream %s (hr = %08x)\n", debugstr_w(encname), hr); msi_free( encname ); - IStream_Release( stream ); 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; } diff --git a/reactos/dll/win32/msi/suminfo.c b/reactos/dll/win32/msi/suminfo.c index 5d23ab6a2dc..f4ded7f2530 100644 --- a/reactos/dll/win32/msi/suminfo.c +++ b/reactos/dll/win32/msi/suminfo.c @@ -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, §ion_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, §ion_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 ); - si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, - sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo ); - if( !si ) - return si; + if (!(si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, sizeof(MSISUMMARYINFO), MSI_CloseSummaryInfo ))) + return NULL; - 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; +} diff --git a/reactos/dll/win32/msi/table.c b/reactos/dll/win32/msi/table.c index a5ac8bd9a68..8c440d52e0f 100644 --- a/reactos/dll/win32/msi/table.c +++ b/reactos/dll/win32/msi/table.c @@ -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 ); + msiobj_release( &query->hdr ); + if (r == ERROR_SUCCESS) + goto done; -err: + 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 ); diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index e6f4bded692..9993b9374fa 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -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 -- 2.17.1