[MSI] Sync with Wine Staging 1.7.47. CORE-9924
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 19 Jul 2015 23:04:25 +0000 (23:04 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 19 Jul 2015 23:04:25 +0000 (23:04 +0000)
svn path=/trunk/; revision=68461

20 files changed:
reactos/dll/win32/msi/CMakeLists.txt
reactos/dll/win32/msi/action.c
reactos/dll/win32/msi/assembly.c
reactos/dll/win32/msi/automation.c
reactos/dll/win32/msi/custom.c
reactos/dll/win32/msi/database.c
reactos/dll/win32/msi/dialog.c
reactos/dll/win32/msi/files.c
reactos/dll/win32/msi/font.c
reactos/dll/win32/msi/install.c
reactos/dll/win32/msi/media.c
reactos/dll/win32/msi/msi.c
reactos/dll/win32/msi/msipriv.h
reactos/dll/win32/msi/package.c
reactos/dll/win32/msi/patch.c
reactos/dll/win32/msi/source.c
reactos/dll/win32/msi/streams.c
reactos/dll/win32/msi/suminfo.c
reactos/dll/win32/msi/table.c
reactos/media/doc/README.WINE

index 3e52477..daca0f3 100644 (file)
@@ -65,7 +65,7 @@ set_module_type(msi win32dll)
 target_link_libraries(msi uuid ${PSEH_LIB} wine)
 add_dependencies(msi msi_idlheader)
 add_delay_importlibs(msi odbccp32 crypt32 wintrust)
-add_importlibs(msi advapi32 cabinet comctl32 gdi32 ole32 oleaut32 shell32 shlwapi urlmon user32 version wininet
+add_importlibs(msi advapi32 cabinet comctl32 gdi32 ole32 oleaut32 shell32 shlwapi urlmon user32 version wininet mspatcha
     #FIXME : should be in delayed imports
     imagehlp
     msvcrt
index 0816eac..c1baa82 100644 (file)
@@ -1262,7 +1262,7 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
     load_file_hash(package, file);
     load_file_disk_id(package, file);
 
-    TRACE("File Loaded (%s)\n",debugstr_w(file->File));  
+    TRACE("File loaded (file %s sequence %u)\n", debugstr_w(file->File), file->Sequence);
 
     list_add_tail( &package->files, &file->entry );
  
@@ -1297,9 +1297,10 @@ static UINT load_media( MSIRECORD *row, LPVOID param )
     const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
 
     /* FIXME: load external cabinets and directory sources too */
-    if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS;
-    msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
-    return ERROR_SUCCESS;
+    if (!cabinet || cabinet[0] != '#' || disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
+        return ERROR_SUCCESS;
+
+    return msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
 }
 
 static UINT load_all_media( MSIPACKAGE *package )
@@ -1320,21 +1321,38 @@ static UINT load_all_media( MSIPACKAGE *package )
     return r;
 }
 
+static UINT load_patch_disk_id( MSIPACKAGE *package, MSIFILEPATCH *patch )
+{
+    static const WCHAR query[] =
+        {'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ',
+         '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
+         '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','u',0};
+    MSIRECORD *rec;
+
+    if (!(rec = MSI_QueryGetRecord( package->db, query, patch->Sequence )))
+    {
+        WARN("query failed\n");
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    patch->disk_id = MSI_RecordGetInteger( rec, 1 );
+    msiobj_release( &rec->hdr );
+    return ERROR_SUCCESS;
+}
+
 static UINT load_patch(MSIRECORD *row, LPVOID param)
 {
     MSIPACKAGE *package = param;
     MSIFILEPATCH *patch;
-    LPWSTR file_key;
+    const WCHAR *file_key;
 
     patch = msi_alloc_zero( sizeof (MSIFILEPATCH) );
     if (!patch)
         return ERROR_NOT_ENOUGH_MEMORY;
 
-    file_key = msi_dup_record_field( row, 1 );
+    file_key = MSI_RecordGetString( row, 1 );
     patch->File = msi_get_loaded_file( package, file_key );
-    msi_free(file_key);
-
-    if( !patch->File )
+    if (!patch->File)
     {
         ERR("Failed to find target for patch in File table\n");
         msi_free(patch);
@@ -1342,20 +1360,17 @@ static UINT load_patch(MSIRECORD *row, LPVOID param)
     }
 
     patch->Sequence = MSI_RecordGetInteger( row, 2 );
-
-    /* FIXME: The database should be properly transformed */
-    patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
-
     patch->PatchSize = MSI_RecordGetInteger( row, 3 );
     patch->Attributes = MSI_RecordGetInteger( row, 4 );
-    patch->IsApplied = FALSE;
 
     /* FIXME:
      * Header field - for patch validation.
      * _StreamRef   - External key into MsiPatchHeaders (instead of the header field)
      */
 
-    TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File));
+    load_patch_disk_id( package, patch );
+
+    TRACE("Patch loaded (file %s sequence %u)\n", debugstr_w(patch->File->File), patch->Sequence);
 
     list_add_tail( &package->filepatches, &patch->entry );
 
@@ -2060,7 +2075,6 @@ DWORD msi_get_disk_file_size( LPCWSTR filename )
         return INVALID_FILE_SIZE;
 
     size = GetFileSize( file, NULL );
-    TRACE("size is %u\n", size);
     CloseHandle( file );
     return size;
 }
@@ -2071,25 +2085,45 @@ BOOL msi_file_hash_matches( MSIFILE *file )
     MSIFILEHASHINFO hash;
 
     hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
-    r = MsiGetFileHashW( file->TargetPath, 0, &hash );
+    r = msi_get_filehash( file->TargetPath, &hash );
     if (r != ERROR_SUCCESS)
         return FALSE;
 
     return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) );
 }
 
-static WCHAR *get_temp_dir( void )
+static WCHAR *create_temp_dir( MSIDATABASE *db )
 {
     static UINT id;
-    WCHAR tmp[MAX_PATH], dir[MAX_PATH];
+    WCHAR *ret;
 
-    GetTempPathW( MAX_PATH, tmp );
-    for (;;)
+    if (!db->tempfolder)
     {
-        if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL;
-        if (CreateDirectoryW( dir, NULL )) break;
+        WCHAR tmp[MAX_PATH];
+        UINT len = sizeof(tmp)/sizeof(tmp[0]);
+
+        if (msi_get_property( db, szTempFolder, tmp, &len ) ||
+            GetFileAttributesW( tmp ) != FILE_ATTRIBUTE_DIRECTORY)
+        {
+            GetTempPathW( MAX_PATH, tmp );
+        }
+        if (!(db->tempfolder = strdupW( tmp ))) return NULL;
     }
-    return strdupW( dir );
+
+    if ((ret = msi_alloc( (strlenW( db->tempfolder ) + 20) * sizeof(WCHAR) )))
+    {
+        for (;;)
+        {
+            if (!GetTempFileNameW( db->tempfolder, szMsi, ++id, ret ))
+            {
+                msi_free( ret );
+                return NULL;
+            }
+            if (CreateDirectoryW( ret, NULL )) break;
+        }
+    }
+
+    return ret;
 }
 
 /*
@@ -2140,18 +2174,20 @@ WCHAR *msi_build_directory_name( DWORD count, ... )
     return dir;
 }
 
-static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
+BOOL msi_is_global_assembly( MSICOMPONENT *comp )
 {
-    MSIASSEMBLY *assembly = file->Component->assembly;
-
-    TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName));
+    return comp->assembly && !comp->assembly->application;
+}
 
+static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
+{
     msi_free( file->TargetPath );
-    if (assembly && !assembly->application)
+    if (msi_is_global_assembly( file->Component ))
     {
-        if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
+        MSIASSEMBLY *assembly = file->Component->assembly;
+
+        if (!assembly->tempdir) assembly->tempdir = create_temp_dir( package->db );
         file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
-        msi_track_tempfile( package, file->TargetPath );
     }
     else
     {
@@ -2159,7 +2195,7 @@ static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
         file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
     }
 
-    TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
+    TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
 }
 
 static UINT calculate_file_cost( MSIPACKAGE *package )
@@ -2187,6 +2223,7 @@ static UINT calculate_file_cost( MSIPACKAGE *package )
             continue;
         }
         file_size = msi_get_disk_file_size( file->TargetPath );
+        TRACE("%s (size %u)\n", debugstr_w(file->TargetPath), file_size);
 
         if (file->Version)
         {
index cb8130d..84026c2 100644 (file)
@@ -29,6 +29,8 @@ static HRESULT (WINAPI *pCreateAssemblyCacheNet40)( IAssemblyCache **, DWORD );
 static HRESULT (WINAPI *pCreateAssemblyCacheSxs)( IAssemblyCache **, DWORD );
 static HRESULT (WINAPI *pLoadLibraryShim)( LPCWSTR, LPCWSTR, LPVOID, HMODULE * );
 static HRESULT (WINAPI *pGetFileVersion)( LPCWSTR, LPWSTR, DWORD, DWORD * );
+static HRESULT (WINAPI *pCreateAssemblyNameObject)( IAssemblyName **, LPCWSTR, DWORD, LPVOID );
+static HRESULT (WINAPI *pCreateAssemblyEnum)( IAssemblyEnum **, IUnknown *, IAssemblyName *, DWORD, LPVOID );
 
 static HMODULE hfusion10, hfusion11, hfusion20, hfusion40, hmscoree, hsxs;
 
@@ -70,8 +72,11 @@ static BOOL init_function_pointers( void )
         pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" );
 
     if (!pLoadLibraryShim( szFusion, szVersion40, NULL, &hfusion40 ))
+    {
         pCreateAssemblyCacheNet40 = (void *)GetProcAddress( hfusion40, "CreateAssemblyCache" );
-
+        pCreateAssemblyNameObject = (void *)GetProcAddress( hfusion40, "CreateAssemblyNameObject" );
+        pCreateAssemblyEnum = (void *)GetProcAddress( hfusion40, "CreateAssemblyEnum" );
+    }
     return TRUE;
 }
 
@@ -250,6 +255,70 @@ static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_n
     return FALSE;
 }
 
+WCHAR *msi_get_assembly_path( MSIPACKAGE *package, const WCHAR *displayname )
+{
+    HRESULT hr;
+    ASSEMBLY_INFO info;
+    IAssemblyCache *cache = package->cache_net[CLR_VERSION_V40];
+
+    if (!cache) return NULL;
+
+    memset( &info, 0, sizeof(info) );
+    info.cbAssemblyInfo = sizeof(info);
+    hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info );
+    if (hr != E_NOT_SUFFICIENT_BUFFER) return NULL;
+
+    if (!(info.pszCurrentAssemblyPathBuf = msi_alloc( info.cchBuf * sizeof(WCHAR) ))) return NULL;
+
+    hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info );
+    if (FAILED( hr ))
+    {
+        msi_free( info.pszCurrentAssemblyPathBuf );
+        return NULL;
+    }
+    TRACE("returning %s\n", debugstr_w(info.pszCurrentAssemblyPathBuf));
+    return info.pszCurrentAssemblyPathBuf;
+}
+
+IAssemblyEnum *msi_create_assembly_enum( MSIPACKAGE *package, const WCHAR *displayname )
+{
+    HRESULT hr;
+    IAssemblyName *name;
+    IAssemblyEnum *ret;
+    WCHAR *str;
+    UINT len = 0;
+
+    if (!pCreateAssemblyNameObject || !pCreateAssemblyEnum) return NULL;
+
+    hr = pCreateAssemblyNameObject( &name, displayname, CANOF_PARSE_DISPLAY_NAME, NULL );
+    if (FAILED( hr )) return NULL;
+
+    hr = IAssemblyName_GetName( name, &len, NULL );
+    if (hr != E_NOT_SUFFICIENT_BUFFER || !(str = msi_alloc( len * sizeof(WCHAR) )))
+    {
+        IAssemblyName_Release( name );
+        return NULL;
+    }
+
+    hr = IAssemblyName_GetName( name, &len, str );
+    IAssemblyName_Release( name );
+    if (FAILED( hr ))
+    {
+        msi_free( str );
+        return NULL;
+    }
+
+    hr = pCreateAssemblyNameObject( &name, str, 0, NULL );
+    msi_free( str );
+    if (FAILED( hr )) return NULL;
+
+    hr = pCreateAssemblyEnum( &ret, NULL, name, ASM_CACHE_GAC, NULL );
+    IAssemblyName_Release( name );
+    if (FAILED( hr )) return NULL;
+
+    return ret;
+}
+
 static const WCHAR clr_version_v10[] = {'v','1','.','0','.','3','7','0','5',0};
 static const WCHAR clr_version_v11[] = {'v','1','.','1','.','4','3','2','2',0};
 static const WCHAR clr_version_v20[] = {'v','2','.','0','.','5','0','7','2','7',0};
index dda9430..01a1ac8 100644 (file)
@@ -1350,7 +1350,7 @@ static HRESULT session_invoke(
 {
     SessionObject *session = (SessionObject*)This;
     WCHAR *szString;
-    DWORD dwLen;
+    DWORD dwLen = 0;
     MSIHANDLE msiHandle;
     LANGID langId;
     UINT ret;
index a750c7a..ad24101 100644 (file)
@@ -189,6 +189,35 @@ static void set_deferred_action_props( MSIPACKAGE *package, const WCHAR *deferre
     msi_set_property( package->db, szProductCode, beg, end - beg );
 }
 
+WCHAR *msi_create_temp_file( MSIDATABASE *db )
+{
+    WCHAR *ret;
+
+    if (!db->tempfolder)
+    {
+        WCHAR tmp[MAX_PATH];
+        UINT len = sizeof(tmp)/sizeof(tmp[0]);
+
+        if (msi_get_property( db, szTempFolder, tmp, &len ) ||
+            GetFileAttributesW( tmp ) != FILE_ATTRIBUTE_DIRECTORY)
+        {
+            GetTempPathW( MAX_PATH, tmp );
+        }
+        if (!(db->tempfolder = strdupW( tmp ))) return NULL;
+    }
+
+    if ((ret = msi_alloc( (strlenW( db->tempfolder ) + 20) * sizeof(WCHAR) )))
+    {
+        if (!GetTempFileNameW( db->tempfolder, szMsi, 0, ret ))
+        {
+            msi_free( ret );
+            return NULL;
+        }
+    }
+
+    return ret;
+}
+
 static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll )
 {
     static const WCHAR query[] = {
@@ -196,38 +225,21 @@ static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL
         '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ',
         '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
     MSIRECORD *row;
-    MSIBINARY *binary;
+    MSIBINARY *binary = NULL;
     HANDLE file;
     CHAR buffer[1024];
-    WCHAR fmt[MAX_PATH], tmpfile[MAX_PATH];
-    DWORD sz = MAX_PATH, write;
+    WCHAR *tmpfile;
+    DWORD sz, write;
     UINT r;
 
-    if (msi_get_property(package->db, szTempFolder, fmt, &sz) != ERROR_SUCCESS ||
-        GetFileAttributesW(fmt) == INVALID_FILE_ATTRIBUTES) GetTempPathW(MAX_PATH, fmt);
+    if (!(tmpfile = msi_create_temp_file( package->db ))) return NULL;
 
-    if (!GetTempFileNameW( fmt, szMsi, 0, tmpfile ))
-    {
-        TRACE("unable to create temp file %s (%u)\n", debugstr_w(tmpfile), GetLastError());
-        return NULL;
-    }
+    if (!(row = MSI_QueryGetRecord( package->db, query, source ))) goto error;
+    if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) ))) goto error;
 
-    row = MSI_QueryGetRecord(package->db, query, source);
-    if (!row)
-        return NULL;
+    file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
+    if (file == INVALID_HANDLE_VALUE) goto error;
 
-    if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) )))
-    {
-        msiobj_release( &row->hdr );
-        return NULL;
-    }
-    file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
-    if (file == INVALID_HANDLE_VALUE)
-    {
-        msiobj_release( &row->hdr );
-        msi_free( binary );
-        return NULL;
-    }
     do
     {
         sz = sizeof(buffer);
@@ -241,13 +253,7 @@ static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL
     } while (sz == sizeof buffer);
 
     CloseHandle( file );
-    msiobj_release( &row->hdr );
-    if (r != ERROR_SUCCESS)
-    {
-        DeleteFileW( tmpfile );
-        msi_free( binary );
-        return NULL;
-    }
+    if (r != ERROR_SUCCESS) goto error;
 
     /* keep a reference to prevent the dll from being unloaded */
     if (dll && !(binary->module = LoadLibraryW( tmpfile )))
