[MSI] Sync with Wine Staging 1.7.37. CORE-9246
authorAmine Khaldi <amine.khaldi@reactos.org>
Mon, 9 Mar 2015 20:28:19 +0000 (20:28 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Mon, 9 Mar 2015 20:28:19 +0000 (20:28 +0000)
svn path=/trunk/; revision=66632

19 files changed:
reactos/dll/win32/msi/action.c
reactos/dll/win32/msi/assembly.c
reactos/dll/win32/msi/database.c
reactos/dll/win32/msi/dialog.c
reactos/dll/win32/msi/media.c
reactos/dll/win32/msi/msi.c
reactos/dll/win32/msi/msi.rc
reactos/dll/win32/msi/msi.spec
reactos/dll/win32/msi/msipriv.h
reactos/dll/win32/msi/msiquery.c
reactos/dll/win32/msi/package.c
reactos/dll/win32/msi/patch.c
reactos/dll/win32/msi/registry.c
reactos/dll/win32/msi/script.c
reactos/dll/win32/msi/storages.c
reactos/dll/win32/msi/streams.c
reactos/dll/win32/msi/string.c
reactos/dll/win32/msi/table.c
reactos/media/doc/README.WINE

index dc04a7d..0816eac 100644 (file)
@@ -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 );
index d7939e8..cb8130d 100644 (file)
@@ -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 );
index 66b79f9..e170472 100644 (file)
@@ -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 )
index 9959bd1..b4c18d6 100644 (file)
@@ -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 ) )
index 3d0eb8a..0b6408d 100644 (file)
@@ -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 );
index 6bf5328..0a3e4aa 100644 (file)
@@ -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;
+}
index 5597391..7bcadb2 100644 (file)
@@ -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 <wine/wine_common_ver.rc>
index 4e64f40..0ea9a27 100644 (file)
 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)
 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
 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()
-
index ec772b8..a3f9df4 100644 (file)
@@ -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);
index 002a164..9dc33be 100644 (file)
@@ -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 */
 
index 09f8c5c..69698b7 100644 (file)
@@ -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)
     {
index 81b9e34..6025c97 100644 (file)
@@ -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 (!si)
+    {
+        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 & ~(MSITRANSFORM_VALIDATE_PRODUCT|MSITRANSFORM_VALIDATE_LANGUAGE))
-        FIXME("unsupported validation flags %x\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)
+    {
+        if (!template[0] || ((p = strchrW( template, ';' )) && match_language( package, atoiW( p + 1 ) )))
+        {
+            valid_flags |= MSITRANSFORM_VALIDATE_LANGUAGE;
+        }
+    }
     if (wanted_flags & MSITRANSFORM_VALIDATE_PRODUCT)
     {
-        WCHAR *package_product = msi_dup_property( package->db, szProductCode );
-        WCHAR *transform_product = msi_get_suminfo_product( transform );
+        WCHAR *product_code_installed = msi_dup_property( package->db, szProductCode );
 
-        TRACE("package = %s transform = %s\n", debugstr_w(package_product), debugstr_w(transform_product));
-
-        if (!transform_product || strstrW( transform_product, package_product ))
+        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( transform_product );
-        msi_free( package_product );
+        msi_free( product_code_installed );
     }
-    if (wanted_flags & MSITRANSFORM_VALIDATE_LANGUAGE)
+    if (wanted_flags & MSITRANSFORM_VALIDATE_PLATFORM)
     {
-        WCHAR *template;
-        const WCHAR *p;
+        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 (!si)
+        if (!product_version_installed)
         {
-            ERR("no summary information!\n");
-            goto end;
+            free_transform_desc( desc );
+            msiobj_release( &si->hdr );
+            return ERROR_INSTALL_PACKAGE_INVALID;
         }
-        if (!(template = msi_suminfo_dup_string( si, PID_TEMPLATE )))
+        msi_parse_version_string( product_version_installed, &major_installed, &minor_installed );
+        msi_parse_version_string( desc->version_from, &major, &minor );
+
+        if (major_installed == major)
         {
-            ERR("no template property!\n");
-            goto end;
+            valid_flags |= MSITRANSFORM_VALIDATE_MAJORVERSION;
+            wanted_flags &= ~MSITRANSFORM_VALIDATE_MINORVERSION;
         }
-        TRACE("template: %s\n", debugstr_w(template));
-        if (!template[0] || ((p = strchrW( template, ';' )) && match_language( package, atoiW( p + 1 ) )))
+        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)
         {
-            valid_flags |= MSITRANSFORM_VALIDATE_LANGUAGE;
+            free_transform_desc( desc );
+            msiobj_release( &si->hdr );
+            return ERROR_INSTALL_PACKAGE_INVALID;
         }
-        msi_free( template );
+        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;
 }
index 2429fa1..31995a8 100644 (file)
@@ -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 )
index f700da7..1165ec4 100644 (file)
@@ -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);
index ef57633..a88dc95 100644 (file)
@@ -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)
index 8b46565..bca1c01 100644 (file)
@@ -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,54 +25,30 @@ 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;
     }
