From 102b741c7eade8c26e89241109495a84bf059908 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Mon, 9 Mar 2015 20:28:19 +0000 Subject: [PATCH] [MSI] Sync with Wine Staging 1.7.37. CORE-9246 svn path=/trunk/; revision=66632 --- reactos/dll/win32/msi/action.c | 142 +++----- reactos/dll/win32/msi/assembly.c | 4 +- reactos/dll/win32/msi/database.c | 170 +--------- reactos/dll/win32/msi/dialog.c | 3 +- reactos/dll/win32/msi/media.c | 22 +- reactos/dll/win32/msi/msi.c | 108 +++++- reactos/dll/win32/msi/msi.rc | 8 +- reactos/dll/win32/msi/msi.spec | 19 +- reactos/dll/win32/msi/msipriv.h | 29 +- reactos/dll/win32/msi/msiquery.c | 9 +- reactos/dll/win32/msi/package.c | 19 +- reactos/dll/win32/msi/patch.c | 233 +++++++++++-- reactos/dll/win32/msi/registry.c | 29 +- reactos/dll/win32/msi/script.c | 2 +- reactos/dll/win32/msi/storages.c | 2 +- reactos/dll/win32/msi/streams.c | 556 ++++++++++++++++++------------- reactos/dll/win32/msi/string.c | 22 +- reactos/dll/win32/msi/table.c | 46 ++- reactos/media/doc/README.WINE | 2 +- 19 files changed, 803 insertions(+), 622 deletions(-) diff --git a/reactos/dll/win32/msi/action.c b/reactos/dll/win32/msi/action.c index dc04a7d64f9..0816eacb092 100644 --- a/reactos/dll/win32/msi/action.c +++ b/reactos/dll/win32/msi/action.c @@ -2407,7 +2407,6 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) sprintfW( buf, fmtW, free.QuadPart / 512 ); msi_set_property( package->db, szPrimaryVolumeSpaceAvailable, buf, -1 ); } - toupperW( primary_folder[0] ); msi_set_property( package->db, szPrimaryVolumePath, primary_folder, 2 ); } msi_free( primary_folder ); @@ -2422,9 +2421,9 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) return MSI_SetFeatureStates(package); } -static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD *type, DWORD *size ) +static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD len, DWORD *type, DWORD *size ) { - BYTE *data = NULL; + BYTE *data; if (!value) { @@ -2513,19 +2512,18 @@ static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD *type, else { const WCHAR *ptr = value; - DWORD len; *type = REG_SZ; if (value[0] == '#') { - ptr++; + ptr++; len--; if (value[1] == '%') { - ptr++; + ptr++; len--; *type = REG_EXPAND_SZ; } } - len = deformat_string( package, ptr, (WCHAR **)&data ); + data = (BYTE *)msi_strdupW( ptr, len ); if (len > strlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ; *size = (len + 1) * sizeof(WCHAR); } @@ -2574,38 +2572,22 @@ static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key return ret; } -static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path ) +static inline REGSAM get_registry_view( const MSICOMPONENT *comp ) { - static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'}; - static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]); - - if ((is_64bit || is_wow64) && - !(comp->Attributes & msidbComponentAttributes64bit) && - root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len )) - { - UINT size; - WCHAR *path_32node; - - size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR); - if (!(path_32node = msi_alloc( size ))) return NULL; - - memcpy( path_32node, path, len * sizeof(WCHAR) ); - strcpyW( path_32node + len, szWow6432Node ); - strcatW( path_32node, szBackSlash ); - strcatW( path_32node, path + len ); - return path_32node; - } - return strdupW( path ); + REGSAM view = 0; + if (is_wow64 || is_64bit) + view |= (comp->Attributes & msidbComponentAttributes64bit) ? KEY_WOW64_64KEY : KEY_WOW64_32KEY; + return view; } -static HKEY open_key( HKEY root, const WCHAR *path, BOOL create ) +static HKEY open_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, BOOL create ) { REGSAM access = KEY_ALL_ACCESS; WCHAR *subkey, *p, *q; HKEY hkey, ret = NULL; LONG res; - if (is_wow64) access |= KEY_WOW64_64KEY; + access |= get_registry_view( comp ); if (!(subkey = strdupW( path ))) return NULL; p = subkey; @@ -2622,7 +2604,7 @@ static HKEY open_key( HKEY root, const WCHAR *path, BOOL create ) } if (q && q[1]) { - ret = open_key( hkey, q + 1, create ); + ret = open_key( comp, hkey, q + 1, create ); RegCloseKey( hkey ); } else ret = hkey; @@ -2803,7 +2785,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) BYTE *new_value, *old_value = NULL; HKEY root_key, hkey; DWORD type, old_type, new_size, old_size = 0; - LPWSTR deformated, uikey, keypath; + LPWSTR deformated, uikey; const WCHAR *szRoot, *component, *name, *key, *str; MSICOMPONENT *comp; MSIRECORD * uirow; @@ -2847,23 +2829,19 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) strcpyW(uikey,szRoot); strcatW(uikey,deformated); - keypath = get_keypath( comp, root_key, deformated ); - msi_free( deformated ); - if (!(hkey = open_key( root_key, keypath, TRUE ))) + if (!(hkey = open_key( comp, root_key, deformated, TRUE ))) { - ERR("Could not create key %s\n", debugstr_w(keypath)); + ERR("Could not create key %s\n", debugstr_w(deformated)); msi_free(uikey); - msi_free(keypath); + msi_free(deformated); return ERROR_FUNCTION_FAILED; } - str = msi_record_get_string( row, 5, &len ); - if (str && len > strlenW( str )) - { - type = REG_MULTI_SZ; - new_size = (len + 1) * sizeof(WCHAR); - new_value = (BYTE *)msi_strdupW( str, len ); - } - else new_value = parse_value( package, str, &type, &new_size ); + msi_free( deformated ); + str = msi_record_get_string( row, 5, NULL ); + len = deformat_string( package, str, &deformated ); + new_value = parse_value( package, deformated, len, &type, &new_size ); + + msi_free( deformated ); deformat_string(package, name, &deformated); if (!is_special_entry( name )) @@ -2911,7 +2889,6 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) msi_free(old_value); msi_free(deformated); msi_free(uikey); - msi_free(keypath); return ERROR_SUCCESS; } @@ -2933,20 +2910,20 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) return rc; } -static void delete_key( HKEY root, const WCHAR *path ) +static void delete_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path ) { REGSAM access = 0; WCHAR *subkey, *p; HKEY hkey; LONG res; - if (is_wow64) access |= KEY_WOW64_64KEY; + access |= get_registry_view( comp ); if (!(subkey = strdupW( path ))) return; for (;;) { if ((p = strrchrW( subkey, '\\' ))) *p = 0; - hkey = open_key( root, subkey, FALSE ); + hkey = open_key( comp, root, subkey, FALSE ); if (!hkey) break; if (p && p[1]) res = RegDeleteKeyExW( hkey, p + 1, access, 0 ); @@ -2963,13 +2940,13 @@ static void delete_key( HKEY root, const WCHAR *path ) msi_free( subkey ); } -static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value ) +static void delete_value( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, const WCHAR *value ) { LONG res; HKEY hkey; DWORD num_subkeys, num_values; - if ((hkey = open_key( root, path, FALSE ))) + if ((hkey = open_key( comp, root, path, FALSE ))) { if ((res = RegDeleteValueW( hkey, value ))) TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res); @@ -2980,20 +2957,20 @@ static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value ) if (!res && !num_subkeys && !num_values) { TRACE("removing empty key %s\n", debugstr_w(path)); - delete_key( root, path ); + delete_key( comp, root, path ); } } } -static void delete_tree( HKEY root, const WCHAR *path ) +static void delete_tree( const MSICOMPONENT *comp, HKEY root, const WCHAR *path ) { LONG res; HKEY hkey; - if (!(hkey = open_key( root, path, FALSE ))) return; + if (!(hkey = open_key( comp, root, path, FALSE ))) return; res = SHDeleteKeyW( hkey, NULL ); if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res); - delete_key( root, path ); + delete_key( comp, root, path ); RegCloseKey( hkey ); } @@ -3001,7 +2978,7 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para { MSIPACKAGE *package = param; LPCWSTR component, name, key_str, root_key_str; - LPWSTR deformated_key, deformated_name, ui_key_str, keypath; + LPWSTR deformated_key, deformated_name, ui_key_str; MSICOMPONENT *comp; MSIRECORD *uirow; BOOL delete_key = FALSE; @@ -3050,11 +3027,9 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para deformat_string( package, name, &deformated_name ); - keypath = get_keypath( comp, hkey_root, deformated_key ); + if (delete_key) delete_tree( comp, hkey_root, deformated_key ); + else delete_value( comp, hkey_root, deformated_key, deformated_name ); msi_free( deformated_key ); - if (delete_key) delete_tree( hkey_root, keypath ); - else delete_value( hkey_root, keypath, deformated_name ); - msi_free( keypath ); uirow = MSI_CreateRecord( 2 ); MSI_RecordSetStringW( uirow, 1, ui_key_str ); @@ -3071,7 +3046,7 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param { MSIPACKAGE *package = param; LPCWSTR component, name, key_str, root_key_str; - LPWSTR deformated_key, deformated_name, ui_key_str, keypath; + LPWSTR deformated_key, deformated_name, ui_key_str; MSICOMPONENT *comp; MSIRECORD *uirow; BOOL delete_key = FALSE; @@ -3115,11 +3090,9 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param deformat_string( package, name, &deformated_name ); - keypath = get_keypath( comp, hkey_root, deformated_key ); + if (delete_key) delete_tree( comp, hkey_root, deformated_key ); + else delete_value( comp, hkey_root, deformated_key, deformated_name ); msi_free( deformated_key ); - if (delete_key) delete_tree( hkey_root, keypath ); - else delete_value( hkey_root, keypath, deformated_name ); - msi_free( keypath ); uirow = MSI_CreateRecord( 2 ); MSI_RecordSetStringW( uirow, 1, ui_key_str ); @@ -5300,7 +5273,7 @@ static UINT ACTION_InstallFinalize(MSIPACKAGE *package) WCHAR *remove; /* first do the same as an InstallExecute */ - rc = ACTION_InstallExecute(package); + rc = execute_script(package, SCRIPT_INSTALL); if (rc != ERROR_SUCCESS) return rc; @@ -5940,24 +5913,21 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) if (!comp) return ERROR_SUCCESS; + event = MSI_RecordGetInteger( rec, 3 ); + deformat_string( package, MSI_RecordGetString( rec, 2 ), &name ); + comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) + if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStart)) && + !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStart))) { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); + TRACE("not starting %s\n", debugstr_w(name)); + msi_free( name ); return ERROR_SUCCESS; } - deformat_string(package, MSI_RecordGetString(rec, 2), &name); deformat_string(package, MSI_RecordGetString(rec, 4), &args); - event = MSI_RecordGetInteger(rec, 3); wait = MSI_RecordGetInteger(rec, 5); - if (!(event & msidbServiceControlEventStart)) - { - r = ERROR_SUCCESS; - goto done; - } - scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if (!scm) { @@ -6147,23 +6117,24 @@ static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param ) MSICOMPONENT *comp; MSIRECORD *uirow; LPCWSTR component; - LPWSTR name = NULL, display_name = NULL; + WCHAR *name, *display_name = NULL; DWORD event, len; SC_HANDLE scm; - event = MSI_RecordGetInteger( rec, 3 ); - if (!(event & msidbServiceControlEventStop)) - return ERROR_SUCCESS; - component = MSI_RecordGetString( rec, 6 ); comp = msi_get_loaded_component( package, component ); if (!comp) return ERROR_SUCCESS; + event = MSI_RecordGetInteger( rec, 3 ); + deformat_string( package, MSI_RecordGetString( rec, 2 ), &name ); + comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) + if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStop)) && + !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStop))) { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); + TRACE("not stopping %s\n", debugstr_w(name)); + msi_free( name ); return ERROR_SUCCESS; } @@ -6183,7 +6154,6 @@ static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param ) } CloseServiceHandle( scm ); - deformat_string( package, MSI_RecordGetString( rec, 2 ), &name ); stop_service( name ); done: @@ -6982,6 +6952,7 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) data = msi_alloc(size); if (!data) { + msi_free(deformatted); RegCloseKey(env); return ERROR_OUTOFMEMORY; } @@ -7801,10 +7772,7 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, package->full_reinstall = 1; } - /* properties may have been added by a transform */ - msi_clone_properties( package ); msi_set_original_database_property( package->db, szPackagePath ); - msi_parse_command_line( package, szCommandLine, FALSE ); msi_adjust_privilege_properties( package ); msi_set_context( package ); diff --git a/reactos/dll/win32/msi/assembly.c b/reactos/dll/win32/msi/assembly.c index d7939e8fc8f..cb8130d5422 100644 --- a/reactos/dll/win32/msi/assembly.c +++ b/reactos/dll/win32/msi/assembly.c @@ -242,7 +242,7 @@ static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_n memset( &info, 0, sizeof(info) ); info.cbAssemblyInfo = sizeof(info); hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, display_name, &info ); - if (hr == S_OK /* sxs version */ || hr == HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER )) + if (hr == S_OK /* sxs version */ || hr == E_NOT_SUFFICIENT_BUFFER) { return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED); } @@ -348,7 +348,7 @@ static enum clr_version get_clr_version( const WCHAR *filename ) if (!pGetFileVersion) return CLR_VERSION_V10; hr = pGetFileVersion( filename, NULL, 0, &len ); - if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) return CLR_VERSION_V11; + if (hr != E_NOT_SUFFICIENT_BUFFER) return CLR_VERSION_V11; if ((strW = msi_alloc( len * sizeof(WCHAR) ))) { hr = pGetFileVersion( filename, strW, len, &len ); diff --git a/reactos/dll/win32/msi/database.c b/reactos/dll/win32/msi/database.c index 66b79f99b48..e170472b2bb 100644 --- a/reactos/dll/win32/msi/database.c +++ b/reactos/dll/win32/msi/database.c @@ -36,179 +36,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); #define IS_INTMSIDBOPEN(x) (((ULONG_PTR)(x) >> 16) == 0) -typedef struct tagMSITRANSFORM { - struct list entry; - IStorage *stg; -} MSITRANSFORM; - -typedef struct tagMSISTREAM { - struct list entry; - IStorage *stg; - IStream *stm; -} MSISTREAM; - -static UINT find_open_stream( MSIDATABASE *db, IStorage *stg, LPCWSTR name, IStream **stm ) -{ - MSISTREAM *stream; - - LIST_FOR_EACH_ENTRY( stream, &db->streams, MSISTREAM, entry ) - { - HRESULT r; - STATSTG stat; - - if (stream->stg != stg) continue; - - r = IStream_Stat( stream->stm, &stat, 0 ); - if( FAILED( r ) ) - { - WARN("failed to stat stream r = %08x!\n", r); - continue; - } - - if( !strcmpW( name, stat.pwcsName ) ) - { - TRACE("found %s\n", debugstr_w(name)); - *stm = stream->stm; - CoTaskMemFree( stat.pwcsName ); - return ERROR_SUCCESS; - } - - CoTaskMemFree( stat.pwcsName ); - } - - return ERROR_FUNCTION_FAILED; -} - -UINT msi_clone_open_stream( MSIDATABASE *db, IStorage *stg, LPCWSTR name, IStream **stm ) -{ - IStream *stream; - - if (find_open_stream( db, stg, name, &stream ) == ERROR_SUCCESS) - { - HRESULT r; - LARGE_INTEGER pos; - - r = IStream_Clone( stream, stm ); - if( FAILED( r ) ) - { - WARN("failed to clone stream r = %08x!\n", r); - return ERROR_FUNCTION_FAILED; - } - - pos.QuadPart = 0; - r = IStream_Seek( *stm, pos, STREAM_SEEK_SET, NULL ); - if( FAILED( r ) ) - { - IStream_Release( *stm ); - return ERROR_FUNCTION_FAILED; - } - - return ERROR_SUCCESS; - } - - return ERROR_FUNCTION_FAILED; -} - -UINT msi_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm ) -{ - HRESULT r; - IStorage *stg; - WCHAR decoded[MAX_STREAM_NAME_LEN + 1]; - - decode_streamname( stname, decoded ); - TRACE("%s -> %s\n", debugstr_w(stname), debugstr_w(decoded)); - - if (msi_clone_open_stream( db, db->storage, stname, stm ) == ERROR_SUCCESS) - return ERROR_SUCCESS; - - r = IStorage_OpenStream( db->storage, stname, NULL, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm ); - if( FAILED( r ) ) - { - MSITRANSFORM *transform; - - LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry ) - { - r = IStorage_OpenStream( transform->stg, stname, NULL, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm ); - if (SUCCEEDED(r)) - { - stg = transform->stg; - break; - } - } - } - else stg = db->storage; - - if( SUCCEEDED(r) ) - { - MSISTREAM *stream; - - if (!(stream = msi_alloc( sizeof(MSISTREAM) ))) return ERROR_NOT_ENOUGH_MEMORY; - stream->stg = stg; - IStorage_AddRef( stg ); - stream->stm = *stm; - IStream_AddRef( *stm ); - list_add_tail( &db->streams, &stream->entry ); - } - - return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED; -} - static void free_transforms( MSIDATABASE *db ) { while( !list_empty( &db->transforms ) ) { - MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ), - MSITRANSFORM, entry ); + MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ), MSITRANSFORM, entry ); list_remove( &t->entry ); IStorage_Release( t->stg ); msi_free( t ); } } -void msi_destroy_stream( MSIDATABASE *db, const WCHAR *stname ) -{ - MSISTREAM *stream, *stream2; - - LIST_FOR_EACH_ENTRY_SAFE( stream, stream2, &db->streams, MSISTREAM, entry ) - { - HRESULT r; - STATSTG stat; - - r = IStream_Stat( stream->stm, &stat, 0 ); - if (FAILED(r)) - { - WARN("failed to stat stream r = %08x\n", r); - continue; - } - - if (!strcmpW( stname, stat.pwcsName )) - { - TRACE("destroying %s\n", debugstr_w(stname)); - - list_remove( &stream->entry ); - IStream_Release( stream->stm ); - IStorage_Release( stream->stg ); - IStorage_DestroyElement( stream->stg, stname ); - msi_free( stream ); - CoTaskMemFree( stat.pwcsName ); - break; - } - CoTaskMemFree( stat.pwcsName ); - } -} - static void free_streams( MSIDATABASE *db ) { - while( !list_empty( &db->streams ) ) + UINT i; + for (i = 0; i < db->num_streams; i++) { - MSISTREAM *s = LIST_ENTRY(list_head( &db->streams ), MSISTREAM, entry); - list_remove( &s->entry ); - IStream_Release( s->stm ); - IStorage_Release( s->stg ); - msi_free( s ); + if (db->streams[i].stream) IStream_Release( db->streams[i].stream ); } + msi_free( db->streams ); } void append_storage_to_db( MSIDATABASE *db, IStorage *stg ) @@ -219,9 +65,6 @@ void append_storage_to_db( MSIDATABASE *db, IStorage *stg ) t->stg = stg; IStorage_AddRef( stg ); list_add_head( &db->transforms, &t->entry ); - - /* the transform may add or replace streams */ - free_streams( db ); } static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) @@ -229,8 +72,8 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) MSIDATABASE *db = (MSIDATABASE *) arg; msi_free(db->path); - free_cached_tables( db ); free_streams( db ); + free_cached_tables( db ); free_transforms( db ); if (db->strings) msi_destroy_stringtable( db->strings ); IStorage_Release( db->storage ); @@ -413,7 +256,6 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) db->deletefile = strdupW( szDBPath ); list_init( &db->tables ); list_init( &db->transforms ); - list_init( &db->streams ); db->strings = msi_load_string_table( stg, &db->bytes_per_strref ); if( !db->strings ) diff --git a/reactos/dll/win32/msi/dialog.c b/reactos/dll/win32/msi/dialog.c index 9959bd1287e..b4c18d68209 100644 --- a/reactos/dll/win32/msi/dialog.c +++ b/reactos/dll/win32/msi/dialog.c @@ -135,7 +135,6 @@ static const WCHAR szVolumeCostList[] = { 'V','o','l','u','m','e','C','o','s','t static const WCHAR szVolumeSelectCombo[] = { 'V','o','l','u','m','e','S','e','l','e','c','t','C','o','m','b','o',0 }; static const WCHAR szSelectionDescription[] = {'S','e','l','e','c','t','i','o','n','D','e','s','c','r','i','p','t','i','o','n',0}; static const WCHAR szSelectionPath[] = {'S','e','l','e','c','t','i','o','n','P','a','t','h',0}; -static const WCHAR szProperty[] = {'P','r','o','p','e','r','t','y',0}; static const WCHAR szHyperLink[] = {'H','y','p','e','r','L','i','n','k',0}; /* dialog sequencing */ @@ -2152,7 +2151,7 @@ static void msi_dialog_update_pathedit( msi_dialog *dialog, msi_control *control /* FIXME: test when this should fail */ static BOOL msi_dialog_verify_path( LPWSTR path ) { - if ( !lstrlenW( path ) ) + if ( !path[0] ) return FALSE; if ( PathIsRelativeW( path ) ) diff --git a/reactos/dll/win32/msi/media.c b/reactos/dll/win32/msi/media.c index 3d0eb8a9182..0b6408d17cd 100644 --- a/reactos/dll/win32/msi/media.c +++ b/reactos/dll/win32/msi/media.c @@ -216,15 +216,12 @@ static INT_PTR CDECL cabinet_open_stream( char *pszFile, int oflag, int pmode ) WARN("failed to encode stream name\n"); return -1; } - if (msi_clone_open_stream( package_disk.package->db, cab->storage, encoded, &stream ) != ERROR_SUCCESS) + hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream ); + if (FAILED(hr)) { - hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream ); - if (FAILED(hr)) - { - WARN("failed to open stream 0x%08x\n", hr); - msi_free( encoded ); - return -1; - } + WARN("failed to open stream 0x%08x\n", hr); + msi_free( encoded ); + return -1; } msi_free( encoded ); return (INT_PTR)stream; @@ -287,9 +284,6 @@ static UINT CDECL msi_media_get_disk_info(MSIPACKAGE *package, MSIMEDIAINFO *mi) mi->cabinet = strdupW(MSI_RecordGetString(row, 4)); mi->volume_label = strdupW(MSI_RecordGetString(row, 5)); - if (!mi->first_volume) - mi->first_volume = strdupW(mi->volume_label); - msiobj_release(&row->hdr); return ERROR_SUCCESS; } @@ -662,7 +656,6 @@ void msi_free_media_info(MSIMEDIAINFO *mi) msi_free(mi->disk_prompt); msi_free(mi->cabinet); msi_free(mi->volume_label); - msi_free(mi->first_volume); msi_free(mi); } @@ -708,9 +701,6 @@ UINT msi_load_media_info(MSIPACKAGE *package, UINT Sequence, MSIMEDIAINFO *mi) mi->volume_label = strdupW(MSI_RecordGetString(row, 5)); msiobj_release(&row->hdr); - if (!mi->first_volume) - mi->first_volume = strdupW(mi->volume_label); - msi_set_sourcedir_props(package, FALSE); source_dir = msi_dup_property(package->db, szSourceDir); lstrcpyW(mi->sourcedir, source_dir); @@ -880,7 +870,7 @@ UINT ready_media( MSIPACKAGE *package, BOOL compressed, MSIMEDIAINFO *mi ) } } /* check volume matches, change media if not */ - if (mi->volume_label && mi->disk_id > 1 && strcmpW( mi->first_volume, mi->volume_label )) + if (mi->volume_label && mi->disk_id > 1) { WCHAR *source = msi_dup_property( package->db, szSourceDir ); BOOL match = source_matches_volume( mi, source ); diff --git a/reactos/dll/win32/msi/msi.c b/reactos/dll/win32/msi/msi.c index 6bf53288d82..0a3e4aa5b90 100644 --- a/reactos/dll/win32/msi/msi.c +++ b/reactos/dll/win32/msi/msi.c @@ -1738,10 +1738,6 @@ UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode, datakey = patch; szProperty = szInstalled; } - else if (!strcmpW( szProperty, INSTALLPROPERTY_LOCALPACKAGEW )) - { - datakey = udpatch; - } else if (!strcmpW( szProperty, INSTALLPROPERTY_UNINSTALLABLEW ) || !strcmpW( szProperty, INSTALLPROPERTY_PATCHSTATEW ) || !strcmpW( szProperty, INSTALLPROPERTY_DISPLAYNAMEW ) || @@ -4178,6 +4174,92 @@ UINT WINAPI MsiInstallMissingComponentW(LPCWSTR szProduct, LPCWSTR szComponent, return ERROR_SUCCESS; } +UINT WINAPI MsiProvideComponentA( LPCSTR product, LPCSTR feature, LPCSTR component, DWORD mode, LPSTR buf, LPDWORD buflen ) +{ + WCHAR *productW = NULL, *componentW = NULL, *featureW = NULL, *bufW = NULL; + UINT r = ERROR_OUTOFMEMORY; + DWORD lenW; + int len; + + TRACE("%s, %s, %s, %x, %p, %p\n", debugstr_a(product), debugstr_a(component), debugstr_a(feature), mode, buf, buflen); + + if (product && !(productW = strdupAtoW( product ))) goto done; + if (feature && !(featureW = strdupAtoW( feature ))) goto done; + if (component && !(componentW = strdupAtoW( component ))) goto done; + + r = MsiProvideComponentW( productW, featureW, componentW, mode, NULL, &lenW ); + if (r != ERROR_SUCCESS) + goto done; + + if (!(bufW = msi_alloc( ++lenW * sizeof(WCHAR) ))) + { + r = ERROR_OUTOFMEMORY; + goto done; + } + + r = MsiProvideComponentW( productW, featureW, componentW, mode, bufW, &lenW ); + if (r != ERROR_SUCCESS) + goto done; + + len = WideCharToMultiByte( CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL ); + if (buf) + { + if (len > *buflen) + r = ERROR_MORE_DATA; + else + WideCharToMultiByte( CP_ACP, 0, bufW, -1, buf, *buflen, NULL, NULL ); + } + + *buflen = len - 1; + +done: + msi_free( productW ); + msi_free( featureW ); + msi_free( componentW ); + msi_free( bufW ); + return r; +} + +UINT WINAPI MsiProvideComponentW( LPCWSTR product, LPCWSTR feature, LPCWSTR component, DWORD mode, LPWSTR buf, LPDWORD buflen ) +{ + INSTALLSTATE state; + + TRACE("%s, %s, %s, %x, %p, %p\n", debugstr_w(product), debugstr_w(component), debugstr_w(feature), mode, buf, buflen); + + state = MsiQueryFeatureStateW( product, feature ); + TRACE("feature state: %d\n", state); + switch (mode) + { + case INSTALLMODE_NODETECTION: + break; + + default: + FIXME("mode %x not implemented\n", mode); + return ERROR_INSTALL_FAILURE; + } + + state = MsiGetComponentPathW( product, component, buf, buflen ); + TRACE("component state: %d\n", state); + switch (state) + { + case INSTALLSTATE_INVALIDARG: + return ERROR_INVALID_PARAMETER; + + case INSTALLSTATE_MOREDATA: + return ERROR_MORE_DATA; + + case INSTALLSTATE_ADVERTISED: + case INSTALLSTATE_LOCAL: + case INSTALLSTATE_SOURCE: + MsiUseFeatureW( product, feature ); + return ERROR_SUCCESS; + + default: + TRACE("MsiGetComponentPathW returned %d\n", state); + return ERROR_INSTALL_FAILURE; + } +} + /*********************************************************************** * MsiBeginTransactionA [MSI.@] */ @@ -4224,3 +4306,21 @@ UINT WINAPI Migrate10CachedPackagesW(void* a, void* b, void* c, DWORD d) FIXME("%p,%p,%p,%08x\n", a, b, c, d); return ERROR_SUCCESS; } + +/*********************************************************************** + * MsiRemovePatchesA [MSI.@] + */ +UINT WINAPI MsiRemovePatchesA(LPCSTR patchlist, LPCSTR product, INSTALLTYPE type, LPCSTR propertylist) +{ + FIXME("(%s %s %d %s\n", debugstr_a(patchlist), debugstr_a(product), type, debugstr_a(propertylist)); + return ERROR_SUCCESS; +} + +/*********************************************************************** + * MsiRemovePatchesW [MSI.@] + */ +UINT WINAPI MsiRemovePatchesW(LPCWSTR patchlist, LPCWSTR product, INSTALLTYPE type, LPCWSTR propertylist) +{ + FIXME("(%s %s %d %s\n", debugstr_w(patchlist), debugstr_w(product), type, debugstr_w(propertylist)); + return ERROR_SUCCESS; +} diff --git a/reactos/dll/win32/msi/msi.rc b/reactos/dll/win32/msi/msi.rc index 5597391a13f..7bcadb24447 100644 --- a/reactos/dll/win32/msi/msi.rc +++ b/reactos/dll/win32/msi/msi.rc @@ -84,9 +84,9 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL #define WINE_FILEDESCRIPTION_STR "Wine MSI dll" #define WINE_FILENAME_STR "msi.dll" -#define WINE_FILEVERSION 4,5,6001,22299 -#define WINE_FILEVERSION_STR "4.5.6001.22299" -#define WINE_PRODUCTVERSION 4,5,6001,22299 -#define WINE_PRODUCTVERSION_STR "4.5.6001.22299" +#define WINE_FILEVERSION 4,5,6001,22308 +#define WINE_FILEVERSION_STR "4.5.6001.22308" +#define WINE_PRODUCTVERSION 4,5,6001,22308 +#define WINE_PRODUCTVERSION_STR "4.5.6001.22308" #include diff --git a/reactos/dll/win32/msi/msi.spec b/reactos/dll/win32/msi/msi.spec index 4e64f40283d..0ea9a273094 100644 --- a/reactos/dll/win32/msi/msi.spec +++ b/reactos/dll/win32/msi/msi.spec @@ -97,10 +97,10 @@ 101 stub MsiProcessAdvertiseScriptA 102 stub MsiProcessAdvertiseScriptW 103 stdcall MsiProcessMessage(long long long) -104 stub MsiProvideComponentA +104 stdcall MsiProvideComponentA(str str str long ptr ptr) 105 stdcall MsiProvideComponentFromDescriptorA(str ptr ptr ptr) 106 stdcall MsiProvideComponentFromDescriptorW(wstr ptr ptr ptr) -107 stub MsiProvideComponentW +107 stdcall MsiProvideComponentW(wstr wstr wstr long ptr ptr) 108 stdcall MsiProvideQualifiedComponentA(str str long ptr ptr) 109 stdcall MsiProvideQualifiedComponentW(wstr wstr long ptr ptr) 110 stdcall MsiQueryFeatureStateA(str str) @@ -230,8 +230,8 @@ 234 stub MsiDeleteUserDataW 235 stub Migrate10CachedPackagesA 236 stdcall Migrate10CachedPackagesW(ptr ptr ptr long) -237 stub MsiRemovePatchesA -238 stub MsiRemovePatchesW +237 stdcall MsiRemovePatchesA(str str long str) +238 stdcall MsiRemovePatchesW(wstr wstr long wstr) 239 stdcall MsiApplyMultiplePatchesA(str str str) 240 stdcall MsiApplyMultiplePatchesW(wstr wstr wstr) 241 stub MsiExtractPatchXMLDataA @@ -281,9 +281,16 @@ 285 stdcall MsiBeginTransactionW(wstr long ptr ptr) 286 stdcall MsiEndTransaction(long) 287 stub MsiJoinTransaction -288 stub QueryInstanceCount +288 stub MsiSetOfflineContextW +289 stdcall MsiEnumComponentsExA(str long long ptr ptr ptr ptr) +290 stdcall MsiEnumComponentsExW(wstr long long ptr ptr ptr ptr) +291 stdcall MsiEnumClientsExA(str str long long ptr ptr ptr ptr) +292 stdcall MsiEnumClientsExW(wstr wstr long long ptr ptr ptr ptr) +293 stub MsiGetComponentPathExA +294 stub MsiGetComponentPathExW +295 stub QueryInstanceCount + @ stdcall -private DllCanUnloadNow() @ stdcall -private DllGetClassObject(ptr ptr ptr) @ stdcall -private DllRegisterServer() @ stdcall -private DllUnregisterServer() - diff --git a/reactos/dll/win32/msi/msipriv.h b/reactos/dll/win32/msi/msipriv.h index ec772b8b43e..a3f9df4c2ae 100644 --- a/reactos/dll/win32/msi/msipriv.h +++ b/reactos/dll/win32/msi/msipriv.h @@ -94,6 +94,18 @@ struct tagMSIOBJECTHDR #define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET 10000 #define MSI_INITIAL_MEDIA_TRANSFORM_DISKID 30000 +typedef struct tagMSISTREAM +{ + UINT str_index; + IStream *stream; +} MSISTREAM; + +typedef struct tagMSITRANSFORM +{ + struct list entry; + IStorage *stg; +} MSITRANSFORM; + typedef struct tagMSIDATABASE { MSIOBJECTHDR hdr; @@ -107,7 +119,9 @@ typedef struct tagMSIDATABASE UINT media_transform_disk_id; struct list tables; struct list transforms; - struct list streams; + MSISTREAM *streams; + UINT num_streams; + UINT num_streams_allocated; } MSIDATABASE; typedef struct tagMSIVIEW MSIVIEW; @@ -168,7 +182,6 @@ typedef struct tagMSIMEDIAINFO UINT last_sequence; LPWSTR disk_prompt; LPWSTR cabinet; - LPWSTR first_volume; LPWSTR volume_label; BOOL is_continuous; BOOL is_extracted; @@ -757,6 +770,7 @@ extern void msi_free_handle_table(void) DECLSPEC_HIDDEN; extern void free_cached_tables( MSIDATABASE *db ) DECLSPEC_HIDDEN; extern UINT MSI_CommitTables( MSIDATABASE *db ) DECLSPEC_HIDDEN; +extern UINT msi_commit_streams( MSIDATABASE *db ) DECLSPEC_HIDDEN; /* string table functions */ @@ -766,7 +780,7 @@ enum StringPersistence StringNonPersistent = 1 }; -extern BOOL msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcount, enum StringPersistence persistence ) DECLSPEC_HIDDEN; +extern BOOL msi_add_string( string_table *st, const WCHAR *data, int len, enum StringPersistence persistence ) DECLSPEC_HIDDEN; extern UINT msi_string2id( const string_table *st, const WCHAR *data, int len, UINT *id ) DECLSPEC_HIDDEN; extern VOID msi_destroy_stringtable( string_table *st ) DECLSPEC_HIDDEN; extern const WCHAR *msi_string_lookup( const string_table *st, UINT id, int *len ) DECLSPEC_HIDDEN; @@ -844,9 +858,7 @@ extern LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) DECLSPEC_HIDDEN; extern BOOL decode_streamname(LPCWSTR in, LPWSTR out) DECLSPEC_HIDDEN; /* database internals */ -extern UINT msi_get_raw_stream( MSIDATABASE *, LPCWSTR, IStream ** ) DECLSPEC_HIDDEN; -extern UINT msi_clone_open_stream( MSIDATABASE *, IStorage *, const WCHAR *, IStream ** ) DECLSPEC_HIDDEN; -void msi_destroy_stream( MSIDATABASE *, const WCHAR * ) DECLSPEC_HIDDEN; +extern UINT msi_get_stream( MSIDATABASE *, const WCHAR *, IStream ** ) DECLSPEC_HIDDEN; extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ) DECLSPEC_HIDDEN; extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ) DECLSPEC_HIDDEN; extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... ) DECLSPEC_HIDDEN; @@ -879,7 +891,7 @@ extern UINT MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE ) DECLSPEC_H extern UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename ) DECLSPEC_HIDDEN; extern UINT msi_package_add_info(MSIPACKAGE *, DWORD, DWORD, LPCWSTR, LPWSTR) DECLSPEC_HIDDEN; extern UINT msi_package_add_media_disk(MSIPACKAGE *, DWORD, DWORD, DWORD, LPWSTR, LPWSTR) DECLSPEC_HIDDEN; -extern UINT msi_clone_properties(MSIPACKAGE *) DECLSPEC_HIDDEN; +extern UINT msi_clone_properties(MSIDATABASE *) DECLSPEC_HIDDEN; extern UINT msi_set_context(MSIPACKAGE *) DECLSPEC_HIDDEN; extern void msi_adjust_privilege_properties(MSIPACKAGE *) DECLSPEC_HIDDEN; extern UINT MSI_GetFeatureCost(MSIPACKAGE *, MSIFEATURE *, MSICOSTTREE, INSTALLSTATE, LPINT) DECLSPEC_HIDDEN; @@ -955,6 +967,7 @@ extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) DECL extern INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) DECLSPEC_HIDDEN; extern LPWSTR msi_get_suminfo_product( IStorage *stg ) DECLSPEC_HIDDEN; extern UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ) DECLSPEC_HIDDEN; +extern enum platform parse_platform( const WCHAR *str ) DECLSPEC_HIDDEN; /* undocumented functions */ UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD ); @@ -1173,7 +1186,6 @@ static const WCHAR szX64[] = {'x','6','4',0}; static const WCHAR szAMD64[] = {'A','M','D','6','4',0}; static const WCHAR szARM[] = {'A','r','m',0}; static const WCHAR szWow6432NodeCLSID[] = {'W','o','w','6','4','3','2','N','o','d','e','\\','C','L','S','I','D',0}; -static const WCHAR szWow6432Node[] = {'W','o','w','6','4','3','2','N','o','d','e',0}; static const WCHAR szStreams[] = {'_','S','t','r','e','a','m','s',0}; static const WCHAR szStorages[] = {'_','S','t','o','r','a','g','e','s',0}; static const WCHAR szMsiPublishAssemblies[] = {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0}; @@ -1194,6 +1206,7 @@ static const WCHAR szName[] = {'N','a','m','e',0}; static const WCHAR szData[] = {'D','a','t','a',0}; static const WCHAR szLangResource[] = {'\\','V','a','r','F','i','l','e','I','n','f','o','\\','T','r','a','n','s','l','a','t','i','o','n',0}; static const WCHAR szInstallLocation[] = {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0}; +static const WCHAR szProperty[] = {'P','r','o','p','e','r','t','y',0}; /* memory allocation macro functions */ static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1); diff --git a/reactos/dll/win32/msi/msiquery.c b/reactos/dll/win32/msi/msiquery.c index 002a16454d4..9dc33beb909 100644 --- a/reactos/dll/win32/msi/msiquery.c +++ b/reactos/dll/win32/msi/msiquery.c @@ -821,8 +821,13 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb ) /* FIXME: lock the database */ - r = MSI_CommitTables( db ); - if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n"); + r = msi_commit_streams( db ); + if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n"); + else + { + r = MSI_CommitTables( db ); + if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n"); + } /* FIXME: unlock the database */ diff --git a/reactos/dll/win32/msi/package.c b/reactos/dll/win32/msi/package.c index 09f8c5c4f62..69698b73b56 100644 --- a/reactos/dll/win32/msi/package.c +++ b/reactos/dll/win32/msi/package.c @@ -361,7 +361,7 @@ static UINT create_temp_property_table(MSIPACKAGE *package) return rc; } -UINT msi_clone_properties(MSIPACKAGE *package) +UINT msi_clone_properties( MSIDATABASE *db ) { static const WCHAR query_select[] = { 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', @@ -378,7 +378,7 @@ UINT msi_clone_properties(MSIPACKAGE *package) MSIQUERY *view_select; UINT rc; - rc = MSI_DatabaseOpenViewW( package->db, query_select, &view_select ); + rc = MSI_DatabaseOpenViewW( db, query_select, &view_select ); if (rc != ERROR_SUCCESS) return rc; @@ -399,7 +399,7 @@ UINT msi_clone_properties(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) break; - rc = MSI_DatabaseOpenViewW( package->db, query_insert, &view_insert ); + rc = MSI_DatabaseOpenViewW( db, query_insert, &view_insert ); if (rc != ERROR_SUCCESS) { msiobj_release( &rec_select->hdr ); @@ -415,7 +415,7 @@ UINT msi_clone_properties(MSIPACKAGE *package) TRACE("insert failed, trying update\n"); - rc = MSI_DatabaseOpenViewW( package->db, query_update, &view_update ); + rc = MSI_DatabaseOpenViewW( db, query_update, &view_update ); if (rc != ERROR_SUCCESS) { WARN("open view failed %u\n", rc); @@ -1150,7 +1150,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url ) package->BaseURL = strdupW( base_url ); create_temp_property_table( package ); - msi_clone_properties( package ); + msi_clone_properties( package->db ); msi_adjust_privilege_properties( package ); package->ProductCode = msi_dup_property( package->db, szProductCode ); @@ -1246,7 +1246,7 @@ UINT msi_create_empty_local_file( LPWSTR path, LPCWSTR suffix ) return ERROR_SUCCESS; } -static enum platform parse_platform( WCHAR *str ) +enum platform parse_platform( const WCHAR *str ) { if (!str[0] || !strcmpW( str, szIntel )) return PLATFORM_INTEL; else if (!strcmpW( str, szIntel64 )) return PLATFORM_INTEL64; @@ -1652,11 +1652,8 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) } index++; } - if (index) - { - msi_clone_properties( package ); - msi_adjust_privilege_properties( package ); - } + if (index) msi_adjust_privilege_properties( package ); + r = msi_set_original_database_property( package->db, szPackage ); if (r != ERROR_SUCCESS) { diff --git a/reactos/dll/win32/msi/patch.c b/reactos/dll/win32/msi/patch.c index 81b9e3499e4..6025c9780a4 100644 --- a/reactos/dll/win32/msi/patch.c +++ b/reactos/dll/win32/msi/patch.c @@ -35,57 +35,220 @@ static BOOL match_language( MSIPACKAGE *package, LANGID langid ) return FALSE; } +struct transform_desc +{ + WCHAR *product_code_from; + WCHAR *product_code_to; + WCHAR *version_from; + WCHAR *version_to; + WCHAR *upgrade_code; +}; + +static void free_transform_desc( struct transform_desc *desc ) +{ + msi_free( desc->product_code_from ); + msi_free( desc->product_code_to ); + msi_free( desc->version_from ); + msi_free( desc->version_to ); + msi_free( desc->upgrade_code ); + msi_free( desc ); +} + +static struct transform_desc *parse_transform_desc( const WCHAR *str ) +{ + struct transform_desc *ret; + const WCHAR *p = str, *q; + UINT len; + + if (!(ret = msi_alloc_zero( sizeof(*ret) ))) return NULL; + + q = strchrW( p, '}' ); + if (*p != '{' || !q) goto error; + + len = q - p + 1; + if (!(ret->product_code_from = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error; + memcpy( ret->product_code_from, p, len * sizeof(WCHAR) ); + ret->product_code_from[len] = 0; + + p = q + 1; + if (!(q = strchrW( p, ';' ))) goto error; + len = q - p; + if (!(ret->version_from = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error; + memcpy( ret->version_from, p, len * sizeof(WCHAR) ); + ret->version_from[len] = 0; + + p = q + 1; + q = strchrW( p, '}' ); + if (*p != '{' || !q) goto error; + + len = q - p + 1; + if (!(ret->product_code_to = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error; + memcpy( ret->product_code_to, p, len * sizeof(WCHAR) ); + ret->product_code_to[len] = 0; + + p = q + 1; + if (!(q = strchrW( p, ';' ))) goto error; + len = q - p; + if (!(ret->version_to = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error; + memcpy( ret->version_to, p, len * sizeof(WCHAR) ); + ret->version_to[len] = 0; + + p = q + 1; + q = strchrW( p, '}' ); + if (*p != '{' || !q) goto error; + + len = q - p + 1; + if (!(ret->upgrade_code = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error; + memcpy( ret->upgrade_code, p, len * sizeof(WCHAR) ); + ret->upgrade_code[len] = 0; + + return ret; + +error: + free_transform_desc( ret ); + return NULL; +} + static UINT check_transform_applicable( MSIPACKAGE *package, IStorage *transform ) { + static const UINT supported_flags = + 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; + WCHAR *template, *product, *p; + struct transform_desc *desc; - if (si) wanted_flags = msi_suminfo_get_int32( si, PID_CHARCOUNT ); - TRACE("validation flags %x\n", wanted_flags); - - if (wanted_flags & ~(MSITRANSFORM_VALIDATE_PRODUCT|MSITRANSFORM_VALIDATE_LANGUAGE)) - FIXME("unsupported validation flags %x\n", wanted_flags); - - if (wanted_flags & MSITRANSFORM_VALIDATE_PRODUCT) + if (!si) { - WCHAR *package_product = msi_dup_property( package->db, szProductCode ); - WCHAR *transform_product = msi_get_suminfo_product( transform ); - - TRACE("package = %s transform = %s\n", debugstr_w(package_product), debugstr_w(transform_product)); - - if (!transform_product || strstrW( transform_product, package_product )) - { - valid_flags |= MSITRANSFORM_VALIDATE_PRODUCT; - } - msi_free( transform_product ); - msi_free( package_product ); + WARN("no summary information!\n"); + return ERROR_FUNCTION_FAILED; } + wanted_flags = msi_suminfo_get_int32( si, PID_CHARCOUNT ); + wanted_flags &= 0xffff; /* mask off error condition flags */ + TRACE("validation flags 0x%04x\n", wanted_flags); + + if (wanted_flags & ~supported_flags) + { + FIXME("unsupported validation flags 0x%04x\n", wanted_flags); + msiobj_release( &si->hdr ); + return ERROR_FUNCTION_FAILED; + } + if (!(template = msi_suminfo_dup_string( si, PID_TEMPLATE ))) + { + WARN("no template property!\n"); + msiobj_release( &si->hdr ); + return ERROR_FUNCTION_FAILED; + } + TRACE("template property: %s\n", debugstr_w(template)); + if (!(product = msi_get_suminfo_product( transform ))) + { + WARN("no product property!\n"); + msi_free( template ); + msiobj_release( &si->hdr ); + return ERROR_FUNCTION_FAILED; + } + TRACE("product property: %s\n", debugstr_w(product)); + if (!(desc = parse_transform_desc( product ))) + { + msi_free( template ); + msiobj_release( &si->hdr ); + return ERROR_FUNCTION_FAILED; + } + msi_free( product ); + if (wanted_flags & MSITRANSFORM_VALIDATE_LANGUAGE) { - WCHAR *template; - const WCHAR *p; - - if (!si) - { - ERR("no summary information!\n"); - goto end; - } - if (!(template = msi_suminfo_dup_string( si, PID_TEMPLATE ))) - { - ERR("no template property!\n"); - goto end; - } - TRACE("template: %s\n", debugstr_w(template)); if (!template[0] || ((p = strchrW( template, ';' )) && match_language( package, atoiW( p + 1 ) ))) { valid_flags |= MSITRANSFORM_VALIDATE_LANGUAGE; } - msi_free( template ); + } + if (wanted_flags & MSITRANSFORM_VALIDATE_PRODUCT) + { + WCHAR *product_code_installed = msi_dup_property( package->db, szProductCode ); + + if (!product_code_installed) + { + msi_free( template ); + free_transform_desc( desc ); + msiobj_release( &si->hdr ); + return ERROR_INSTALL_PACKAGE_INVALID; + } + if (!strcmpW( desc->product_code_from, product_code_installed )) + { + valid_flags |= MSITRANSFORM_VALIDATE_PRODUCT; + } + msi_free( product_code_installed ); + } + if (wanted_flags & MSITRANSFORM_VALIDATE_PLATFORM) + { + if ((p = strchrW( template, ';' ))) + { + *p = 0; + if (package->platform == parse_platform( template )) + valid_flags |= MSITRANSFORM_VALIDATE_PLATFORM; + } + } + msi_free( template ); + if (wanted_flags & MSITRANSFORM_VALIDATE_MAJORVERSION) + { + WCHAR *product_version_installed = msi_dup_property( package->db, szProductVersion ); + DWORD major_installed, minor_installed, major, minor; + + if (!product_version_installed) + { + free_transform_desc( desc ); + msiobj_release( &si->hdr ); + return ERROR_INSTALL_PACKAGE_INVALID; + } + msi_parse_version_string( product_version_installed, &major_installed, &minor_installed ); + msi_parse_version_string( desc->version_from, &major, &minor ); + + if (major_installed == major) + { + valid_flags |= MSITRANSFORM_VALIDATE_MAJORVERSION; + wanted_flags &= ~MSITRANSFORM_VALIDATE_MINORVERSION; + } + msi_free( product_version_installed ); + } + else if (wanted_flags & MSITRANSFORM_VALIDATE_MINORVERSION) + { + WCHAR *product_version_installed = msi_dup_property( package->db, szProductVersion ); + DWORD major_installed, minor_installed, major, minor; + + if (!product_version_installed) + { + free_transform_desc( desc ); + msiobj_release( &si->hdr ); + return ERROR_INSTALL_PACKAGE_INVALID; + } + msi_parse_version_string( product_version_installed, &major_installed, &minor_installed ); + msi_parse_version_string( desc->version_from, &major, &minor ); + + if (major_installed == major && minor_installed == minor) + valid_flags |= MSITRANSFORM_VALIDATE_MINORVERSION; + msi_free( product_version_installed ); + } + if (wanted_flags & MSITRANSFORM_VALIDATE_UPGRADECODE) + { + WCHAR *upgrade_code_installed = msi_dup_property( package->db, szUpgradeCode ); + + if (!upgrade_code_installed) + { + free_transform_desc( desc ); + msiobj_release( &si->hdr ); + return ERROR_INSTALL_PACKAGE_INVALID; + } + if (!strcmpW( desc->upgrade_code, upgrade_code_installed )) + valid_flags |= MSITRANSFORM_VALIDATE_UPGRADECODE; + msi_free( upgrade_code_installed ); } -end: + free_transform_desc( desc ); msiobj_release( &si->hdr ); - if (valid_flags & ~wanted_flags) return ERROR_FUNCTION_FAILED; + if ((valid_flags & wanted_flags) != wanted_flags) return ERROR_FUNCTION_FAILED; TRACE("applicable transform\n"); return ERROR_SUCCESS; } diff --git a/reactos/dll/win32/msi/registry.c b/reactos/dll/win32/msi/registry.c index 2429fa1ee7b..31995a8f78f 100644 --- a/reactos/dll/win32/msi/registry.c +++ b/reactos/dll/win32/msi/registry.c @@ -83,12 +83,6 @@ static const WCHAR szInstallProperties_fmt[] = { '%','s','\\','P','r','o','d','u','c','t','s','\\','%','s','\\', 'I','n','s','t','a','l','l','P','r','o','p','e','r','t','i','e','s',0}; -static const WCHAR szInstaller_LocalManaged_fmt[] = { - 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'I','n','s','t','a','l','l','e','r','\\','M','a','n','a','g','e','d','\\','%','s','\\', - 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0}; - static const WCHAR szInstaller_LocalManagedProd_fmt[] = { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', @@ -111,11 +105,6 @@ static const WCHAR szInstaller_Patches[] = { 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 'I','n','s','t','a','l','l','e','r','\\','P','a','t','c','h','e','s',0}; -static const WCHAR szInstaller_Components[] = { - 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'I','n','s','t','a','l','l','e','r','\\','C','o','m','p','o','n','e','n','t','s',0}; - static const WCHAR szInstaller_LocalClassesProducts[] = { 'S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s','\\', 'I','n','s','t','a','l','l','e','r','\\','P','r','o','d','u','c','t','s',0}; @@ -1497,6 +1486,24 @@ UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) return r; } +UINT WINAPI MsiEnumClientsExA(LPCSTR component, LPCSTR usersid, DWORD ctx, DWORD index, + CHAR installed_product[GUID_SIZE], + MSIINSTALLCONTEXT *installed_ctx, LPSTR sid, LPDWORD sid_len) +{ + FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_a(component), debugstr_a(usersid), + ctx, index, installed_product, installed_ctx, sid, sid_len); + return ERROR_ACCESS_DENIED; +} + +UINT WINAPI MsiEnumClientsExW(LPCWSTR component, LPCWSTR usersid, DWORD ctx, DWORD index, + WCHAR installed_product[GUID_SIZE], + MSIINSTALLCONTEXT *installed_ctx, LPWSTR sid, LPDWORD sid_len) +{ + FIXME("%s, %s, %u, %u, %p, %p, %p, %p\n", debugstr_w(component), debugstr_w(usersid), + ctx, index, installed_product, installed_ctx, sid, sid_len); + return ERROR_ACCESS_DENIED; +} + static UINT MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex, awstring *lpQualBuf, LPDWORD pcchQual, awstring *lpAppBuf, LPDWORD pcchAppBuf ) diff --git a/reactos/dll/win32/msi/script.c b/reactos/dll/win32/msi/script.c index f700da7ef23..1165ec41ff9 100644 --- a/reactos/dll/win32/msi/script.c +++ b/reactos/dll/win32/msi/script.c @@ -344,7 +344,7 @@ DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function if (FAILED(hr)) goto done; /* Call a function if necessary through the IDispatch interface */ - if (function != NULL && strlenW(function) > 0) { + if (function && function[0]) { TRACE("Calling function %s\n", debugstr_w(function)); hr = IActiveScript_GetScriptDispatch(pActiveScript, NULL, &pDispatch); diff --git a/reactos/dll/win32/msi/storages.c b/reactos/dll/win32/msi/storages.c index ef57633f871..a88dc95390a 100644 --- a/reactos/dll/win32/msi/storages.c +++ b/reactos/dll/win32/msi/storages.c @@ -62,7 +62,7 @@ static STORAGE *create_storage(MSISTORAGESVIEW *sv, LPCWSTR name, IStorage *stg) if (!storage) return NULL; - storage->str_index = msi_addstringW(sv->db->strings, name, -1, 1, StringNonPersistent); + storage->str_index = msi_add_string(sv->db->strings, name, -1, StringNonPersistent); storage->storage = stg; if (storage->storage) diff --git a/reactos/dll/win32/msi/streams.c b/reactos/dll/win32/msi/streams.c index 8b46565bab3..bca1c0125a0 100644 --- a/reactos/dll/win32/msi/streams.c +++ b/reactos/dll/win32/msi/streams.c @@ -2,6 +2,7 @@ * Implementation of the Microsoft Installer (msi.dll) * * Copyright 2007 James Hawkins + * Copyright 2015 Hans Leidekker for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,56 +25,32 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb); #define NUM_STREAMS_COLS 2 -typedef struct tabSTREAM -{ - UINT str_index; - IStream *stream; -} STREAM; - typedef struct tagMSISTREAMSVIEW { MSIVIEW view; MSIDATABASE *db; - STREAM **streams; - UINT max_streams; - UINT num_rows; - UINT row_size; + UINT num_cols; } MSISTREAMSVIEW; -static BOOL streams_set_table_size(MSISTREAMSVIEW *sv, UINT size) +static BOOL streams_resize_table( MSIDATABASE *db, UINT size ) { - if (size >= sv->max_streams) + if (!db->num_streams_allocated) { - sv->max_streams *= 2; - sv->streams = msi_realloc_zero(sv->streams, sv->max_streams * sizeof(STREAM *)); - if (!sv->streams) - return FALSE; + if (!(db->streams = msi_alloc_zero( size * sizeof(MSISTREAM) ))) return FALSE; + db->num_streams_allocated = size; + return TRUE; + } + while (size >= db->num_streams_allocated) + { + MSISTREAM *tmp; + UINT new_size = db->num_streams_allocated * 2; + if (!(tmp = msi_realloc_zero( db->streams, new_size * sizeof(MSISTREAM) ))) return FALSE; + db->streams = tmp; + db->num_streams_allocated = new_size; } - return TRUE; } -static STREAM *create_stream(MSISTREAMSVIEW *sv, LPCWSTR name, BOOL encoded, IStream *stm) -{ - STREAM *stream; - WCHAR decoded[MAX_STREAM_NAME_LEN + 1]; - - stream = msi_alloc(sizeof(STREAM)); - if (!stream) - return NULL; - - if (encoded) - { - decode_streamname(name, decoded); - TRACE("stream -> %s %s\n", debugstr_w(name), debugstr_w(decoded)); - name = decoded; - } - - stream->str_index = msi_addstringW(sv->db->strings, name, -1, 1, StringNonPersistent); - stream->stream = stm; - return stream; -} - static UINT STREAMS_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT *val) { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; @@ -83,10 +60,10 @@ static UINT STREAMS_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT if (col != 1) return ERROR_INVALID_PARAMETER; - if (row >= sv->num_rows) + if (row >= sv->db->num_streams) return ERROR_NO_MORE_ITEMS; - *val = sv->streams[row]->str_index; + *val = sv->db->streams[row].str_index; return ERROR_SUCCESS; } @@ -94,14 +71,21 @@ static UINT STREAMS_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT static UINT STREAMS_fetch_stream(struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm) { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; + LARGE_INTEGER pos; + HRESULT hr; TRACE("(%p, %d, %d, %p)\n", view, row, col, stm); - if (row >= sv->num_rows) + if (row >= sv->db->num_streams) return ERROR_FUNCTION_FAILED; - IStream_AddRef(sv->streams[row]->stream); - *stm = sv->streams[row]->stream; + pos.QuadPart = 0; + hr = IStream_Seek( sv->db->streams[row].stream, pos, STREAM_SEEK_SET, NULL ); + if (FAILED( hr )) + return ERROR_FUNCTION_FAILED; + + *stm = sv->db->streams[row].stream; + IStream_AddRef( *stm ); return ERROR_SUCCESS; } @@ -118,110 +102,94 @@ static UINT STREAMS_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask) { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; - STREAM *stream; - IStream *stm; - STATSTG stat; - LPWSTR encname = NULL, name = NULL; - USHORT *data = NULL; - HRESULT hr; - ULONG count; - UINT r = ERROR_FUNCTION_FAILED; TRACE("(%p, %d, %p, %08x)\n", view, row, rec, mask); - if (row > sv->num_rows) - return ERROR_FUNCTION_FAILED; + if (row > sv->db->num_streams || mask >= (1 << sv->num_cols)) + return ERROR_INVALID_PARAMETER; - r = MSI_RecordGetIStream(rec, 2, &stm); + if (mask & 1) + { + const WCHAR *name = MSI_RecordGetString( rec, 1 ); + + if (!name) return ERROR_INVALID_PARAMETER; + sv->db->streams[row].str_index = msi_add_string( sv->db->strings, name, -1, StringNonPersistent ); + } + if (mask & 2) + { + IStream *old, *new; + HRESULT hr; + UINT r; + + r = MSI_RecordGetIStream( rec, 2, &new ); + if (r != ERROR_SUCCESS) + return r; + + old = sv->db->streams[row].stream; + hr = IStream_QueryInterface( new, &IID_IStream, (void **)&sv->db->streams[row].stream ); + if (FAILED( hr )) + { + IStream_Release( new ); + return ERROR_FUNCTION_FAILED; + } + if (old) IStream_Release( old ); + } + + return ERROR_SUCCESS; +} + +static UINT streams_find_row( MSISTREAMSVIEW *sv, MSIRECORD *rec, UINT *row ) +{ + const WCHAR *str; + UINT r, i, id, val; + + str = MSI_RecordGetString( rec, 1 ); + r = msi_string2id( sv->db->strings, str, -1, &id ); if (r != ERROR_SUCCESS) return r; - hr = IStream_Stat(stm, &stat, STATFLAG_NONAME); - if (FAILED(hr)) + for (i = 0; i < sv->db->num_streams; i++) { - WARN("failed to stat stream: %08x\n", hr); - goto done; + STREAMS_fetch_int( &sv->view, i, 1, &val ); + + if (val == id) + { + if (row) *row = i; + return ERROR_SUCCESS; + } } - if (stat.cbSize.QuadPart >> 32) - { - WARN("stream too large\n"); - goto done; - } - - data = msi_alloc(stat.cbSize.QuadPart); - if (!data) - goto done; - - hr = IStream_Read(stm, data, stat.cbSize.QuadPart, &count); - if (FAILED(hr) || count != stat.cbSize.QuadPart) - { - WARN("failed to read stream: %08x\n", hr); - goto done; - } - - name = strdupW(MSI_RecordGetString(rec, 1)); - if (!name) - { - WARN("failed to retrieve stream name\n"); - goto done; - } - - encname = encode_streamname(FALSE, name); - msi_destroy_stream(sv->db, encname); - - r = write_stream_data(sv->db->storage, name, data, count, FALSE); - if (r != ERROR_SUCCESS) - { - WARN("failed to write stream data: %d\n", r); - goto done; - } - - stream = create_stream(sv, name, FALSE, NULL); - if (!stream) - goto done; - - hr = IStorage_OpenStream(sv->db->storage, encname, 0, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream->stream); - if (FAILED(hr)) - { - WARN("failed to open stream: %08x\n", hr); - msi_free(stream); - goto done; - } - - sv->streams[row] = stream; - -done: - msi_free(name); - msi_free(data); - msi_free(encname); - - IStream_Release(stm); - - return r; + return ERROR_FUNCTION_FAILED; } static UINT STREAMS_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary) { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; - UINT i; + UINT i, r, num_rows = sv->db->num_streams + 1; TRACE("(%p, %p, %d, %d)\n", view, rec, row, temporary); - if (!streams_set_table_size(sv, ++sv->num_rows)) + r = streams_find_row( sv, rec, NULL ); + if (r == ERROR_SUCCESS) + return ERROR_FUNCTION_FAILED; + + if (!streams_resize_table( sv->db, num_rows )) return ERROR_FUNCTION_FAILED; if (row == -1) - row = sv->num_rows - 1; + row = num_rows - 1; /* shift the rows to make room for the new row */ - for (i = sv->num_rows - 1; i > row; i--) + for (i = num_rows - 1; i > row; i--) { - sv->streams[i] = sv->streams[i - 1]; + sv->db->streams[i] = sv->db->streams[i - 1]; } - return STREAMS_set_row(view, row, rec, 0); + r = STREAMS_set_row( view, row, rec, (1 << sv->num_cols) - 1 ); + if (r == ERROR_SUCCESS) + sv->db->num_streams = num_rows; + + return r; } static UINT STREAMS_delete_row(struct tagMSIVIEW *view, UINT row) @@ -248,8 +216,8 @@ static UINT STREAMS_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *co TRACE("(%p, %p, %p)\n", view, rows, cols); - if (cols) *cols = NUM_STREAMS_COLS; - if (rows) *rows = sv->num_rows; + if (cols) *cols = sv->num_cols; + if (rows) *rows = sv->db->num_streams; return ERROR_SUCCESS; } @@ -257,10 +225,11 @@ static UINT STREAMS_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *co static UINT STREAMS_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name, UINT *type, BOOL *temporary, LPCWSTR *table_name ) { - TRACE("(%p, %d, %p, %p, %p, %p)\n", view, n, name, type, temporary, - table_name); + MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; - if (n == 0 || n > NUM_STREAMS_COLS) + TRACE("(%p, %d, %p, %p, %p, %p)\n", view, n, name, type, temporary, table_name); + + if (!n || n > sv->num_cols) return ERROR_INVALID_PARAMETER; switch (n) @@ -280,30 +249,6 @@ static UINT STREAMS_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *n return ERROR_SUCCESS; } -static UINT streams_find_row(MSISTREAMSVIEW *sv, MSIRECORD *rec, UINT *row) -{ - LPCWSTR str; - UINT r, i, id, data; - - str = MSI_RecordGetString(rec, 1); - r = msi_string2id(sv->db->strings, str, -1, &id); - if (r != ERROR_SUCCESS) - return r; - - for (i = 0; i < sv->num_rows; i++) - { - STREAMS_fetch_int(&sv->view, i, 1, &data); - - if (data == id) - { - *row = i; - return ERROR_SUCCESS; - } - } - - return ERROR_FUNCTION_FAILED; -} - static UINT streams_modify_update(struct tagMSIVIEW *view, MSIRECORD *rec) { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; @@ -313,15 +258,15 @@ static UINT streams_modify_update(struct tagMSIVIEW *view, MSIRECORD *rec) if (r != ERROR_SUCCESS) return ERROR_FUNCTION_FAILED; - return STREAMS_set_row(view, row, rec, 0); + return STREAMS_set_row( view, row, rec, (1 << sv->num_cols) - 1 ); } static UINT streams_modify_assign(struct tagMSIVIEW *view, MSIRECORD *rec) { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; - UINT r, row; + UINT r; - r = streams_find_row(sv, rec, &row); + r = streams_find_row( sv, rec, NULL ); if (r == ERROR_SUCCESS) return streams_modify_update(view, rec); @@ -371,23 +316,10 @@ static UINT STREAMS_modify(struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRE static UINT STREAMS_delete(struct tagMSIVIEW *view) { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; - UINT i; TRACE("(%p)\n", view); - for (i = 0; i < sv->num_rows; i++) - { - if (sv->streams[i]) - { - if (sv->streams[i]->stream) - IStream_Release(sv->streams[i]->stream); - msi_free(sv->streams[i]); - } - } - - msi_free(sv->streams); msi_free(sv); - return ERROR_SUCCESS; } @@ -399,23 +331,22 @@ static UINT STREAMS_find_matching_rows(struct tagMSIVIEW *view, UINT col, TRACE("(%p, %d, %d, %p, %p)\n", view, col, val, row, handle); - if (col == 0 || col > NUM_STREAMS_COLS) + if (!col || col > sv->num_cols) return ERROR_INVALID_PARAMETER; - while (index < sv->num_rows) + while (index < sv->db->num_streams) { - if (sv->streams[index]->str_index == val) + if (sv->db->streams[index].str_index == val) { *row = index; break; } - index++; } *handle = UlongToPtr(++index); - if (index > sv->num_rows) + if (index > sv->db->num_streams) return ERROR_NO_MORE_ITEMS; return ERROR_SUCCESS; @@ -444,107 +375,256 @@ static const MSIVIEWOPS streams_ops = NULL, }; -static INT add_streams_to_table(MSISTREAMSVIEW *sv) +static HRESULT open_stream( MSIDATABASE *db, const WCHAR *name, IStream **stream ) { - IEnumSTATSTG *stgenum = NULL; - STATSTG stat; - STREAM *stream = NULL; HRESULT hr; - UINT r, count = 0, size; - LPWSTR encname; - hr = IStorage_EnumElements(sv->db->storage, 0, NULL, 0, &stgenum); - if (FAILED(hr)) - return -1; - - sv->max_streams = 1; - sv->streams = msi_alloc_zero(sizeof(STREAM *)); - if (!sv->streams) - return -1; - - while (TRUE) + hr = IStorage_OpenStream( db->storage, name, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, stream ); + if (FAILED( hr )) { - size = 0; - hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &size); - if (FAILED(hr) || !size) - break; + MSITRANSFORM *transform; - if (stat.type != STGTY_STREAM) + LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry ) { - CoTaskMemFree(stat.pwcsName); - continue; + hr = IStorage_OpenStream( transform->stg, name, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, stream ); + if (SUCCEEDED( hr )) + break; } + } + return hr; +} + +static MSISTREAM *find_stream( MSIDATABASE *db, const WCHAR *name ) +{ + UINT r, id, i; + + r = msi_string2id( db->strings, name, -1, &id ); + if (r != ERROR_SUCCESS) + return NULL; + + for (i = 0; i < db->num_streams; i++) + { + if (db->streams[i].str_index == id) return &db->streams[i]; + } + return NULL; +} + +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].stream = stream; + db->num_streams++; + + TRACE("added %s\n", debugstr_w( decoded )); + return ERROR_SUCCESS; +} + +static UINT load_streams( MSIDATABASE *db ) +{ + IEnumSTATSTG *stgenum; + STATSTG stat; + HRESULT hr; + UINT count, r = ERROR_SUCCESS; + IStream *stream; + + hr = IStorage_EnumElements( db->storage, 0, NULL, 0, &stgenum ); + if (FAILED( hr )) + return ERROR_FUNCTION_FAILED; + + for (;;) + { + count = 0; + hr = IEnumSTATSTG_Next( stgenum, 1, &stat, &count ); + if (FAILED( hr ) || !count) + break; /* table streams are not in the _Streams table */ - if (*stat.pwcsName == 0x4840) + if (stat.type != STGTY_STREAM || *stat.pwcsName == 0x4840 || + find_stream( db, stat.pwcsName )) { - CoTaskMemFree(stat.pwcsName); + CoTaskMemFree( stat.pwcsName ); continue; } + TRACE("found new stream %s\n", debugstr_w( stat.pwcsName )); - stream = create_stream(sv, stat.pwcsName, TRUE, NULL); - if (!stream) + hr = open_stream( db, stat.pwcsName, &stream ); + if (FAILED( hr )) { - count = -1; - CoTaskMemFree(stat.pwcsName); + ERR("unable to open stream %08x\n", hr); + CoTaskMemFree( stat.pwcsName ); + r = ERROR_FUNCTION_FAILED; break; } - /* these streams appear to be unencoded */ - if (*stat.pwcsName == 0x0005) - { - r = msi_get_raw_stream(sv->db, stat.pwcsName, &stream->stream); - } - else - { - encname = encode_streamname(FALSE, stat.pwcsName); - r = msi_get_raw_stream(sv->db, encname, &stream->stream); - msi_free(encname); - } - CoTaskMemFree(stat.pwcsName); - + r = append_stream( db, stat.pwcsName, stream ); + CoTaskMemFree( stat.pwcsName ); if (r != ERROR_SUCCESS) - { - WARN("unable to get stream %u\n", r); - count = -1; break; - } - - if (!streams_set_table_size(sv, ++count)) - { - count = -1; - break; - } - - sv->streams[count - 1] = stream; } - IEnumSTATSTG_Release(stgenum); - return count; + TRACE("loaded %u streams\n", db->num_streams); + IEnumSTATSTG_Release( stgenum ); + return r; +} + +UINT msi_get_stream( MSIDATABASE *db, const WCHAR *name, IStream **ret ) +{ + MSISTREAM *stream; + WCHAR *encname; + HRESULT hr; + UINT r; + + if ((stream = find_stream( db, name ))) + { + LARGE_INTEGER pos; + + pos.QuadPart = 0; + hr = IStream_Seek( stream->stream, pos, STREAM_SEEK_SET, NULL ); + if (FAILED( hr )) + return ERROR_FUNCTION_FAILED; + + *ret = stream->stream; + IStream_AddRef( *ret ); + return ERROR_SUCCESS; + } + + if (!(encname = encode_streamname( FALSE, name ))) + return ERROR_OUTOFMEMORY; + + hr = open_stream( db, encname, ret ); + msi_free( encname ); + if (FAILED( hr )) + return ERROR_FUNCTION_FAILED; + + r = append_stream( db, name, *ret ); + if (r != ERROR_SUCCESS) + { + IStream_Release( *ret ); + return r; + } + + IStream_AddRef( *ret ); + return ERROR_SUCCESS; } UINT STREAMS_CreateView(MSIDATABASE *db, MSIVIEW **view) { MSISTREAMSVIEW *sv; - INT rows; + UINT r; TRACE("(%p, %p)\n", db, view); - sv = msi_alloc_zero( sizeof(MSISTREAMSVIEW) ); - if (!sv) - return ERROR_FUNCTION_FAILED; + r = load_streams( db ); + if (r != ERROR_SUCCESS) + return r; + + if (!(sv = msi_alloc_zero( sizeof(MSISTREAMSVIEW) ))) + return ERROR_OUTOFMEMORY; sv->view.ops = &streams_ops; + sv->num_cols = NUM_STREAMS_COLS; sv->db = db; - rows = add_streams_to_table(sv); - if (rows < 0) - { - msi_free( sv ); - return ERROR_FUNCTION_FAILED; - } - sv->num_rows = rows; *view = (MSIVIEW *)sv; return ERROR_SUCCESS; } + +static HRESULT write_stream( IStream *dst, IStream *src ) +{ + HRESULT hr; + char buf[4096]; + STATSTG stat; + LARGE_INTEGER pos; + UINT count, size; + + hr = IStream_Stat( src, &stat, STATFLAG_NONAME ); + if (FAILED( hr )) return hr; + + hr = IStream_SetSize( dst, stat.cbSize ); + if (FAILED( hr )) return hr; + + pos.QuadPart = 0; + hr = IStream_Seek( dst, pos, STREAM_SEEK_SET, NULL ); + if (FAILED( hr )) return hr; + + for (;;) + { + size = min( sizeof(buf), stat.cbSize.QuadPart ); + hr = IStream_Read( src, buf, size, &count ); + if (FAILED( hr ) || count != size) + { + WARN("failed to read stream: %08x\n", hr); + return E_INVALIDARG; + } + stat.cbSize.QuadPart -= count; + if (count) + { + size = count; + hr = IStream_Write( dst, buf, size, &count ); + if (FAILED( hr ) || count != size) + { + WARN("failed to write stream: %08x\n", hr); + return E_INVALIDARG; + } + } + if (!stat.cbSize.QuadPart) break; + } + + return S_OK; +} + +UINT msi_commit_streams( MSIDATABASE *db ) +{ + UINT i; + const WCHAR *name; + WCHAR *encname; + IStream *stream; + HRESULT hr; + + TRACE("got %u streams\n", db->num_streams); + + for (i = 0; i < db->num_streams; i++) + { + 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 (FAILED( hr )) + { + ERR("failed to create stream %s (hr = %08x)\n", debugstr_w(encname), hr); + msi_free( encname ); + return ERROR_FUNCTION_FAILED; + } + hr = write_stream( stream, db->streams[i].stream ); + if (FAILED( hr )) + { + ERR("failed to write 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 )) + { + WARN("failed to commit stream %s (hr = %08x)\n", debugstr_w(encname), hr); + msi_free( encname ); + return ERROR_FUNCTION_FAILED; + } + msi_free( encname ); + } + + return ERROR_SUCCESS; +} diff --git a/reactos/dll/win32/msi/string.c b/reactos/dll/win32/msi/string.c index 0718866d524..7801392aa14 100644 --- a/reactos/dll/win32/msi/string.c +++ b/reactos/dll/win32/msi/string.c @@ -214,7 +214,7 @@ static void set_st_entry( string_table *st, UINT n, WCHAR *str, int len, USHORT st->freeslot = n + 1; } -static UINT msi_string2idA( const string_table *st, LPCSTR buffer, UINT *id ) +static UINT string2id( const string_table *st, const char *buffer, UINT *id ) { DWORD sz; UINT r = ERROR_INVALID_PARAMETER; @@ -241,7 +241,7 @@ static UINT msi_string2idA( const string_table *st, LPCSTR buffer, UINT *id ) return r; } -static int msi_addstring( string_table *st, UINT n, const char *data, UINT len, USHORT refcount, enum StringPersistence persistence ) +static int add_string( string_table *st, UINT n, const char *data, UINT len, USHORT refcount, enum StringPersistence persistence ) { LPWSTR str; int sz; @@ -256,7 +256,7 @@ static int msi_addstring( string_table *st, UINT n, const char *data, UINT len, } else { - if( ERROR_SUCCESS == msi_string2idA( st, data, &n ) ) + if (string2id( st, data, &n ) == ERROR_SUCCESS) { if (persistence == StringPersistent) st->strings[n].persistent_refcount += refcount; @@ -287,7 +287,7 @@ static int msi_addstring( string_table *st, UINT n, const char *data, UINT len, return n; } -int msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcount, enum StringPersistence persistence ) +int msi_add_string( string_table *st, const WCHAR *data, int len, enum StringPersistence persistence ) { UINT n; LPWSTR str; @@ -303,9 +303,9 @@ int msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcoun if (msi_string2id( st, data, len, &n) == ERROR_SUCCESS ) { if (persistence == StringPersistent) - st->strings[n].persistent_refcount += refcount; + st->strings[n].persistent_refcount++; else - st->strings[n].nonpersistent_refcount += refcount; + st->strings[n].nonpersistent_refcount++; return n; } @@ -322,7 +322,7 @@ int msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcoun memcpy( str, data, len*sizeof(WCHAR) ); str[len] = 0; - set_st_entry( st, n, str, len, refcount, persistence ); + set_st_entry( st, n, str, len, 1, persistence ); return n; } @@ -346,7 +346,7 @@ const WCHAR *msi_string_lookup( const string_table *st, UINT id, int *len ) } /* - * msi_id2stringA + * id2string * * [in] st - pointer to the string table * [in] id - id of the string to retrieve @@ -356,7 +356,7 @@ const WCHAR *msi_string_lookup( const string_table *st, UINT id, int *len ) * * Returned string is not nul terminated. */ -static UINT msi_id2stringA( const string_table *st, UINT id, LPSTR buffer, UINT *sz ) +static UINT id2string( const string_table *st, UINT id, char *buffer, UINT *sz ) { int len, lenW; const WCHAR *str; @@ -529,7 +529,7 @@ string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref ) break; } - r = msi_addstring( st, n, data+offset, len, refs, StringPersistent ); + r = add_string( st, n, data+offset, len, refs, StringPersistent ); if( r != n ) ERR("Failed to add string %d\n", n ); n++; @@ -599,7 +599,7 @@ UINT msi_save_string_table( const string_table *st, IStorage *storage, UINT *byt } sz = datasize - used; - r = msi_id2stringA( st, i, data+used, &sz ); + r = id2string( st, i, data+used, &sz ); if( r != ERROR_SUCCESS ) { ERR("failed to fetch string\n"); diff --git a/reactos/dll/win32/msi/table.c b/reactos/dll/win32/msi/table.c index 7ecb9ad4357..db536dc7880 100644 --- a/reactos/dll/win32/msi/table.c +++ b/reactos/dll/win32/msi/table.c @@ -88,7 +88,7 @@ static inline UINT bytes_per_column( MSIDATABASE *db, const MSICOLUMNINFO *col, return 2; if( (col->type & 0xff) != 4 ) - ERR("Invalid column size!\n"); + ERR("Invalid column size %u\n", col->type & 0xff); return 4; } @@ -741,8 +741,8 @@ UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info, for( i = 0, col = col_info; col; i++, col = col->next ) { - UINT table_id = msi_addstringW( db->strings, col->table, -1, 1, string_persistence ); - UINT col_id = msi_addstringW( db->strings, col->column, -1, 1, string_persistence ); + UINT table_id = msi_add_string( db->strings, col->table, -1, string_persistence ); + UINT col_id = msi_add_string( db->strings, col->column, -1, string_persistence ); table->colinfo[ i ].tablename = msi_string_lookup( db->strings, table_id, NULL ); table->colinfo[ i ].number = i + 1; @@ -932,7 +932,7 @@ static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR name ) UINT size, offset, old_count; UINT n; - table = find_cached_table( db, name ); + if (!(table = find_cached_table( db, name ))) return; old_count = table->col_count; msi_free_colinfo( table->colinfo, table->col_count ); msi_free( table->colinfo ); @@ -1130,25 +1130,23 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt { MSITABLEVIEW *tv = (MSITABLEVIEW*)view; UINT r; - LPWSTR encname, full_name = NULL; + WCHAR *name; if( !view->ops->fetch_int ) return ERROR_INVALID_PARAMETER; - r = msi_stream_name( tv, row, &full_name ); - if ( r != ERROR_SUCCESS ) + r = msi_stream_name( tv, row, &name ); + if (r != ERROR_SUCCESS) { - ERR("fetching stream, error = %d\n", r); + ERR("fetching stream, error = %u\n", r); return r; } - encname = encode_streamname( FALSE, full_name ); - r = msi_get_raw_stream( tv->db, encname, stm ); - if( r ) - ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r); + r = msi_get_stream( tv->db, name, stm ); + if (r != ERROR_SUCCESS) + ERR("fetching stream %s, error = %u\n", debugstr_w(name), r); - msi_free( full_name ); - msi_free( encname ); + msi_free( name ); return r; } @@ -1350,8 +1348,8 @@ static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UI { int len; const WCHAR *sval = msi_record_get_string( rec, i + 1, &len ); - val = msi_addstringW( tv->db->strings, sval, len, 1, - persistent ? StringPersistent : StringNonPersistent ); + val = msi_add_string( tv->db->strings, sval, len, + persistent ? StringPersistent : StringNonPersistent ); } else { @@ -2555,6 +2553,12 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, */ sz = 2; num_cols = mask >> 8; + if (num_cols > tv->num_cols) + { + ERR("excess columns in transform: %u > %u\n", num_cols, tv->num_cols); + break; + } + for (i = 0; i < num_cols; i++) { if( (tv->columns[i].type & MSITYPE_STRING) && @@ -2612,7 +2616,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, /* * Native msi seems writes nul into the Number (2nd) column of - * the _Columns table, only when the columns are from a new table + * the _Columns table when there are new columns */ if ( number == MSI_NULL_INTEGER ) { @@ -2663,7 +2667,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, WARN("failed to insert row %u\n", r); } - if (number != MSI_NULL_INTEGER && !strcmpW( name, szColumns )) + if (!strcmpW( name, szColumns )) msi_update_table_columns( db, table ); msiobj_release( &rec->hdr ); @@ -2697,6 +2701,7 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg ) string_table *strings; UINT ret = ERROR_FUNCTION_FAILED; UINT bytes_per_strref; + BOOL property_update = FALSE; TRACE("%p %p\n", db, stg ); @@ -2741,6 +2746,8 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg ) tables = transform; else if (!strcmpW( transform->name, szColumns ) ) columns = transform; + else if (!strcmpW( transform->name, szProperty )) + property_update = TRUE; TRACE("transform contains stream %s\n", debugstr_w(name)); @@ -2790,7 +2797,10 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg ) } if ( ret == ERROR_SUCCESS ) + { append_storage_to_db( db, stg ); + if (property_update) msi_clone_properties( db ); + } end: if ( stgenum ) diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 9ee8596f088..862a6130a24 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -123,7 +123,7 @@ reactos/dll/win32/msg711.acm # Synced to Wine-1.7.27 reactos/dll/win32/msgsm32.acm # Synced to Wine-1.7.27 reactos/dll/win32/mshtml # Synced to Wine-1.7.27 reactos/dll/win32/mshtml.tlb # Synced to Wine-1.7.27 -reactos/dll/win32/msi # Synced to Wine-1.7.27 +reactos/dll/win32/msi # Synced to WineStaging-1.7.37 reactos/dll/win32/msimg32 # Synced to Wine-1.7.27 reactos/dll/win32/msimtf # Synced to Wine-1.7.27 reactos/dll/win32/msisip # Synced to Wine-1.7.27