@@ -255,9 +261,18 @@ static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL
         WARN( "failed to load dll %s (%u)\n", debugstr_w( tmpfile ), GetLastError() );
     }
     binary->source = strdupW( source );
-    binary->tmpfile = strdupW( tmpfile );
+    binary->tmpfile = tmpfile;
     list_add_tail( &package->binaries, &binary->entry );
+
+    msiobj_release( &row->hdr );
     return binary;
+
+error:
+    if (row) msiobj_release( &row->hdr );
+    DeleteFileW( tmpfile );
+    msi_free( tmpfile );
+    msi_free( binary );
+    return NULL;
 }
 
 static MSIBINARY *get_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll )
@@ -1443,7 +1458,7 @@ HRESULT create_msi_custom_remote( IUnknown *pOuter, LPVOID *ppObj )
     This->IWineMsiRemoteCustomAction_iface.lpVtbl = &msi_custom_remote_vtbl;
     This->refs = 1;
 
-    *ppObj = This;
+    *ppObj = &This->IWineMsiRemoteCustomAction_iface;
 
     return S_OK;
 }
index e170472..b815b72 100644 (file)
@@ -82,6 +82,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
         DeleteFileW( db->deletefile );
         msi_free( db->deletefile );
     }
+    msi_free( db->tempfolder );
 }
 
 static HRESULT db_initialize( IStorage *stg, const GUID *clsid )
@@ -137,8 +138,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
     if( !pdb )
         return ERROR_INVALID_PARAMETER;
 
-    if (szPersist - MSIDBOPEN_PATCHFILE >= MSIDBOPEN_READONLY &&
-        szPersist - MSIDBOPEN_PATCHFILE <= MSIDBOPEN_CREATEDIRECT)
+    if (szPersist - MSIDBOPEN_PATCHFILE <= MSIDBOPEN_CREATEDIRECT)
     {
         TRACE("Database is a patch\n");
         szPersist -= MSIDBOPEN_PATCHFILE;
@@ -2004,7 +2004,7 @@ HRESULT create_msi_remote_database( IUnknown *pOuter, LPVOID *ppObj )
     This->database = 0;
     This->refs = 1;
 
-    *ppObj = This;
+    *ppObj = &This->IWineMsiRemoteDatabase_iface;
 
     return S_OK;
 }
index b4c18d6..3f5c7c5 100644 (file)
@@ -102,7 +102,6 @@ typedef struct
 {
     msi_dialog* dialog;
     msi_control *parent;
-    DWORD       attributes;
     LPWSTR      propval;
 } radio_button_group_descr;
 
@@ -476,42 +475,17 @@ static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name )
     return MSI_QueryGetRecord( db, query, name );
 }
 
-static LPWSTR msi_create_tmp_path(void)
-{
-    WCHAR tmp[MAX_PATH];
-    LPWSTR path = NULL;
-    DWORD len, r;
-
-    r = GetTempPathW( MAX_PATH, tmp );
-    if( !r )
-        return path;
-    len = lstrlenW( tmp ) + 20;
-    path = msi_alloc( len * sizeof (WCHAR) );
-    if( path )
-    {
-        r = GetTempFileNameW( tmp, szMsi, 0, path );
-        if (!r)
-        {
-            msi_free( path );
-            path = NULL;
-        }
-    }
-    return path;
-}
-
 static HANDLE msi_load_image( MSIDATABASE *db, LPCWSTR name, UINT type,
                               UINT cx, UINT cy, UINT flags )
 {
-    MSIRECORD *rec = NULL;
+    MSIRECORD *rec;
     HANDLE himage = NULL;
     LPWSTR tmp;
     UINT r;
 
     TRACE("%p %s %u %u %08x\n", db, debugstr_w(name), cx, cy, flags);
 
-    tmp = msi_create_tmp_path();
-    if( !tmp )
-        return himage;
+    if (!(tmp = msi_create_temp_file( db ))) return NULL;
 
     rec = msi_get_binary_record( db, name );
     if( rec )
@@ -2267,15 +2241,10 @@ static UINT msi_dialog_create_radiobutton( MSIRECORD *rec, LPVOID param )
     msi_dialog *dialog = group->dialog;
     msi_control *control;
     LPCWSTR prop, text, name;
-    DWORD style, attributes = group->attributes;
+    DWORD style = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTORADIOBUTTON | BS_MULTILINE;
 
-    style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE | WS_TABSTOP;
     name = MSI_RecordGetString( rec, 3 );
     text = MSI_RecordGetString( rec, 8 );
-    if( attributes & msidbControlAttributesVisible )
-        style |= WS_VISIBLE;
-    if( ~attributes & msidbControlAttributesEnabled )
-        style |= WS_DISABLED;
 
     control = dialog_create_window( dialog, rec, 0, szButton, name, text, style,
                                     group->parent->hwnd );
@@ -2338,6 +2307,10 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
     TRACE("%p %p %s\n", dialog, rec, debugstr_w( prop ));
 
     attr = MSI_RecordGetInteger( rec, 8 );
+    if (attr & msidbControlAttributesVisible)
+        style |= WS_VISIBLE;
+    if (~attr & msidbControlAttributesEnabled)
+        style |= WS_DISABLED;
     if (attr & msidbControlAttributesHasBorder)
         style |= BS_GROUPBOX;
     else
@@ -2367,7 +2340,6 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
 
     group.dialog = dialog;
     group.parent = control;
-    group.attributes = MSI_RecordGetInteger( rec, 8 );
     group.propval = msi_dup_property( dialog->package->db, control->property );
 
     r = MSI_IterateRecords( view, 0, msi_dialog_create_radiobutton, &group );
index 943bc7b..981d568 100644 (file)
 
 #include "msipriv.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+#include <patchapi.h>
 
-static HMODULE hmspatcha;
-static BOOL (WINAPI *ApplyPatchToFileW)(LPCWSTR, LPCWSTR, LPCWSTR, ULONG);
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
 static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *action )
 {
@@ -50,40 +49,71 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *ac
     msi_ui_progress( package, 2, f->FileSize, 0, 0 );
 }
 
+static BOOL is_registered_patch_media( MSIPACKAGE *package, UINT disk_id )
+{
+    MSIPATCHINFO *patch;
+
+    LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
+    {
+        if (patch->disk_id == disk_id && patch->registered) return TRUE;
+    }
+    return FALSE;
+}
+
+static BOOL is_obsoleted_by_patch( MSIPACKAGE *package, MSIFILE *file )
+{
+    if (!list_empty( &package->patches ) && file->disk_id < MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
+    {
+        if (!msi_get_property_int( package->db, szInstalled, 0 )) return FALSE;
+        return TRUE;
+    }
+    if (is_registered_patch_media( package, file->disk_id )) return TRUE;
+    return FALSE;
+}
+
 static msi_file_state calculate_install_state( MSIPACKAGE *package, MSIFILE *file )
 {
     MSICOMPONENT *comp = file->Component;
     VS_FIXEDFILEINFO *file_version;
     WCHAR *font_version;
     msi_file_state state;
+    DWORD size;
 
     comp->Action = msi_get_component_action( package, comp );
-    if (comp->Action != INSTALLSTATE_LOCAL || (comp->assembly && comp->assembly->installed))
+    if (!comp->Enabled || comp->Action != INSTALLSTATE_LOCAL || (comp->assembly && comp->assembly->installed))
     {
-        TRACE("file %s is not scheduled for install\n", debugstr_w(file->File));
+        TRACE("skipping %s (not scheduled for install)\n", debugstr_w(file->File));
         return msifs_skipped;
     }
-    if ((comp->assembly && !comp->assembly->application && !comp->assembly->installed) ||
+    if (is_obsoleted_by_patch( package, file ))
+    {
+        TRACE("skipping %s (obsoleted by patch)\n", debugstr_w(file->File));
+        return msifs_skipped;
+    }
+    if ((msi_is_global_assembly( comp ) && !comp->assembly->installed) ||
         GetFileAttributesW( file->TargetPath ) == INVALID_FILE_ATTRIBUTES)
     {
-        TRACE("file %s is missing\n", debugstr_w(file->File));
+        TRACE("installing %s (missing)\n", debugstr_w(file->File));
         return msifs_missing;
     }
     if (file->Version)
     {
         if ((file_version = msi_get_disk_file_version( file->TargetPath )))
         {
-            TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version),
-                  HIWORD(file_version->dwFileVersionMS),
-                  LOWORD(file_version->dwFileVersionMS),
-                  HIWORD(file_version->dwFileVersionLS),
-                  LOWORD(file_version->dwFileVersionLS));
-
             if (msi_compare_file_versions( file_version, file->Version ) < 0)
+            {
+                TRACE("overwriting %s (new version %s old version %u.%u.%u.%u)\n",
+                      debugstr_w(file->File), debugstr_w(file->Version),
+                      HIWORD(file_version->dwFileVersionMS), LOWORD(file_version->dwFileVersionMS),
+                      HIWORD(file_version->dwFileVersionLS), LOWORD(file_version->dwFileVersionLS));
                 state = msifs_overwrite;
+            }
             else
             {
-                TRACE("destination file version equal or greater, not overwriting\n");
+                TRACE("keeping %s (new version %s old version %u.%u.%u.%u)\n",
+                      debugstr_w(file->File), debugstr_w(file->Version),
+                      HIWORD(file_version->dwFileVersionMS), LOWORD(file_version->dwFileVersionMS),
+                      HIWORD(file_version->dwFileVersionLS), LOWORD(file_version->dwFileVersionLS));
                 state = msifs_present;
             }
             msi_free( file_version );
@@ -91,37 +121,42 @@ static msi_file_state calculate_install_state( MSIPACKAGE *package, MSIFILE *fil
         }
         else if ((font_version = msi_font_version_from_file( file->TargetPath )))
         {
-            TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(font_version));
-
             if (msi_compare_font_versions( font_version, file->Version ) < 0)
+            {
+                TRACE("overwriting %s (new version %s old version %s)\n",
+                      debugstr_w(file->File), debugstr_w(file->Version), debugstr_w(font_version));
                 state = msifs_overwrite;
+            }
             else
             {
-                TRACE("destination file version equal or greater, not overwriting\n");
+                TRACE("keeping %s (new version %s old version %s)\n",
+                      debugstr_w(file->File), debugstr_w(file->Version), debugstr_w(font_version));
                 state = msifs_present;
             }
             msi_free( font_version );
             return state;
         }
     }
-    if (msi_get_disk_file_size( file->TargetPath ) != file->FileSize)
+    if ((size = msi_get_disk_file_size( file->TargetPath )) != file->FileSize)
     {
+        TRACE("overwriting %s (old size %u new size %u)\n", debugstr_w(file->File), size, file->FileSize);
         return msifs_overwrite;
     }
     if (file->hash.dwFileHashInfoSize)
     {
         if (msi_file_hash_matches( file ))
         {
-            TRACE("file hashes match, not overwriting\n");
+            TRACE("keeping %s (hash match)\n", debugstr_w(file->File));
             return msifs_hashmatch;
         }
         else
         {
-            TRACE("file hashes do not match, overwriting\n");
+            TRACE("overwriting %s (hash mismatch)\n", debugstr_w(file->File));
             return msifs_overwrite;
         }
     }
     /* assume present */
+    TRACE("keeping %s\n", debugstr_w(file->File));
     return msifs_present;
 }
 