-
-    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)
+    while (size >= db->num_streams_allocated)
     {
-        decode_streamname(name, decoded);
-        TRACE("stream -> %s %s\n", debugstr_w(name), debugstr_w(decoded));
-        name = decoded;
+        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;
     }
-
-    stream->str_index = msi_addstringW(sv->db->strings, name, -1, 1, StringNonPersistent);
-    stream->stream = stm;
-    return stream;
+    return TRUE;
 }
 
 static UINT STREAMS_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT *val)
@@ -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;
-
-    r = MSI_RecordGetIStream(rec, 2, &stm);
-    if (r != ERROR_SUCCESS)
-        return r;
+    if (row > sv->db->num_streams || mask >= (1 << sv->num_cols))
+        return ERROR_INVALID_PARAMETER;
 
-    hr = IStream_Stat(stm, &stat, STATFLAG_NONAME);
-    if (FAILED(hr))
+    if (mask & 1)
     {
-        WARN("failed to stat stream: %08x\n", hr);
-        goto done;
-    }
+        const WCHAR *name = MSI_RecordGetString( rec, 1 );
 
-    if (stat.cbSize.QuadPart >> 32)
-    {
-        WARN("stream too large\n");
-        goto done;
+        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;
 
-    data = msi_alloc(stat.cbSize.QuadPart);
-    if (!data)
-        goto done;
+        r = MSI_RecordGetIStream( rec, 2, &new );
+        if (r != ERROR_SUCCESS)
+            return r;
 
-    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;
+        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 );
     }
 
-    name = strdupW(MSI_RecordGetString(rec, 1));
-    if (!name)
-    {
-        WARN("failed to retrieve stream name\n");
-        goto done;
-    }
+    return ERROR_SUCCESS;
+}
 
-    encname = encode_streamname(FALSE, name);
-    msi_destroy_stream(sv->db, encname);
+static UINT streams_find_row( MSISTREAMSVIEW *sv, MSIRECORD *rec, UINT *row )
+{
+    const WCHAR *str;
+    UINT r, i, id, val;
 
-    r = write_stream_data(sv->db->storage, name, data, count, FALSE);
+    str = MSI_RecordGetString( rec, 1 );
+    r = msi_string2id( sv->db->strings, str, -1, &id );
     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;
+        return r;
 
-    hr = IStorage_OpenStream(sv->db->storage, encname, 0,
-                             STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream->stream);
-    if (FAILED(hr))
+    for (i = 0; i < sv->db->num_streams; i++)
     {
-        WARN("failed to open stream: %08x\n", hr);
-        msi_free(stream);
-        goto done;
-    }
-
-    sv->streams[row] = stream;
+        STREAMS_fetch_int( &sv->view, i, 1, &val );
 
-done:
-    msi_free(name);
-    msi_free(data);
-    msi_free(encname);
-
-    IStream_Release(stm);
+        if (val == id)
+        {
+            if (row) *row = i;
+            return ERROR_SUCCESS;
+        }
+    }
 
-    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;
+
+    TRACE("(%p, %d, %p, %p, %p, %p)\n", view, n, name, type, temporary, table_name);
 
-    if (n == 0 || n > NUM_STREAMS_COLS)
+    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;
-        }
+    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;
 
-        sv->streams[count - 1] = stream;
+    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;
     }
 
-    IEnumSTATSTG_Release(stgenum);
-    return count;
+    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)
+
+    *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 (;;)
     {
-        msi_free( sv );
-        return ERROR_FUNCTION_FAILED;
+        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;
     }
-    sv->num_rows = rows;
 
-    *view = (MSIVIEW *)sv;
+    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;
 }
index 0718866..7801392 100644 (file)
@@ -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");
index 7ecb9ad..db536dc 100644 (file)
@@ -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 )
index 9ee8596..862a613 100644 (file)
@@ -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