@@ -246,33 +281,32 @@ static MSIFILE *find_file( MSIPACKAGE *package, UINT disk_id, const WCHAR *filen
     return NULL;
 }
 
-static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
+static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR filename, DWORD action,
                             LPWSTR *path, DWORD *attrs, PVOID user)
 {
-    static MSIFILE *f = NULL;
-    UINT_PTR disk_id = (UINT_PTR)user;
+    MSIFILE *file = *(MSIFILE **)user;
 
     if (action == MSICABEXTRACT_BEGINEXTRACT)
     {
-        if (!(f = find_file( package, disk_id, file )))
+        if (!(file = find_file( package, file->disk_id, filename )))
         {
-            TRACE("unknown file in cabinet (%s)\n", debugstr_w(file));
+            TRACE("unknown file in cabinet (%s)\n", debugstr_w(filename));
             return FALSE;
         }
-        if (f->disk_id != disk_id || (f->state != msifs_missing && f->state != msifs_overwrite))
+        if (file->state != msifs_missing && file->state != msifs_overwrite)
             return FALSE;
 
-        if (!f->Component->assembly || f->Component->assembly->application)
+        if (!msi_is_global_assembly( file->Component ))
         {
-            msi_create_directory(package, f->Component->Directory);
+            msi_create_directory( package, file->Component->Directory );
         }
-        *path = strdupW(f->TargetPath);
-        *attrs = f->Attributes;
+        *path = strdupW( file->TargetPath );
+        *attrs = file->Attributes;
+        *(MSIFILE **)user = file;
     }
     else if (action == MSICABEXTRACT_FILEEXTRACTED)
     {
-        f->state = msifs_installed;
-        f = NULL;
+        if (!msi_is_global_assembly( file->Component )) file->state = msifs_installed;
     }
 
     return TRUE;
@@ -309,7 +343,6 @@ WCHAR *msi_resolve_file_source( MSIPACKAGE *package, MSIFILE *file )
 UINT ACTION_InstallFiles(MSIPACKAGE *package)
 {
     MSIMEDIAINFO *mi;
-    MSICOMPONENT *comp;
     UINT rc = ERROR_SUCCESS;
     MSIFILE *file;
 
@@ -327,7 +360,6 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
             rc = ERROR_FUNCTION_FAILED;
             goto done;
         }
-        if (!file->Component->Enabled) continue;
 
         if (file->state != msifs_hashmatch &&
             file->state != msifs_skipped &&
@@ -345,14 +377,14 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
             (file->IsCompressed && !mi->is_extracted))
         {
             MSICABDATA data;
+            MSIFILE *cursor = file;
 
             data.mi = mi;
             data.package = package;
             data.cb = installfiles_cb;
-            data.user = (PVOID)(UINT_PTR)mi->disk_id;
+            data.user = &cursor;
 
-            if (file->IsCompressed &&
-                !msi_cabextract(package, mi, &data))
+            if (file->IsCompressed && !msi_cabextract(package, mi, &data))
             {
                 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
                 rc = ERROR_INSTALL_FAILURE;
@@ -366,41 +398,43 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
 
             TRACE("copying %s to %s\n", debugstr_w(source), debugstr_w(file->TargetPath));
 
-            if (!file->Component->assembly || file->Component->assembly->application)
+            if (!msi_is_global_assembly( file->Component ))
             {
                 msi_create_directory(package, file->Component->Directory);
             }
             rc = copy_install_file(package, file, source);
             if (rc != ERROR_SUCCESS)
             {
-                ERR("Failed to copy %s to %s (%d)\n", debugstr_w(source),
-                    debugstr_w(file->TargetPath), rc);
+                ERR("Failed to copy %s to %s (%u)\n", debugstr_w(source), debugstr_w(file->TargetPath), rc);
                 rc = ERROR_INSTALL_FAILURE;
                 msi_free(source);
                 goto done;
             }
             msi_free(source);
         }
-        else if (file->state != msifs_installed && !(file->Attributes & msidbFileAttributesPatchAdded))
+        else if (!msi_is_global_assembly( file->Component ) &&
+                 file->state != msifs_installed && !(file->Attributes & msidbFileAttributesPatchAdded))
         {
             ERR("compressed file wasn't installed (%s)\n", debugstr_w(file->File));
             rc = ERROR_INSTALL_FAILURE;
             goto done;
         }
     }
-    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
+    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
-        comp->Action = msi_get_component_action( package, comp );
-        if (comp->Action == INSTALLSTATE_LOCAL && comp->assembly && !comp->assembly->installed)
+        MSICOMPONENT *comp = file->Component;
+
+        if (!msi_is_global_assembly( comp ) || comp->assembly->installed ||
+            (file->state != msifs_missing && file->state != msifs_overwrite)) continue;
+
+        rc = msi_install_assembly( package, comp );
+        if (rc != ERROR_SUCCESS)
         {
-            rc = msi_install_assembly( package, comp );
-            if (rc != ERROR_SUCCESS)
-            {
-                ERR("Failed to install assembly\n");
-                rc = ERROR_INSTALL_FAILURE;
-                break;
-            }
+            ERR("Failed to install assembly\n");
+            rc = ERROR_INSTALL_FAILURE;
+            break;
         }
+        file->state = msifs_installed;
     }
 
 done:
@@ -408,37 +442,14 @@ done:
     return rc;
 }
 
-static BOOL load_mspatcha(void)
-{
-    hmspatcha = LoadLibraryA("mspatcha.dll");
-    if (!hmspatcha)
-    {
-        ERR("Failed to load mspatcha.dll: %d\n", GetLastError());
-        return FALSE;
-    }
-
-    ApplyPatchToFileW = (void*)GetProcAddress(hmspatcha, "ApplyPatchToFileW");
-    if(!ApplyPatchToFileW)
-    {
-        ERR("GetProcAddress(ApplyPatchToFileW) failed: %d.\n", GetLastError());
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-static void unload_mspatch(void)
-{
-    FreeLibrary(hmspatcha);
-}
-
-static MSIFILEPATCH *get_next_filepatch( MSIPACKAGE *package, const WCHAR *key )
+static MSIFILEPATCH *find_filepatch( MSIPACKAGE *package, UINT disk_id, const WCHAR *key )
 {
     MSIFILEPATCH *patch;
 
     LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
     {
-        if (!patch->IsApplied && !strcmpW( key, patch->File->File )) return patch;
+        if (!patch->extracted && patch->disk_id == disk_id && !strcmpW( key, patch->File->File ))
+            return patch;
     }
     return NULL;
 }
@@ -446,48 +457,107 @@ static MSIFILEPATCH *get_next_filepatch( MSIPACKAGE *package, const WCHAR *key )
 static BOOL patchfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
                           LPWSTR *path, DWORD *attrs, PVOID user)
 {
-    static MSIFILEPATCH *p = NULL;
-    static WCHAR patch_path[MAX_PATH] = {0};
-    static WCHAR temp_folder[MAX_PATH] = {0};
+    MSIFILEPATCH *patch = *(MSIFILEPATCH **)user;
 
     if (action == MSICABEXTRACT_BEGINEXTRACT)
     {
-        if (temp_folder[0] == '\0')
-            GetTempPathW(MAX_PATH, temp_folder);
+        MSICOMPONENT *comp;
 
-        if (!(p = get_next_filepatch(package, file)) || !p->File->Component->Enabled)
-            return FALSE;
+        if (is_registered_patch_media( package, patch->disk_id ) ||
+            !(patch = find_filepatch( package, patch->disk_id, file ))) return FALSE;
 
-        GetTempFileNameW(temp_folder, NULL, 0, patch_path);
+        comp = patch->File->Component;
+        comp->Action = msi_get_component_action( package, comp );
+        if (!comp->Enabled || comp->Action != INSTALLSTATE_LOCAL)
+        {
+            TRACE("file %s component %s not installed or disabled\n",
+                  debugstr_w(patch->File->File), debugstr_w(comp->Component));
+            return FALSE;
+        }
 
-        *path = strdupW(patch_path);
-        *attrs = p->File->Attributes;
+        patch->path = msi_create_temp_file( package->db );
+        *path = strdupW( patch->path );
+        *attrs = patch->File->Attributes;
+        *(MSIFILEPATCH **)user = patch;
     }
     else if (action == MSICABEXTRACT_FILEEXTRACTED)
     {
-        WCHAR patched_file[MAX_PATH];
-        BOOL br;
+        patch->extracted = TRUE;
+    }
+
+    return TRUE;
+}
 
-        GetTempFileNameW(temp_folder, NULL, 0, patched_file);
+static UINT patch_file( MSIPACKAGE *package, MSIFILEPATCH *patch )
+{
+    UINT r = ERROR_SUCCESS;
+    WCHAR *tmpfile = msi_create_temp_file( package->db );
 
-        br = ApplyPatchToFileW(patch_path, p->File->TargetPath, patched_file, 0);
-        if (br)
-        {
-            /* FIXME: baseline cache */
+    if (!tmpfile) return ERROR_INSTALL_FAILURE;
+    if (ApplyPatchToFileW( patch->path, patch->File->TargetPath, tmpfile, 0 ))
+    {
+        DeleteFileW( patch->File->TargetPath );
+        MoveFileW( tmpfile, patch->File->TargetPath );
+    }
+    else
+    {
+        WARN("failed to patch %s: %08x\n", debugstr_w(patch->File->TargetPath), GetLastError());
+        r = ERROR_INSTALL_FAILURE;
+    }
+    DeleteFileW( patch->path );
+    DeleteFileW( tmpfile );
+    msi_free( tmpfile );
+    return r;
+}
+
+static UINT patch_assembly( MSIPACKAGE *package, MSIASSEMBLY *assembly, MSIFILEPATCH *patch )
+{
+    UINT r = ERROR_FUNCTION_FAILED;
+    IAssemblyName *name;
+    IAssemblyEnum *iter;
+
+    if (!(iter = msi_create_assembly_enum( package, assembly->display_name )))
+        return ERROR_FUNCTION_FAILED;
 
-            DeleteFileW( p->File->TargetPath );
-            MoveFileW( patched_file, p->File->TargetPath );
+    while ((IAssemblyEnum_GetNextAssembly( iter, NULL, &name, 0 ) == S_OK))
+    {
+        WCHAR *displayname, *path;
+        UINT len = 0;
+        HRESULT hr;
+
+        hr = IAssemblyName_GetDisplayName( name, NULL, &len, 0 );
+        if (hr != E_NOT_SUFFICIENT_BUFFER || !(displayname = msi_alloc( len * sizeof(WCHAR) )))
+            break;
 
-            p->IsApplied = TRUE;
+        hr = IAssemblyName_GetDisplayName( name, displayname, &len, 0 );
+        if (FAILED( hr ))
+        {
+            msi_free( displayname );
+            break;
         }
-        else
-            ERR("Failed patch %s: %d.\n", debugstr_w(p->File->TargetPath), GetLastError());
 
-        DeleteFileW(patch_path);
-        p = NULL;
+        if ((path = msi_get_assembly_path( package, displayname )))
+        {
+            if (!CopyFileW( path, patch->File->TargetPath, FALSE ))
+            {
+                ERR("Failed to copy file %s -> %s (%u)\n", debugstr_w(path),
+                    debugstr_w(patch->File->TargetPath), GetLastError() );
+                msi_free( path );
+                msi_free( displayname );
+                IAssemblyName_Release( name );
+                break;
+            }
+            r = patch_file( package, patch );
+            msi_free( path );
+        }
+
+        msi_free( displayname );
+        IAssemblyName_Release( name );
+        if (r == ERROR_SUCCESS) break;
     }
 
-    return TRUE;
+    IAssemblyEnum_Release( iter );
+    return r;
 }
 
 UINT ACTION_PatchFiles( MSIPACKAGE *package )
@@ -495,12 +565,13 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package )
     MSIFILEPATCH *patch;
     MSIMEDIAINFO *mi;
     UINT rc = ERROR_SUCCESS;
-    BOOL mspatcha_loaded = FALSE;
 
     TRACE("%p\n", package);
 
     mi = msi_alloc_zero( sizeof(MSIMEDIAINFO) );
 
+    TRACE("extracting files\n");
+
     LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
     {
         MSIFILE *file = patch->File;
@@ -516,9 +587,10 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package )
         comp->Action = msi_get_component_action( package, comp );
         if (!comp->Enabled || comp->Action != INSTALLSTATE_LOCAL) continue;
 
-        if (!patch->IsApplied)
+        if (!patch->extracted)
         {
             MSICABDATA data;
+            MSIFILEPATCH *cursor = patch;
 
             rc = ready_media( package, TRUE, mi );
             if (rc != ERROR_SUCCESS)
@@ -526,39 +598,51 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package )
                 ERR("Failed to ready media for %s\n", debugstr_w(file->File));
                 goto done;
             }
-
-            if (!mspatcha_loaded && !load_mspatcha())
-            {
-                rc = ERROR_FUNCTION_FAILED;
-                goto done;
-            }
-            mspatcha_loaded = TRUE;
-
-            data.mi = mi;
+            data.mi      = mi;
             data.package = package;
-            data.cb = patchfiles_cb;
-            data.user = (PVOID)(UINT_PTR)mi->disk_id;
+            data.cb      = patchfiles_cb;
+            data.user    = &cursor;
 
-            if (!msi_cabextract(package, mi, &data))
+            if (!msi_cabextract( package, mi, &data ))
             {
                 ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet));
                 rc = ERROR_INSTALL_FAILURE;
                 goto done;
             }
         }
+    }
+
+    TRACE("applying patches\n");
 
-        if (!patch->IsApplied && !(patch->Attributes & msidbPatchAttributesNonVital))
+    LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
+    {
+        MSICOMPONENT *comp = patch->File->Component;
+
+        if (!patch->path) continue;
+
+        if (msi_is_global_assembly( comp ))
+            rc = patch_assembly( package, comp->assembly, patch );
+        else
+            rc = patch_file( package, patch );
+
+        if (rc && !(patch->Attributes & msidbPatchAttributesNonVital))
         {
-            ERR("Failed to apply patch to file: %s\n", debugstr_w(file->File));
-            rc = ERROR_INSTALL_FAILURE;
-            goto done;
+            ERR("Failed to apply patch to file: %s\n", debugstr_w(patch->File->File));
+            break;
+        }
+
+        if (msi_is_global_assembly( comp ))
+        {
+            if ((rc = msi_install_assembly( package, comp )))
+            {
+                ERR("Failed to install patched assembly\n");
+                break;
+            }
         }
     }
 
 done:
     msi_free_media_info(mi);
-    if (mspatcha_loaded)
-        unload_mspatch();
     return rc;
 }
 
index e2a7734..999f884 100644 (file)
@@ -165,7 +165,6 @@ static WCHAR *load_ttf_name_id( const WCHAR *filename, DWORD id )
 
 end:
     CloseHandle(handle);
-    TRACE("Returning %s\n", debugstr_w(ret));
     return ret;
 }
 
index da21ad3..5414715 100644 (file)
@@ -573,7 +573,7 @@ UINT MSI_SetTargetPathW( MSIPACKAGE *package, LPCWSTR szFolder, LPCWSTR szFolder
         const WCHAR *dir;
         MSICOMPONENT *comp = file->Component;
 
-        if (!comp->Enabled || (comp->assembly && !comp->assembly->application)) continue;
+        if (!comp->Enabled || msi_is_global_assembly( comp )) continue;
 
         dir = msi_get_target_folder( package, comp->Directory );
         msi_free( file->TargetPath );
index 0b6408d..e7f24c4 100644 (file)
@@ -43,8 +43,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
 static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPCWSTR source_root)
 {
-    WCHAR volume_name[MAX_PATH + 1];
-    WCHAR root[MAX_PATH + 1];
+    WCHAR volume_name[MAX_PATH + 1], root[MAX_PATH + 1];
+    const WCHAR *p;
+    int len, len2;
 
     strcpyW(root, source_root);
     PathStripToRootW(root);
@@ -55,7 +56,13 @@ static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPCWSTR source_root)
         WARN("failed to get volume information for %s (%u)\n", debugstr_w(root), GetLastError());
         return FALSE;
     }
-    return !strcmpiW( mi->volume_label, volume_name );
+
+    len = strlenW( volume_name );
+    len2 = strlenW( mi->volume_label );
+    if (len2 > len) return FALSE;
+    p = volume_name + len - len2;
+
+    return !strcmpiW( mi->volume_label, p );
 }
 
 static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
@@ -202,28 +209,39 @@ static INT_PTR CDECL cabinet_open_stream( char *pszFile, int oflag, int pmode )
 {
     MSICABINETSTREAM *cab;
     IStream *stream;
-    WCHAR *encoded;
-    HRESULT hr;
 
-    cab = msi_get_cabinet_stream( package_disk.package, package_disk.id );
-    if (!cab)
+    if (!(cab = msi_get_cabinet_stream( package_disk.package, package_disk.id )))
     {
         WARN("failed to get cabinet stream\n");
         return -1;
     }
-    if (!cab->stream[0] || !(encoded = encode_streamname( FALSE, cab->stream + 1 )))
+    if (cab->storage == package_disk.package->db->storage)
     {
-        WARN("failed to encode stream name\n");
-        return -1;
+        UINT r = msi_get_stream( package_disk.package->db, cab->stream + 1, &stream );
+        if (r != ERROR_SUCCESS)
+        {
+            WARN("failed to get stream %u\n", r);
+            return -1;
+        }
     }
-    hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream );
-    if (FAILED(hr))
+    else /* patch storage */
     {
-        WARN("failed to open stream 0x%08x\n", hr);
+        HRESULT hr;
+        WCHAR *encoded;
+
+        if (!(encoded = encode_streamname( FALSE, cab->stream + 1 )))
+        {
+            WARN("failed to encode stream name\n");
+            return -1;
+        }
+        hr = IStorage_OpenStream( cab->storage, encoded, NULL, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stream );
         msi_free( encoded );
-        return -1;
+        if (FAILED(hr))
+        {
+            WARN("failed to open stream 0x%08x\n", hr);
+            return -1;
+        }
     }
-    msi_free( encoded );
     return (INT_PTR)stream;
 }
 
index 0a3e4aa..c7124de 100644 (file)
@@ -463,7 +463,7 @@ UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages,
         r = MSI_ApplyPatchW(patch, szProductCode, szPropertiesList);
         msi_free(patch);
 
-        if (r != ERROR_SUCCESS)
+        if (r != ERROR_SUCCESS || !*end)
             break;
 
         beg = ++end;
@@ -533,7 +533,7 @@ static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
 {
     MSISUMMARYINFO *si;
     MSIDATABASE *patch_db;
-    UINT r = ERROR_SUCCESS;
+    UINT r;
 
     r = MSI_OpenDatabaseW( patch, MSIDBOPEN_READONLY, &patch_db );
     if (r != ERROR_SUCCESS)
@@ -542,8 +542,8 @@ static UINT MSI_ApplicablePatchW( MSIPACKAGE *package, LPCWSTR patch )
         return r;
     }
 
-    si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
-    if (!si)
+    r = msi_get_suminfo( patch_db->storage, 0, &si );
+    if (r != ERROR_SUCCESS)
     {
         msiobj_release( &patch_db->hdr );
         return ERROR_FUNCTION_FAILED;
@@ -2024,7 +2024,7 @@ UINT WINAPI MsiEnumComponentCostsW( MSIHANDLE handle, LPCWSTR component, DWORD i
     GetWindowsDirectoryW( path, MAX_PATH );
     if (component && component[0])
     {
-        if (comp->assembly && !comp->assembly->application) *temp = comp->Cost;
+        if (msi_is_global_assembly( comp )) *temp = comp->Cost;
         if (!comp->Enabled || !comp->KeyPath)
         {
             *cost = 0;
@@ -3989,48 +3989,24 @@ extern VOID WINAPI MD5Init( MD5_CTX *);
 extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
 extern VOID WINAPI MD5Final( MD5_CTX *);
 
-/***********************************************************************
- * MsiGetFileHashW            [MSI.@]
- */
-UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
-                             PMSIFILEHASHINFO pHash )
+UINT msi_get_filehash( const WCHAR *path, MSIFILEHASHINFO *hash )
 {
     HANDLE handle, mapping;
     void *p;
     DWORD length;
     UINT r = ERROR_FUNCTION_FAILED;
 
-    TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
-
-    if (!szFilePath)
-        return ERROR_INVALID_PARAMETER;
-
-    if (!*szFilePath)
-        return ERROR_PATH_NOT_FOUND;
-
-    if (dwOptions)
-        return ERROR_INVALID_PARAMETER;
-    if (!pHash)
-        return ERROR_INVALID_PARAMETER;
-    if (pHash->dwFileHashInfoSize < sizeof *pHash)
-        return ERROR_INVALID_PARAMETER;
-
-    handle = CreateFileW( szFilePath, GENERIC_READ,
-                          FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
+    handle = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL );
     if (handle == INVALID_HANDLE_VALUE)
     {
         WARN("can't open file %u\n", GetLastError());
         return ERROR_FILE_NOT_FOUND;
     }
-    length = GetFileSize( handle, NULL );
-
-    if (length)
+    if ((length = GetFileSize( handle, NULL )))
     {
-        mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL );
-        if (mapping)
+        if ((mapping = CreateFileMappingW( handle, NULL, PAGE_READONLY, 0, 0, NULL )))
         {
-            p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length );
-            if (p)
+            if ((p = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, length )))
             {
                 MD5_CTX ctx;
 
@@ -4039,7 +4015,7 @@ UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
                 MD5Final( &ctx );
                 UnmapViewOfFile( p );
 
-                memcpy( pHash->dwData, ctx.digest, sizeof pHash->dwData );
+                memcpy( hash->dwData, ctx.digest, sizeof(hash->dwData) );
                 r = ERROR_SUCCESS;
             }
             CloseHandle( mapping );
@@ -4048,15 +4024,38 @@ UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
     else
     {
         /* Empty file -> set hash to 0 */
-        memset( pHash->dwData, 0, sizeof pHash->dwData );
+        memset( hash->dwData, 0, sizeof(hash->dwData) );
         r = ERROR_SUCCESS;
     }
 
     CloseHandle( handle );
-
     return r;
 }
 
+/***********************************************************************
+ * MsiGetFileHashW            [MSI.@]
+ */
+UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
+                             PMSIFILEHASHINFO pHash )
+{
+    TRACE("%s %08x %p\n", debugstr_w(szFilePath), dwOptions, pHash );
+
+    if (!szFilePath)
+        return ERROR_INVALID_PARAMETER;
+
+    if (!*szFilePath)
+        return ERROR_PATH_NOT_FOUND;
+
+    if (dwOptions)
+        return ERROR_INVALID_PARAMETER;
+    if (!pHash)
+        return ERROR_INVALID_PARAMETER;
+    if (pHash->dwFileHashInfoSize < sizeof *pHash)
+        return ERROR_INVALID_PARAMETER;
+
+    return msi_get_filehash( szFilePath, pHash );
+}
+
 /***********************************************************************
  * MsiGetFileHashA            [MSI.@]
  */
@@ -4178,7 +4177,7 @@ UINT WINAPI MsiProvideComponentA( LPCSTR product, LPCSTR feature, LPCSTR compone
 {
     WCHAR *productW = NULL, *componentW = NULL, *featureW = NULL, *bufW = NULL;
     UINT r = ERROR_OUTOFMEMORY;
-    DWORD lenW;
+    DWORD lenW = 0;
     int len;
 
     TRACE("%s, %s, %s, %x, %p, %p\n", debugstr_a(product), debugstr_a(component), debugstr_a(feature), mode, buf, buflen);
index a3f9df4..3dea486 100644 (file)
@@ -53,7 +53,7 @@
 #include <wine/unicode.h>
 
 static const BOOL is_64bit = sizeof(void *) > sizeof(int);
-BOOL is_wow64;
+BOOL is_wow64 DECLSPEC_HIDDEN;
 
 #define MSI_DATASIZEMASK 0x00ff
 #define MSITYPE_VALID    0x0100
@@ -114,6 +114,7 @@ typedef struct tagMSIDATABASE
     UINT bytes_per_strref;
     LPWSTR path;
     LPWSTR deletefile;
+    LPWSTR tempfolder;
     LPCWSTR mode;
     UINT media_transform_offset;
     UINT media_transform_disk_id;
@@ -206,6 +207,8 @@ typedef struct tagMSIPATCHINFO
     LPWSTR localfile;
     MSIPATCHSTATE state;
     BOOL delete_on_close;
+    BOOL registered;
+    UINT disk_id;
 } MSIPATCHINFO;
 
 typedef struct tagMSIBINARY
@@ -593,12 +596,6 @@ typedef struct tagMSIFILE
     UINT disk_id;
 } MSIFILE;
 
-typedef struct tagMSITEMPFILE
-{
-    struct list entry;
-    LPWSTR Path;
-} MSITEMPFILE;
-
 typedef struct tagMSIFILEPATCH
 {
     struct list entry;
@@ -606,7 +603,9 @@ typedef struct tagMSIFILEPATCH
     INT Sequence;
     INT PatchSize;
     INT Attributes;
-    BOOL IsApplied;
+    BOOL extracted;
+    UINT disk_id;
+    WCHAR *path;
 } MSIFILEPATCH;
 
 typedef struct tagMSIAPPID
@@ -949,6 +948,7 @@ extern int msi_compare_file_versions(VS_FIXEDFILEINFO *, const WCHAR *) DECLSPEC
 extern int msi_compare_font_versions(const WCHAR *, const WCHAR *) DECLSPEC_HIDDEN;
 extern DWORD msi_get_disk_file_size(LPCWSTR) DECLSPEC_HIDDEN;
 extern BOOL msi_file_hash_matches(MSIFILE *) DECLSPEC_HIDDEN;
+extern UINT msi_get_filehash(const WCHAR *, MSIFILEHASHINFO *) DECLSPEC_HIDDEN;
 
 extern LONG msi_reg_set_val_str( HKEY hkey, LPCWSTR name, LPCWSTR value ) DECLSPEC_HIDDEN;
 extern LONG msi_reg_set_val_multi_str( HKEY hkey, LPCWSTR name, LPCWSTR value ) DECLSPEC_HIDDEN;
@@ -962,12 +962,14 @@ extern void msi_dialog_unregister_class( void ) DECLSPEC_HIDDEN;
 extern UINT msi_spawn_error_dialog( MSIPACKAGE*, LPWSTR, LPWSTR ) DECLSPEC_HIDDEN;
 
 /* summary information */
-extern MSISUMMARYINFO *MSI_GetSummaryInformationW( IStorage *stg, UINT uiUpdateCount ) DECLSPEC_HIDDEN;
+extern UINT msi_get_suminfo( IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **si ) DECLSPEC_HIDDEN;
+extern UINT msi_get_db_suminfo( MSIDATABASE *db, UINT uiUpdateCount, MSISUMMARYINFO **si ) DECLSPEC_HIDDEN;
 extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) DECLSPEC_HIDDEN;
 extern INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty ) DECLSPEC_HIDDEN;
 extern LPWSTR msi_get_suminfo_product( IStorage *stg ) DECLSPEC_HIDDEN;
 extern UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns ) DECLSPEC_HIDDEN;
 extern enum platform parse_platform( const WCHAR *str ) DECLSPEC_HIDDEN;
+extern UINT msi_load_suminfo_properties( MSIPACKAGE *package ) DECLSPEC_HIDDEN;
 
 /* undocumented functions */
 UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD );
@@ -1033,7 +1035,7 @@ extern MSICOMPONENT *msi_get_loaded_component(MSIPACKAGE *package, const WCHAR *
 extern MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE *package, const WCHAR *Feature) DECLSPEC_HIDDEN;
 extern MSIFILE *msi_get_loaded_file(MSIPACKAGE *package, const WCHAR *file) DECLSPEC_HIDDEN;
 extern MSIFOLDER *msi_get_loaded_folder(MSIPACKAGE *package, const WCHAR *dir) DECLSPEC_HIDDEN;
-extern int msi_track_tempfile(MSIPACKAGE *package, const WCHAR *path) DECLSPEC_HIDDEN;
+extern WCHAR *msi_create_temp_file(MSIDATABASE *db) DECLSPEC_HIDDEN;
 extern void msi_free_action_script(MSIPACKAGE *package, UINT script) DECLSPEC_HIDDEN;
 extern WCHAR *msi_build_icon_path(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
 extern WCHAR *msi_build_directory_name(DWORD , ...) DECLSPEC_HIDDEN;
@@ -1053,6 +1055,9 @@ extern UINT msi_install_assembly(MSIPACKAGE *, MSICOMPONENT *) DECLSPEC_HIDDEN;
 extern UINT msi_uninstall_assembly(MSIPACKAGE *, MSICOMPONENT *) DECLSPEC_HIDDEN;
 extern BOOL msi_init_assembly_caches(MSIPACKAGE *) DECLSPEC_HIDDEN;
 extern void msi_destroy_assembly_caches(MSIPACKAGE *) DECLSPEC_HIDDEN;
+extern BOOL msi_is_global_assembly(MSICOMPONENT *) DECLSPEC_HIDDEN;
+extern IAssemblyEnum *msi_create_assembly_enum(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
+extern WCHAR *msi_get_assembly_path(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
 extern WCHAR *msi_font_version_from_file(const WCHAR *) DECLSPEC_HIDDEN;
 extern WCHAR **msi_split_string(const WCHAR *, WCHAR) DECLSPEC_HIDDEN;
 extern UINT msi_set_original_database_property(MSIDATABASE *, const WCHAR *) DECLSPEC_HIDDEN;
index 69698b7..37afba8 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
-static void remove_tracked_tempfiles( MSIPACKAGE *package )
-{
-    struct list *item, *cursor;
-
-    LIST_FOR_EACH_SAFE( item, cursor, &package->tempfiles )
-    {
-        MSITEMPFILE *temp = LIST_ENTRY( item, MSITEMPFILE, entry );
-
-        list_remove( &temp->entry );
-        TRACE("deleting temp file %s\n", debugstr_w( temp->Path ));
-        DeleteFileW( temp->Path );
-        msi_free( temp->Path );
-        msi_free( temp );
-    }
-}
-
 static void free_feature( MSIFEATURE *feature )
 {
     struct list *item, *cursor;
@@ -145,6 +129,22 @@ static void free_package_structures( MSIPACKAGE *package )
         free_folder( folder );
     }
 
+    LIST_FOR_EACH_SAFE( item, cursor, &package->files )
+    {
+        MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );
+
+        list_remove( &file->entry );
+        msi_free( file->File );
+        msi_free( file->FileName );
+        msi_free( file->ShortName );
+        msi_free( file->LongName );
+        msi_free( file->Version );
+        msi_free( file->Language );
+        if (msi_is_global_assembly( file->Component )) DeleteFileW( file->TargetPath );
+        msi_free( file->TargetPath );
+        msi_free( file );
+    }
+
     LIST_FOR_EACH_SAFE( item, cursor, &package->components )
     {
         MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry );
@@ -160,19 +160,13 @@ static void free_package_structures( MSIPACKAGE *package )
         msi_free( comp );
     }
 
-    LIST_FOR_EACH_SAFE( item, cursor, &package->files )
+    LIST_FOR_EACH_SAFE( item, cursor, &package->filepatches )
     {
-        MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );
+        MSIFILEPATCH *patch = LIST_ENTRY( item, MSIFILEPATCH, entry );
 
-        list_remove( &file->entry );
-        msi_free( file->File );
-        msi_free( file->FileName );
-        msi_free( file->ShortName );
-        msi_free( file->LongName );
-        msi_free( file->Version );
-        msi_free( file->Language );
-        msi_free( file->TargetPath );
-        msi_free( file );
+        list_remove( &patch->entry );
+        msi_free( patch->path );
+        msi_free( patch );
     }
 
     /* clean up extension, progid, class and verb structures */
@@ -313,8 +307,6 @@ static void free_package_structures( MSIPACKAGE *package )
     msi_free( package->LastAction );
     msi_free( package->langids );
 
-    remove_tracked_tempfiles(package);
-
     /* cleanup control event subscriptions */
     msi_event_cleanup_all_subscriptions( package );
 }
@@ -1002,74 +994,6 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     msi_set_property( package->db, szBrowseProperty, szInstallDir, -1 );
 }
 
-static UINT msi_load_summary_properties( MSIPACKAGE *package )
-{
-    UINT rc;
-    MSIHANDLE suminfo;
-    MSIHANDLE hdb = alloc_msihandle( &package->db->hdr );
-    INT count;
-    DWORD len;
-    LPWSTR package_code;
-    static const WCHAR szPackageCode[] = {
-        'P','a','c','k','a','g','e','C','o','d','e',0};
-
-    if (!hdb) {
-        ERR("Unable to allocate handle\n");
-        return ERROR_OUTOFMEMORY;
-    }
-
-    rc = MsiGetSummaryInformationW( hdb, NULL, 0, &suminfo );
-    MsiCloseHandle(hdb);
-    if (rc != ERROR_SUCCESS)
-    {
-        ERR("Unable to open Summary Information\n");
-        return rc;
-    }
-
-    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_PAGECOUNT, NULL,
-                                     &count, NULL, NULL, NULL );
-    if (rc != ERROR_SUCCESS)
-    {
-        WARN("Unable to query page count: %d\n", rc);
-        goto done;
-    }
-
-    /* load package code property */
-    len = 0;
-    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
-                                     NULL, NULL, NULL, &len );
-    if (rc != ERROR_MORE_DATA)
-    {
-        WARN("Unable to query revision number: %d\n", rc);
-        rc = ERROR_FUNCTION_FAILED;
-        goto done;
-    }
-
-    len++;
-    package_code = msi_alloc( len * sizeof(WCHAR) );
-    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
-                                     NULL, NULL, package_code, &len );
-    if (rc != ERROR_SUCCESS)
-    {
-        WARN("Unable to query rev number: %d\n", rc);
-        msi_free( package_code );
-        goto done;
-    }
-
-    msi_set_property( package->db, szPackageCode, package_code, len );
-    msi_free( package_code );
-
-    /* load package attributes */
-    count = 0;
-    MsiSummaryInfoGetPropertyW( suminfo, PID_WORDCOUNT, NULL,
-                                &count, NULL, NULL, NULL );
-    package->WordCount = count;
-
-done:
-    MsiCloseHandle(suminfo);
-    return rc;
-}
-
 static MSIPACKAGE *msi_alloc_package( void )
 {
     MSIPACKAGE *package;
@@ -1162,7 +1086,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
         len = sprintfW( uilevel, fmtW, gUILevel & INSTALLUILEVEL_MASK );
         msi_set_property( package->db, szUILevel, uilevel, len );
 
-        r = msi_load_summary_properties( package );
+        r = msi_load_suminfo_properties( package );
         if (r != ERROR_SUCCESS)
         {
             msiobj_release( &package->hdr );
@@ -1255,7 +1179,7 @@ enum platform parse_platform( const WCHAR *str )
     return PLATFORM_UNKNOWN;
 }
 
-static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package )
+static UINT parse_suminfo( MSISUMMARYINFO *si, MSIPACKAGE *package )
 {
     WCHAR *template, *p, *q, *platform;
     DWORD i, count;
@@ -1363,22 +1287,6 @@ static UINT validate_package( MSIPACKAGE *package )
     return ERROR_INSTALL_LANGUAGE_UNSUPPORTED;
 }
 
-int msi_track_tempfile( MSIPACKAGE *package, const WCHAR *path )
-{
-    MSITEMPFILE *temp;
-
-    TRACE("%s\n", debugstr_w(path));
-
-    LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry )
-    {
-        if (!strcmpW( path, temp->Path )) return 0;
-    }
-    if (!(temp = msi_alloc_zero( sizeof (MSITEMPFILE) ))) return -1;
-    list_add_head( &package->tempfiles, &temp->entry );
-    temp->Path = strdupW( path );
-    return 0;
-}
-
 static WCHAR *get_product_code( MSIDATABASE *db )
 {
     static const WCHAR query[] = {
@@ -1458,11 +1366,17 @@ static WCHAR *get_package_code( MSIDATABASE *db )
 {
     WCHAR *ret;
     MSISUMMARYINFO *si;
+    UINT r;
 
-    if (!(si = MSI_GetSummaryInformationW( db->storage, 0 )))
+    r = msi_get_suminfo( db->storage, 0, &si );
+    if (r != ERROR_SUCCESS)
     {
-        WARN("failed to load summary info\n");
-        return NULL;
+        r = msi_get_db_suminfo( db, 0, &si );
+        if (r != ERROR_SUCCESS)
+        {
+            WARN("failed to load summary info %u\n", r);
+            return NULL;
+        }
     }
     ret = msi_suminfo_dup_string( si, PID_REVNUMBER );
     msiobj_release( &si->hdr );
@@ -1608,14 +1522,18 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     package->localfile = strdupW( localfile );
     package->delete_on_close = delete_on_close;
 
-    si = MSI_GetSummaryInformationW( db->storage, 0 );
-    if (!si)
+    r = msi_get_suminfo( db->storage, 0, &si );
+    if (r != ERROR_SUCCESS)
     {
-        WARN("failed to load summary info\n");
-        msiobj_release( &package->hdr );
-        return ERROR_INSTALL_PACKAGE_INVALID;
+        r = msi_get_db_suminfo( db, 0, &si );
+        if (r != ERROR_SUCCESS)
+        {
+            WARN("failed to load summary info\n");
+            msiobj_release( &package->hdr );
+            return ERROR_INSTALL_PACKAGE_INVALID;
+        }
     }
-    r = msi_parse_summary( si, package );
+    r = parse_suminfo( si, package );
     msiobj_release( &si->hdr );
     if (r != ERROR_SUCCESS)
     {
@@ -2633,7 +2551,7 @@ HRESULT create_msi_remote_package( IUnknown *pOuter, LPVOID *ppObj )
     This->package = 0;
     This->refs = 1;
 
-    *ppObj = This;
+    *ppObj = &This->IWineMsiRemotePackage_iface;
 
     return S_OK;
 }
index 6025c97..d18ee53 100644 (file)
@@ -115,15 +115,16 @@ static UINT check_transform_applicable( MSIPACKAGE *package, IStorage *transform
         MSITRANSFORM_VALIDATE_PRODUCT  | MSITRANSFORM_VALIDATE_LANGUAGE |
         MSITRANSFORM_VALIDATE_PLATFORM | MSITRANSFORM_VALIDATE_MAJORVERSION |
         MSITRANSFORM_VALIDATE_MINORVERSION | MSITRANSFORM_VALIDATE_UPGRADECODE;
-    MSISUMMARYINFO *si = MSI_GetSummaryInformationW( transform, 0 );
-    UINT valid_flags = 0, wanted_flags = 0;
+    MSISUMMARYINFO *si;
+    UINT r, valid_flags = 0, wanted_flags = 0;
     WCHAR *template, *product, *p;
     struct transform_desc *desc;
 
-    if (!si)
+    r = msi_get_suminfo( transform, 0, &si );
+    if (r != ERROR_SUCCESS)
     {
         WARN("no summary information!\n");
-        return ERROR_FUNCTION_FAILED;
+        return r;
     }
     wanted_flags = msi_suminfo_get_int32( si, PID_CHARCOUNT );
     wanted_flags &= 0xffff; /* mask off error condition flags */
@@ -402,6 +403,7 @@ struct patch_offset
 struct patch_offset_list
 {
     struct list files;
+    struct list patches;
     UINT count, min, max;
     UINT offset_to_apply;
 };
@@ -410,6 +412,7 @@ static struct patch_offset_list *patch_offset_list_create( void )
 {
     struct patch_offset_list *pos = msi_alloc( sizeof(struct patch_offset_list) );
     list_init( &pos->files );
+    list_init( &pos->patches );
     pos->count = pos->max = 0;
     pos->min = 999999;
     return pos;
@@ -424,10 +427,15 @@ static void patch_offset_list_free( struct patch_offset_list *pos )
         msi_free( po->name );
         msi_free( po );
     }
+    LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->patches, struct patch_offset, entry )
+    {
+        msi_free( po->name );
+        msi_free( po );
+    }
     msi_free( pos );
 }
 
-static void patch_offset_get_patches( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
+static void patch_offset_get_filepatches( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
 {
     static const WCHAR query[] = {
         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','a','t','c','h',' ',
@@ -451,12 +459,15 @@ static void patch_offset_get_patches( MSIDATABASE *db, UINT last_sequence, struc
 
     while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
     {
-        UINT sequence = MSI_RecordGetInteger( rec, 2 );
+        struct patch_offset *po = msi_alloc( sizeof(struct patch_offset) );
 
-        /* FIXME: we only use the max/min sequence numbers for now */
-        pos->min = min( pos->min, sequence );
-        pos->max = max( pos->max, sequence );
+        po->name     = msi_dup_record_field( rec, 1 );
+        po->sequence = MSI_RecordGetInteger( rec, 2 );
+        pos->min = min( pos->min, po->sequence );
+        pos->max = max( pos->max, po->sequence );
+        list_add_tail( &pos->patches, &po->entry );
         pos->count++;
+
         msiobj_release( &rec->hdr );
     }
     msiobj_release( &view->hdr );
@@ -503,58 +514,137 @@ static void patch_offset_get_files( MSIDATABASE *db, UINT last_sequence, struct
     msiobj_release( &view->hdr );
 }
 
-static UINT patch_offset_modify_db( MSIDATABASE *db, struct patch_offset_list *pos )
+static UINT patch_update_file_sequence( MSIDATABASE *db, const struct patch_offset_list *pos,
+                                        MSIQUERY *view, MSIRECORD *rec )
 {
-    static const WCHAR query[] = {
-        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','F','i','l','e',' ',
-        'W','H','E','R','E',' ','S','e','q','u','e','n','c','e',' ','>','=',' ','?',' ',
-        'A','N','D',' ','S','e','q','u','e','n','c','e',' ','<','=',' ','?',' ',
-        'O','R','D','E','R',' ','B','Y',' ','S','e','q','u','e','n','c','e',0};
     struct patch_offset *po;
+    const WCHAR *file = MSI_RecordGetString( rec, 1 );
+    UINT r = ERROR_SUCCESS, seq = MSI_RecordGetInteger( rec, 8 );
+
+    LIST_FOR_EACH_ENTRY( po, &pos->files, struct patch_offset, entry )
+    {
+        if (!strcmpiW( file, po->name ))
+        {
+            MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
+            r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
+            if (r != ERROR_SUCCESS)
+                ERR("Failed to update offset for file %s (%u)\n", debugstr_w(file), r);
+            break;
+        }
+    }
+    return r;
+}
+
+static UINT patch_update_filepatch_sequence( MSIDATABASE *db, const struct patch_offset_list *pos,
+                                             MSIQUERY *view, MSIRECORD *rec )
+{
+    static const WCHAR delete_query[] = {
+        'D','E','L','E','T','E',' ','F','R','O','M',' ','`','P','a','t','c','h','`',' ',
+        'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','?',' ',
+        'A','N','D',' ','`','S','e','q','u','e','n','c','e','`',' ','=',' ','?',0};
+    static const WCHAR insert_query[] = {
+        'I','N','S','E','R','T',' ','I','N','T','O',' ','`','P','a','t','c','h','`',' ',
+        '(','`','F','i','l','e','_','`',',','`','S','e','q','u','e','n','c','e','`',',',
+        '`','P','a','t','c','h','S','i','z','e','`',',','`','A','t','t','r','i','b','u','t','e','s','`',',',
+        '`','H','e','a','d','e','r','`',',','`','S','t','r','e','a','m','R','e','f','_','`',')',' ',
+        'V','A','L','U','E','S',' ','(','?',',','?',',','?',',','?',',','?',',','?',')',0};
+    struct patch_offset *po;
+    const WCHAR *file = MSI_RecordGetString( rec, 1 );
+    UINT r = ERROR_SUCCESS, seq = MSI_RecordGetInteger( rec, 2 );
+
+    LIST_FOR_EACH_ENTRY( po, &pos->patches, struct patch_offset, entry )
+    {
+        if (seq == po->sequence && !strcmpiW( file, po->name ))
+        {
+            MSIQUERY *delete_view, *insert_view;
+            MSIRECORD *rec2;
+
+            r = MSI_DatabaseOpenViewW( db, delete_query, &delete_view );
+            if (r != ERROR_SUCCESS) return r;
+
+            rec2 = MSI_CreateRecord( 2 );
+            MSI_RecordSetStringW( rec2, 1, po->name );
+            MSI_RecordSetInteger( rec2, 2, po->sequence );
+            r = MSI_ViewExecute( delete_view, rec2 );
+            msiobj_release( &delete_view->hdr );
+            msiobj_release( &rec2->hdr );
+            if (r != ERROR_SUCCESS) return r;
+
+            r = MSI_DatabaseOpenViewW( db, insert_query, &insert_view );
+            if (r != ERROR_SUCCESS) return r;
+
+            MSI_RecordSetInteger( rec, 2, po->sequence + pos->offset_to_apply );
+
+            r = MSI_ViewExecute( insert_view, rec );
+            msiobj_release( &insert_view->hdr );
+            if (r != ERROR_SUCCESS)
+                ERR("Failed to update offset for filepatch %s (%u)\n", debugstr_w(file), r);
+            break;
+        }
+    }
+    return r;
+}
+
+static UINT patch_offset_modify_db( MSIDATABASE *db, struct patch_offset_list *pos )
+{
+    static const WCHAR file_query[] = {
+        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','F','i','l','e','`',' ',
+        'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>','=',' ','?',' ',
+        'A','N','D',' ','`','S','e','q','u','e','n','c','e','`',' ','<','=',' ','?',' ',
+        'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
+    static const WCHAR patch_query[] = {
+        'S','E','L','E','C','T',' ','*','F','R','O','M',' ','`','P','a','t','c','h','`',' ',
+        'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>','=',' ','?',' ',
+        'A','N','D',' ','`','S','e','q','u','e','n','c','e','`',' ','<','=',' ','?',' ',
+        'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
     MSIRECORD *rec;
     MSIQUERY *view;
-    UINT r;
+    UINT r, min = pos->min, max = pos->max, r_fetch;
 
-    r = MSI_DatabaseOpenViewW( db, query, &view );
+    r = MSI_DatabaseOpenViewW( db, file_query, &view );
     if (r != ERROR_SUCCESS)
         return ERROR_SUCCESS;
 
     rec = MSI_CreateRecord( 2 );
-    MSI_RecordSetInteger( rec, 1, pos->min );
-    MSI_RecordSetInteger( rec, 2, pos->max );
+    MSI_RecordSetInteger( rec, 1, min );
+    MSI_RecordSetInteger( rec, 2, max );
 
     r = MSI_ViewExecute( view, rec );
     msiobj_release( &rec->hdr );
     if (r != ERROR_SUCCESS)
         goto done;
 
-    LIST_FOR_EACH_ENTRY( po, &pos->files, struct patch_offset, entry )
+    while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
     {
-        UINT r_fetch;
-        while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
-        {
-            const WCHAR *file = MSI_RecordGetString( rec, 1 );
-            UINT seq;
+        r = patch_update_file_sequence( db, pos, view, rec );
+        msiobj_release( &rec->hdr );
+        if (r != ERROR_SUCCESS) goto done;
+    }
+    msiobj_release( &view->hdr );
 
-            if (!strcmpiW( file, po->name ))
-            {
-                /* update record */
-                seq = MSI_RecordGetInteger( rec, 8 );
-                MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
-                r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
-                if (r != ERROR_SUCCESS)
-                    ERR("Failed to update offset for file %s\n", debugstr_w(file));
-                msiobj_release( &rec->hdr );
-                break;
-            }
-            msiobj_release( &rec->hdr );
-        }
-        if (r_fetch != ERROR_SUCCESS) break;
+    r = MSI_DatabaseOpenViewW( db, patch_query, &view );
+    if (r != ERROR_SUCCESS)
+        return ERROR_SUCCESS;
+
+    rec = MSI_CreateRecord( 2 );
+    MSI_RecordSetInteger( rec, 1, min );
+    MSI_RecordSetInteger( rec, 2, max );
+
+    r = MSI_ViewExecute( view, rec );
+    msiobj_release( &rec->hdr );
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
+    {
+        r = patch_update_filepatch_sequence( db, pos, view, rec );
+        msiobj_release( &rec->hdr );
+        if (r != ERROR_SUCCESS) goto done;
     }
 
 done:
     msiobj_release( &view->hdr );
-    return ERROR_SUCCESS;
+    return r;
 }
 
 static const WCHAR patch_media_query[] = {
@@ -574,7 +664,7 @@ struct patch_media
     WCHAR  *source;
 };
 
-static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
+static UINT patch_add_media( MSIPACKAGE *package, IStorage *storage, MSIPATCHINFO *patch )
 {
     static const WCHAR delete_query[] = {
         'D','E','L','E','T','E',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ',
@@ -611,7 +701,10 @@ static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
             msiobj_release( &rec->hdr );
             continue;
         }
-        if (!(media = msi_alloc( sizeof( *media )))) goto done;
+        if (!(media = msi_alloc( sizeof( *media )))) {
+            msiobj_release( &rec->hdr );
+            goto done;
+       }
         media->disk_id = disk_id;
         media->last_sequence = MSI_RecordGetInteger( rec, 2 );
         media->prompt  = msi_dup_record_field( rec, 3 );
@@ -661,9 +754,13 @@ static UINT add_patch_media( MSIPACKAGE *package, IStorage *patch )
         msiobj_release( &rec->hdr );
         if (r != ERROR_SUCCESS) goto done;
 
-        r = msi_add_cabinet_stream( package, disk_id, patch, media->cabinet );
-        if (r != ERROR_SUCCESS) WARN("failed to add cabinet stream %u\n", r);
-        package->db->media_transform_disk_id++;
+        r = msi_add_cabinet_stream( package, disk_id, storage, media->cabinet );
+        if (r != ERROR_SUCCESS) ERR("failed to add cabinet stream %u\n", r);
+        else
+        {
+            patch->disk_id = disk_id;
+            package->db->media_transform_disk_id++;
+        }
     }
 
 done:
@@ -680,7 +777,7 @@ done:
     return r;
 }
 
-static UINT set_patch_offsets( MSIDATABASE *db )
+static UINT patch_set_offsets( MSIDATABASE *db, MSIPATCHINFO *patch )
 {
     MSIQUERY *view;
     MSIRECORD *rec;
@@ -696,7 +793,7 @@ static UINT set_patch_offsets( MSIDATABASE *db )
 
     while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
     {
-        UINT last_sequence = MSI_RecordGetInteger( rec, 2 );
+        UINT offset, last_sequence = MSI_RecordGetInteger( rec, 2 );
         struct patch_offset_list *pos;
 
         /* FIXME: set/check Source field instead? */
@@ -707,23 +804,26 @@ static UINT set_patch_offsets( MSIDATABASE *db )
         }
         pos = patch_offset_list_create();
         patch_offset_get_files( db, last_sequence, pos );
-        patch_offset_get_patches( db, last_sequence, pos );
-        {
-            UINT offset = db->media_transform_offset - pos->min;
-            last_sequence = offset + pos->max;
+        patch_offset_get_filepatches( db, last_sequence, pos );
 
-            /* FIXME: this is for the patch table, which is not yet properly transformed */
-            last_sequence += pos->min;
-            pos->offset_to_apply = offset;
-            if (pos->count)
-                patch_offset_modify_db( db, pos );
+        offset = db->media_transform_offset - pos->min;
+        last_sequence = offset + pos->max;
 
-            MSI_RecordSetInteger( rec, 2, last_sequence );
-            r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
+        last_sequence += pos->min;
+        pos->offset_to_apply = offset;
+        if (pos->count)
+        {
+            r = patch_offset_modify_db( db, pos );
             if (r != ERROR_SUCCESS)
-                ERR("Failed to update Media table entry, expect breakage (%u)\n", r);
-            db->media_transform_offset = last_sequence + 1;
+                ERR("Failed to set offsets, expect breakage (%u)\n", r);
         }
+        MSI_RecordSetInteger( rec, 2, last_sequence );
+        r = MSI_ViewModify( view, MSIMODIFY_UPDATE, rec );
+        if (r != ERROR_SUCCESS)
+            ERR("Failed to update Media table entry, expect breakage (%u)\n", r);
+
+        db->media_transform_offset = last_sequence + 1;
+
         patch_offset_list_free( pos );
         msiobj_release( &rec->hdr );
     }
@@ -745,15 +845,18 @@ static UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIP
         r = apply_substorage_transform( package, patch_db, substorage[i] );
         if (r == ERROR_SUCCESS)
         {
-            add_patch_media( package, patch_db->storage );
-            set_patch_offsets( package->db );
+            r = patch_set_offsets( package->db, patch );
+            if (r == ERROR_SUCCESS)
+                r = patch_add_media( package, patch_db->storage, patch );
         }
     }
     msi_free( substorage );
     if (r != ERROR_SUCCESS)
         return r;
 
-    patch_set_media_source_prop( package );
+    r = patch_set_media_source_prop( package );
+    if (r != ERROR_SUCCESS)
+        return r;
 
     patch->state = MSIPATCHSTATE_APPLIED;
     list_add_tail( &package->patches, &patch->entry );
@@ -777,9 +880,9 @@ static UINT msi_apply_patch_package( MSIPACKAGE *package, const WCHAR *file )
     WCHAR localfile[MAX_PATH];
     MSISUMMARYINFO *si;
     MSIPATCHINFO *patch = NULL;
-    UINT r = ERROR_SUCCESS;
+    UINT r;
 
-    TRACE("%p %s\n", package, debugstr_w(file));
+    TRACE("%p, %s\n", package, debugstr_w(file));
 
     r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
     if (r != ERROR_SUCCESS)
@@ -787,10 +890,11 @@ static UINT msi_apply_patch_package( MSIPACKAGE *package, const WCHAR *file )
         ERR("failed to open patch collection %s\n", debugstr_w( file ) );
         return r;
     }
-    if (!(si = MSI_GetSummaryInformationW( patch_db->storage, 0 )))
+    r = msi_get_suminfo( patch_db->storage, 0, &si );
+    if (r != ERROR_SUCCESS)
     {
         msiobj_release( &patch_db->hdr );
-        return ERROR_FUNCTION_FAILED;
+        return r;
     }
     r = msi_check_patch_applicable( package, si );
     if (r != ERROR_SUCCESS)
@@ -808,6 +912,7 @@ static UINT msi_apply_patch_package( MSIPACKAGE *package, const WCHAR *file )
         goto done;
 
     r = ERROR_OUTOFMEMORY;
+    patch->registered = FALSE;
     if (!(patch->filename = strdupW( file ))) goto done;
     if (!(patch->localfile = strdupW( localfile ))) goto done;
 
@@ -894,6 +999,8 @@ UINT msi_apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code )
     MSIPATCHINFO *patch_info;
     MSISUMMARYINFO *si;
 
+    TRACE("%p, %s\n", package, debugstr_w(patch_code));
+
     len = sizeof(patch_file) / sizeof(WCHAR);
     r = MsiGetPatchInfoExW( patch_code, package->ProductCode, NULL, package->Context,
                             INSTALLPROPERTY_LOCALPACKAGEW, patch_file, &len );
@@ -908,11 +1015,11 @@ UINT msi_apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code )
         ERR("failed to open patch database %s\n", debugstr_w( patch_file ));
         return r;
     }
-    si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
-    if (!si)
+    r = msi_get_suminfo( patch_db->storage, 0, &si );
+    if (r != ERROR_SUCCESS)
     {
         msiobj_release( &patch_db->hdr );
-        return ERROR_FUNCTION_FAILED;
+        return r;
     }
     r = msi_parse_patch_summary( si, &patch_info );
     msiobj_release( &si->hdr );
@@ -922,6 +1029,7 @@ UINT msi_apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code )
         msiobj_release( &patch_db->hdr );
         return r;
     }
+    patch_info->registered = TRUE;
     patch_info->localfile = strdupW( patch_file );
     if (!patch_info->localfile)
     {
index ecfcde4..adb5a86 100644 (file)
@@ -241,13 +241,6 @@ UINT WINAPI MsiSourceListEnumMediaDisksW(LPCWSTR szProductCodeOrPatchCode,
         return ERROR_NO_MORE_ITEMS;
     }
 
-    if (!pcchVolumeLabel && !pcchDiskPrompt)
-    {
-        r = RegEnumValueW(media, dwIndex, NULL, NULL, NULL,
-                          &type, NULL, NULL);
-        goto done;
-    }
-
     res = RegQueryInfoKeyW(media, NULL, NULL, NULL, NULL, NULL,
                            NULL, &numvals, &valuesz, &datasz, NULL, NULL);
     if (res != ERROR_SUCCESS)
index bca1c01..642093e 100644 (file)
@@ -411,23 +411,22 @@ static MSISTREAM *find_stream( MSIDATABASE *db, const WCHAR *name )
 
 static UINT append_stream( MSIDATABASE *db, const WCHAR *name, IStream *stream )
 {
-    WCHAR decoded[MAX_STREAM_NAME_LEN + 1];
     UINT i = db->num_streams;
 
     if (!streams_resize_table( db, db->num_streams + 1 ))
         return ERROR_OUTOFMEMORY;
 
-    decode_streamname( name, decoded );
-    db->streams[i].str_index = msi_add_string( db->strings, decoded, -1, StringNonPersistent );
+    db->streams[i].str_index = msi_add_string( db->strings, name, -1, StringNonPersistent );
     db->streams[i].stream = stream;
     db->num_streams++;
 
-    TRACE("added %s\n", debugstr_w( decoded ));
+    TRACE("added %s\n", debugstr_w( name ));
     return ERROR_SUCCESS;
 }
 
 static UINT load_streams( MSIDATABASE *db )
 {
+    WCHAR decoded[MAX_STREAM_NAME_LEN + 1];
     IEnumSTATSTG *stgenum;
     STATSTG stat;
     HRESULT hr;
@@ -446,25 +445,29 @@ static UINT load_streams( MSIDATABASE *db )
             break;
 
         /* table streams are not in the _Streams table */
-        if (stat.type != STGTY_STREAM || *stat.pwcsName == 0x4840 ||
-            find_stream( db, stat.pwcsName ))
+        if (stat.type != STGTY_STREAM || *stat.pwcsName == 0x4840)
+        {
+            CoTaskMemFree( stat.pwcsName );
+            continue;
+        }
+        decode_streamname( stat.pwcsName, decoded );
+        if (find_stream( db, decoded ))
         {
             CoTaskMemFree( stat.pwcsName );
             continue;
         }
-        TRACE("found new stream %s\n", debugstr_w( stat.pwcsName ));
+        TRACE("found new stream %s\n", debugstr_w( decoded ));
 
         hr = open_stream( db, stat.pwcsName, &stream );
+        CoTaskMemFree( stat.pwcsName );
         if (FAILED( hr ))
         {
             ERR("unable to open stream %08x\n", hr);
-            CoTaskMemFree( stat.pwcsName );
             r = ERROR_FUNCTION_FAILED;
             break;
         }
 
-        r = append_stream( db, stat.pwcsName, stream );
-        CoTaskMemFree( stat.pwcsName );
+        r = append_stream( db, decoded, stream );
         if (r != ERROR_SUCCESS)
             break;
     }
@@ -596,30 +599,29 @@ UINT msi_commit_streams( MSIDATABASE *db )
         name = msi_string_lookup( db->strings, db->streams[i].str_index, NULL );
         if (!(encname = encode_streamname( FALSE, name ))) return ERROR_OUTOFMEMORY;
 
-        hr = open_stream( db, encname, &stream );
-        if (FAILED( hr )) /* new stream */
+        hr = IStorage_CreateStream( db->storage, encname, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stream );
+        if (SUCCEEDED( hr ))
         {
-            hr = IStorage_CreateStream( db->storage, encname, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stream );
+            hr = write_stream( stream, db->streams[i].stream );
             if (FAILED( hr ))
             {
-                ERR("failed to create stream %s (hr = %08x)\n", debugstr_w(encname), hr);
+                ERR("failed to write stream %s (hr = %08x)\n", debugstr_w(encname), hr);
                 msi_free( encname );
+                IStream_Release( stream );
                 return ERROR_FUNCTION_FAILED;
             }
-            hr = write_stream( stream, db->streams[i].stream );
+            hr = IStream_Commit( stream, 0 );
+            IStream_Release( stream );
             if (FAILED( hr ))
             {
-                ERR("failed to write stream %s (hr = %08x)\n", debugstr_w(encname), hr);
+                ERR("failed to commit stream %s (hr = %08x)\n", debugstr_w(encname), hr);
                 msi_free( encname );
-                IStream_Release( stream );
                 return ERROR_FUNCTION_FAILED;
             }
         }
-        hr = IStream_Commit( stream, 0 );
-        IStream_Release( stream );
-        if (FAILED( hr ))
+        else if (hr != STG_E_FILEALREADYEXISTS)
         {
-            WARN("failed to commit stream %s (hr = %08x)\n", debugstr_w(encname), hr);
+            ERR("failed to create stream %s (hr = %08x)\n", debugstr_w(encname), hr);
             msi_free( encname );
             return ERROR_FUNCTION_FAILED;
         }
index 5d23ab6..f4ded7f 100644 (file)
@@ -219,7 +219,6 @@ static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz
 
 static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
 {
-    UINT ret = ERROR_FUNCTION_FAILED;
     PROPERTYSETHEADER set_hdr;
     FORMATIDOFFSET format_hdr;
     PROPERTYSECTIONHEADER section_hdr;
@@ -234,44 +233,44 @@ static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
     sz = sizeof set_hdr;
     r = IStream_Read( stm, &set_hdr, sz, &count );
     if( FAILED(r) || count != sz )
-        return ret;
+        return ERROR_FUNCTION_FAILED;
 
     if( set_hdr.wByteOrder != 0xfffe )
     {
         ERR("property set not big-endian %04X\n", set_hdr.wByteOrder);
-        return ret;
+        return ERROR_FUNCTION_FAILED;
     }
 
     sz = sizeof format_hdr;
     r = IStream_Read( stm, &format_hdr, sz, &count );
     if( FAILED(r) || count != sz )
-        return ret;
+        return ERROR_FUNCTION_FAILED;
 
     /* check the format id is correct */
     if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) )
-        return ret;
+        return ERROR_FUNCTION_FAILED;
 
     /* seek to the location of the section */
     ofs.QuadPart = format_hdr.dwOffset;
     r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL );
     if( FAILED(r) )
-        return ret;
+        return ERROR_FUNCTION_FAILED;
 
     /* read the section itself */
     sz = SECT_HDR_SIZE;
     r = IStream_Read( stm, &section_hdr, sz, &count );
     if( FAILED(r) || count != sz )
-        return ret;
+        return ERROR_FUNCTION_FAILED;
 
     if( section_hdr.cProperties > MSI_MAX_PROPS )
     {
         ERR("too many properties %d\n", section_hdr.cProperties);
-        return ret;
+        return ERROR_FUNCTION_FAILED;
     }
 
     data = msi_alloc( section_hdr.cbSection);
     if( !data )
-        return ret;
+        return ERROR_FUNCTION_FAILED;
 
     memcpy( data, &section_hdr, SECT_HDR_SIZE );
 
@@ -284,7 +283,7 @@ static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
         ERR("failed to read properties %d %d\n", count, sz);
 
     msi_free( data );
-    return ret;
+    return ERROR_SUCCESS;
 }
 
 static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val )
@@ -410,34 +409,75 @@ static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm )
     return ERROR_SUCCESS;
 }
 
-MSISUMMARYINFO *MSI_GetSummaryInformationW( IStorage *stg, UINT uiUpdateCount )
+static MSISUMMARYINFO *create_suminfo( IStorage *stg, UINT update_count )
 {
-    IStream *stm = NULL;
     MSISUMMARYINFO *si;
-    DWORD grfMode;
-    HRESULT r;
-
-    TRACE("%p %d\n", stg, uiUpdateCount );
 
-    si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, 
-                  sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
-    if( !si )
-        return si;
+    if (!(si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, sizeof(MSISUMMARYINFO), MSI_CloseSummaryInfo )))
+        return NULL;
 
-    si->update_count = uiUpdateCount;
+    si->update_count = update_count;
     IStorage_AddRef( stg );
     si->storage = stg;
 
-    /* read the stream... if we fail, we'll start with an empty property set */
-    grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
-    r = IStorage_OpenStream( si->storage, szSumInfo, 0, grfMode, 0, &stm );
-    if( SUCCEEDED(r) )
+    return si;
+}
+
+UINT msi_get_suminfo( IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **ret )
+{
+    IStream *stm;
+    MSISUMMARYINFO *si;
+    HRESULT hr;
+    UINT r;
+
+    TRACE("%p, %u\n", stg, uiUpdateCount);
+
+    if (!(si = create_suminfo( stg, uiUpdateCount ))) return ERROR_OUTOFMEMORY;
+
+    hr = IStorage_OpenStream( si->storage, szSumInfo, 0, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stm );
+    if (FAILED( hr ))
     {
-        load_summary_info( si, stm );
-        IStream_Release( stm );
+        msiobj_release( &si->hdr );
+        return ERROR_FUNCTION_FAILED;
     }
 
-    return si;
+    r = load_summary_info( si, stm );
+    IStream_Release( stm );
+    if (r != ERROR_SUCCESS)
+    {
+        msiobj_release( &si->hdr );
+        return r;
+    }
+
+    *ret = si;
+    return ERROR_SUCCESS;
+}
+
+UINT msi_get_db_suminfo( MSIDATABASE *db, UINT uiUpdateCount, MSISUMMARYINFO **ret )
+{
+    IStream *stm;
+    MSISUMMARYINFO *si;
+    UINT r;
+
+    if (!(si = create_suminfo( db->storage, uiUpdateCount ))) return ERROR_OUTOFMEMORY;
+
+    r = msi_get_stream( db, szSumInfo, &stm );
+    if (r != ERROR_SUCCESS)
+    {
+        msiobj_release( &si->hdr );
+        return r;
+    }
+
+    r = load_summary_info( si, stm );
+    IStream_Release( stm );
+    if (r != ERROR_SUCCESS)
+    {
+        msiobj_release( &si->hdr );
+        return r;
+    }
+
+    *ret = si;
+    return ERROR_SUCCESS;
 }
 
 UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, 
@@ -445,7 +485,7 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
 {
     MSISUMMARYINFO *si;
     MSIDATABASE *db;
-    UINT ret = ERROR_FUNCTION_FAILED;
+    UINT ret;
 
     TRACE("%d %s %d %p\n", hDatabase, debugstr_w(szDatabase),
            uiUpdateCount, pHandle);
@@ -489,8 +529,16 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
         }
     }
 
-    si = MSI_GetSummaryInformationW( db->storage, uiUpdateCount );
-    if (si)
+    ret = msi_get_suminfo( db->storage, uiUpdateCount, &si );
+    if (ret != ERROR_SUCCESS)
+        ret = msi_get_db_suminfo( db, uiUpdateCount, &si );
+    if (ret != ERROR_SUCCESS)
+    {
+        if ((si = create_suminfo( db->storage, uiUpdateCount )))
+            ret = ERROR_SUCCESS;
+    }
+
+    if (ret == ERROR_SUCCESS)
     {
         *pHandle = alloc_msihandle( &si->hdr );
         if( *pHandle )
@@ -544,26 +592,12 @@ UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, PUINT pCount)
     return ERROR_SUCCESS;
 }
 
-static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
-          INT *piValue, FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
+static UINT get_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT *puiDataType, INT *piValue,
+                      FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
 {
-    MSISUMMARYINFO *si;
     PROPVARIANT *prop;
     UINT ret = ERROR_SUCCESS;
 
-    TRACE("%d %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
-          piValue, pftValue, str, pcchValueBuf);
-
-    if ( uiProperty >= MSI_MAX_PROPS )
-    {
-        if (puiDataType) *puiDataType = VT_EMPTY;
-        return ERROR_UNKNOWN_PROPERTY;
-    }
-
-    si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
-    if( !si )
-        return ERROR_INVALID_HANDLE;
-
     prop = &si->property[uiProperty];
 
     if( puiDataType )
@@ -610,7 +644,6 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
         FIXME("Unknown property variant type\n");
         break;
     }
-    msiobj_release( &si->hdr );
     return ret;
 }
 
@@ -642,9 +675,10 @@ LPWSTR msi_get_suminfo_product( IStorage *stg )
 {
     MSISUMMARYINFO *si;
     LPWSTR prod;
+    UINT r;
 
-    si = MSI_GetSummaryInformationW( stg, 0 );
-    if (!si)
+    r = msi_get_suminfo( stg, 0, &si );
+    if (r != ERROR_SUCCESS)
     {
         ERR("no summary information!\n");
         return NULL;
@@ -658,42 +692,65 @@ UINT WINAPI MsiSummaryInfoGetPropertyA(
       MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
       FILETIME *pftValue, LPSTR szValueBuf, LPDWORD pcchValueBuf)
 {
+    MSISUMMARYINFO *si;
     awstring str;
+    UINT r;
 
-    TRACE("%d %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
+    TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType,
           piValue, pftValue, szValueBuf, pcchValueBuf );
 
+    if (uiProperty >= MSI_MAX_PROPS)
+    {
+        if (puiDataType) *puiDataType = VT_EMPTY;
+        return ERROR_UNKNOWN_PROPERTY;
+    }
+
+    if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
+        return ERROR_INVALID_HANDLE;
+
     str.unicode = FALSE;
     str.str.a = szValueBuf;
 
-    return get_prop( handle, uiProperty, puiDataType, piValue,
-                     pftValue, &str, pcchValueBuf );
+    r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf );
+    msiobj_release( &si->hdr );
+    return r;
 }
 
 UINT WINAPI MsiSummaryInfoGetPropertyW(
       MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
       FILETIME *pftValue, LPWSTR szValueBuf, LPDWORD pcchValueBuf)
 {
+    MSISUMMARYINFO *si;
     awstring str;
+    UINT r;
 
-    TRACE("%d %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
+    TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType,
           piValue, pftValue, szValueBuf, pcchValueBuf );
 
+    if (uiProperty >= MSI_MAX_PROPS)
+    {
+        if (puiDataType) *puiDataType = VT_EMPTY;
+        return ERROR_UNKNOWN_PROPERTY;
+    }
+
+    if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
+        return ERROR_INVALID_HANDLE;
+
     str.unicode = TRUE;
     str.str.w = szValueBuf;
 
-    return get_prop( handle, uiProperty, puiDataType, piValue,
-                     pftValue, &str, pcchValueBuf );
+    r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf );
+    msiobj_release( &si->hdr );
+    return r;
 }
 
 static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type,
-               INT iValue, FILETIME* pftValue, awcstring *str )
+                      INT iValue, FILETIME *pftValue, awcstring *str )
 {
     PROPVARIANT *prop;
     UINT len;
 
-    TRACE("%p %u %u %i %p %p\n", si, uiProperty, type, iValue,
-          pftValue, str );
+    TRACE("%p, %u, %u, %d, %p, %p\n", si, uiProperty, type, iValue, pftValue, str );
 
     prop = &si->property[uiProperty];
 
@@ -741,15 +798,15 @@ static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type,
     return ERROR_SUCCESS;
 }
 
-UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
-               UINT uiDataType, INT iValue, FILETIME* pftValue, LPCWSTR szValue )
+UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
+                                        INT iValue, FILETIME *pftValue, LPCWSTR szValue )
 {
     awcstring str;
     MSISUMMARYINFO *si;
     UINT type, ret;
 
-    TRACE("%d %u %u %i %p %s\n", handle, uiProperty, uiDataType,
-          iValue, pftValue, debugstr_w(szValue) );
+    TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue,
+          debugstr_w(szValue) );
 
     type = get_type( uiProperty );
     if( type == VT_EMPTY || type != uiDataType )
@@ -761,27 +818,26 @@ UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
     if( uiDataType == VT_FILETIME && !pftValue )
         return ERROR_INVALID_PARAMETER;
 
-    si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
-    if( !si )
+    if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
         return ERROR_INVALID_HANDLE;
 
     str.unicode = TRUE;
     str.str.w = szValue;
-    ret = set_prop( si, uiProperty, type, iValue, pftValue, &str );
 
+    ret = set_prop( si, uiProperty, type, iValue, pftValue, &str );
     msiobj_release( &si->hdr );
     return ret;
 }
 
-UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
-               UINT uiDataType, INT iValue, FILETIME* pftValue, LPCSTR szValue )
+UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
+                                        INT iValue, FILETIME *pftValue, LPCSTR szValue )
 {
     awcstring str;
     MSISUMMARYINFO *si;
     UINT type, ret;
 
-    TRACE("%d %u %u %i %p %s\n", handle, uiProperty, uiDataType,
-          iValue, pftValue, debugstr_a(szValue) );
+    TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue,
+          debugstr_a(szValue) );
 
     type = get_type( uiProperty );
     if( type == VT_EMPTY || type != uiDataType )
@@ -793,14 +849,13 @@ UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
     if( uiDataType == VT_FILETIME && !pftValue )
         return ERROR_INVALID_PARAMETER;
 
-    si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
-    if( !si )
+    if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
         return ERROR_INVALID_HANDLE;
 
     str.unicode = FALSE;
     str.str.a = szValue;
-    ret = set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str );
 
+    ret = set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str );
     msiobj_release( &si->hdr );
     return ret;
 }
@@ -905,15 +960,16 @@ static UINT parse_prop( LPCWSTR prop, LPCWSTR value, UINT *pid, INT *int_value,
 
 UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns )
 {
-    UINT r = ERROR_FUNCTION_FAILED;
+    UINT r;
     int i, j;
     MSISUMMARYINFO *si;
 
-    si = MSI_GetSummaryInformationW( db->storage, num_records * (num_columns / 2) );
-    if (!si)
+    r = msi_get_suminfo( db->storage, num_records * (num_columns / 2), &si );
+    if (r != ERROR_SUCCESS)
     {
-        ERR("no summary information!\n");
-        return ERROR_FUNCTION_FAILED;
+        if (!(si = create_suminfo( db->storage, num_records * (num_columns / 2) )))
+            return ERROR_OUTOFMEMORY;
+        r = ERROR_SUCCESS;
     }
 
     for (i = 0; i < num_records; i++)
@@ -980,3 +1036,57 @@ UINT WINAPI MsiCreateTransformSummaryInfoW( MSIHANDLE db, MSIHANDLE db_ref, LPCW
     FIXME("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_w(transform), error, validation);
     return ERROR_FUNCTION_FAILED;
 }
+
+UINT msi_load_suminfo_properties( MSIPACKAGE *package )
+{
+    static const WCHAR packagecodeW[] = {'P','a','c','k','a','g','e','C','o','d','e',0};
+    MSISUMMARYINFO *si;
+    WCHAR *package_code;
+    UINT r, len;
+    awstring str;
+    INT count;
+
+    r = msi_get_suminfo( package->db->storage, 0, &si );
+    if (r != ERROR_SUCCESS)
+    {
+        r = msi_get_db_suminfo( package->db, 0, &si );
+        if (r != ERROR_SUCCESS)
+        {
+            ERR("Unable to open summary information stream %u\n", r);
+            return r;
+        }
+    }
+
+    str.unicode = TRUE;
+    str.str.w = NULL;
+    len = 0;
+    r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len );
+    if (r != ERROR_MORE_DATA)
+    {
+        WARN("Unable to query revision number %u\n", r);
+        msiobj_release( &si->hdr );
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    len++;
+    if (!(package_code = msi_alloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
+    str.str.w = package_code;
+
+    r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len );
+    if (r != ERROR_SUCCESS)
+    {
+        msi_free( package_code );
+        msiobj_release( &si->hdr );
+        return r;
+    }
+
+    r = msi_set_property( package->db, packagecodeW, package_code, len );
+    msi_free( package_code );
+
+    count = 0;
+    get_prop( si, PID_WORDCOUNT, NULL, &count, NULL, NULL, NULL );
+    package->WordCount = count;
+
+    msiobj_release( &si->hdr );
+    return r;
+}
index a5ac8bd..8c440d5 100644 (file)
@@ -1035,7 +1035,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
     return ERROR_SUCCESS;
 }
 
-static UINT msi_stream_name( const MSITABLEVIEW *tv, UINT row, LPWSTR *pstname )
+static UINT get_stream_name( const MSITABLEVIEW *tv, UINT row, WCHAR **pstname )
 {
     LPWSTR p, stname = NULL;
     UINT i, r, type, ival;
@@ -1135,7 +1135,7 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
     if( !view->ops->fetch_int )
         return ERROR_INVALID_PARAMETER;
 
-    r = msi_stream_name( tv, row, &name );
+    r = get_stream_name( tv, row, &name );
     if (r != ERROR_SUCCESS)
     {
         ERR("fetching stream, error = %u\n", r);
@@ -1197,39 +1197,63 @@ static UINT TABLE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
     return msi_view_get_row(tv->db, view, row, rec);
 }
 
-static UINT msi_addstreamW( MSIDATABASE *db, LPCWSTR name, IStream *data )
+static UINT add_stream( MSIDATABASE *db, const WCHAR *name, IStream *data )
 {
     static const WCHAR insert[] = {
         'I','N','S','E','R','T',' ','I','N','T','O',' ',
         '`','_','S','t','r','e','a','m','s','`',' ',
         '(','`','N','a','m','e','`',',','`','D','a','t','a','`',')',' ',
         'V','A','L','U','E','S',' ','(','?',',','?',')',0};
-    MSIQUERY *query = NULL;
+    static const WCHAR update[] = {
+        'U','P','D','A','T','E',' ','`','_','S','t','r','e','a','m','s','`',' ',
+        'S','E','T',' ','`','D','a','t','a','`',' ','=',' ','?',' ',
+        'W','H','E','R','E',' ','`','N','a','m','e','`',' ','=',' ','?',0};
+    MSIQUERY *query;
     MSIRECORD *rec;
     UINT r;
 
     TRACE("%p %s %p\n", db, debugstr_w(name), data);
 
-    rec = MSI_CreateRecord( 2 );
-    if ( !rec )
+    if (!(rec = MSI_CreateRecord( 2 )))
         return ERROR_OUTOFMEMORY;
 
     r = MSI_RecordSetStringW( rec, 1, name );
-    if ( r != ERROR_SUCCESS )
-       goto err;
+    if (r != ERROR_SUCCESS)
+       goto done;
 
     r = MSI_RecordSetIStream( rec, 2, data );
-    if ( r != ERROR_SUCCESS )
-       goto err;
+    if (r != ERROR_SUCCESS)
+       goto done;
 
     r = MSI_DatabaseOpenViewW( db, insert, &query );
-    if ( r != ERROR_SUCCESS )
-       goto err;
+    if (r != ERROR_SUCCESS)
+       goto done;
 
     r = MSI_ViewExecute( query, rec );
+    msiobj_release( &query->hdr );
+    if (r == ERROR_SUCCESS)
+        goto done;
 
-err:
+    msiobj_release( &rec->hdr );
+    if (!(rec = MSI_CreateRecord( 2 )))
+        return ERROR_OUTOFMEMORY;
+
+    r = MSI_RecordSetIStream( rec, 1, data );
+    if (r != ERROR_SUCCESS)
+       goto done;
+
+    r = MSI_RecordSetStringW( rec, 2, name );
+    if (r != ERROR_SUCCESS)
+       goto done;
+
+    r = MSI_DatabaseOpenViewW( db, update, &query );
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    r = MSI_ViewExecute( query, rec );
     msiobj_release( &query->hdr );
+
+done:
     msiobj_release( &rec->hdr );
     return r;
 }
@@ -1326,14 +1350,14 @@ static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UI
                 if ( r != ERROR_SUCCESS )
                     return r;
 
-                r = msi_stream_name( tv, row, &stname );
+                r = get_stream_name( tv, row, &stname );
                 if ( r != ERROR_SUCCESS )
                 {
                     IStream_Release( stm );
                     return r;
                 }
 
-                r = msi_addstreamW( tv->db, stname, stm );
+                r = add_stream( tv->db, stname, stm );
                 IStream_Release( stm );
                 msi_free ( stname );
 
index e6f4bde..9993b93 100644 (file)
@@ -117,7 +117,7 @@ reactos/dll/win32/msg711.acm          # Synced to WineStaging-1.7.47
 reactos/dll/win32/msgsm32.acm         # Synced to WineStaging-1.7.47
 reactos/dll/win32/mshtml              # Synced to WineStaging-1.7.37
 reactos/dll/win32/mshtml.tlb          # Synced to WineStaging-1.7.37
-reactos/dll/win32/msi                 # Synced to WineStaging-1.7.37
+reactos/dll/win32/msi                 # Synced to WineStaging-1.7.47
 reactos/dll/win32/msimg32             # Synced to WineStaging-1.7.37
 reactos/dll/win32/msimtf              # Synced to WineStaging-1.7.37
 reactos/dll/win32/msisip              # Synced to WineStaging-1.7.37