From: Hans Leidekker hans@codeweavers.com
Installing global assemblies requires assembly caches to be initialized and this is no longer the case after the PE conversion (builtin fusion no longer loads if the dll is not present on disk).
The next patch changes msi to perform late initialization of the assembly caches so that native fusion can be loaded once it's installed by .NET installers. However, there's no guarantee that all necessary files and registry keys are installed before the InstallFiles and PatchFiles actions are executed. Therefore this patch moves the parts of these actions handling global assemblies to InstallFinalize.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51345 --- dlls/msi/action.c | 43 +++++++++++++++++++++++++++++++++-- dlls/msi/assembly.c | 55 --------------------------------------------- dlls/msi/files.c | 40 +++++---------------------------- dlls/msi/msipriv.h | 2 +- 4 files changed, 47 insertions(+), 93 deletions(-)
diff --git a/dlls/msi/action.c b/dlls/msi/action.c index d856e94efa7..2bb9604adb8 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -2068,8 +2068,7 @@ static UINT calculate_file_cost( MSIPACKAGE *package )
set_target_path( package, file );
- if ((comp->assembly && !comp->assembly->installed) || - msi_get_file_attributes( package, file->TargetPath ) == INVALID_FILE_ATTRIBUTES) + if (msi_get_file_attributes( package, file->TargetPath ) == INVALID_FILE_ATTRIBUTES) { comp->Cost += file->FileSize; continue; @@ -5134,6 +5133,8 @@ static BOOL is_full_uninstall( MSIPACKAGE *package ) static UINT ACTION_InstallFinalize(MSIPACKAGE *package) { UINT rc; + MSIFILE *file; + MSIFILEPATCH *patch;
/* first do the same as an InstallExecute */ rc = execute_script(package, SCRIPT_INSTALL); @@ -5145,6 +5146,44 @@ static UINT ACTION_InstallFinalize(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) return rc;
+ /* install global assemblies */ + LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) + { + MSICOMPONENT *comp = file->Component; + + if (!msi_is_global_assembly( comp ) || (file->state != msifs_missing && file->state != msifs_overwrite)) + continue; + + rc = msi_install_assembly( package, comp ); + if (rc != ERROR_SUCCESS) + { + ERR("Failed to install assembly\n"); + return ERROR_INSTALL_FAILURE; + } + file->state = msifs_installed; + } + + /* patch global assemblies */ + LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry ) + { + MSICOMPONENT *comp = patch->File->Component; + + if (!msi_is_global_assembly( comp ) || !patch->path) continue; + + rc = msi_patch_assembly( package, comp->assembly, patch ); + if (rc && !(patch->Attributes & msidbPatchAttributesNonVital)) + { + ERR("Failed to apply patch to file: %s\n", debugstr_w(patch->File->File)); + return rc; + } + + if ((rc = msi_install_assembly( package, comp ))) + { + ERR("Failed to install patched assembly\n"); + return rc; + } + } + if (is_full_uninstall(package)) rc = ACTION_UnpublishProduct(package);
diff --git a/dlls/msi/assembly.c b/dlls/msi/assembly.c index 7f75d225be0..586521342b6 100644 --- a/dlls/msi/assembly.c +++ b/dlls/msi/assembly.c @@ -219,24 +219,6 @@ done: return display_name; }
-static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_name ) -{ - HRESULT hr; - ASSEMBLY_INFO info; - - if (!cache) return FALSE; - - memset( &info, 0, sizeof(info) ); - info.cbAssemblyInfo = sizeof(info); - hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, display_name, &info ); - if (hr == S_OK /* sxs version */ || hr == E_NOT_SUFFICIENT_BUFFER) - { - return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED); - } - TRACE( "QueryAssemblyInfo returned %#lx\n", hr ); - return FALSE; -} - WCHAR *msi_get_assembly_path( MSIPACKAGE *package, const WCHAR *displayname ) { HRESULT hr; @@ -309,13 +291,6 @@ static const WCHAR *clr_version[] = L"v4.0.30319" };
-static const WCHAR *get_clr_version_str( enum clr_version version ) -{ - if (version >= ARRAY_SIZE( clr_version )) return L"unknown"; - return clr_version[version]; -} - -/* assembly caches must be initialized */ MSIASSEMBLY *msi_load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) { MSIRECORD *rec; @@ -351,34 +326,6 @@ MSIASSEMBLY *msi_load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) } TRACE("display name %s\n", debugstr_w(a->display_name));
- if (a->application) - { - /* We can't check the manifest here because the target path may still change. - So we assume that the assembly is not installed and lean on the InstallFiles - action to determine which files need to be installed. - */ - a->installed = FALSE; - } - else - { - if (a->attributes == msidbAssemblyAttributesWin32) - a->installed = is_assembly_installed( package->cache_sxs, a->display_name ); - else - { - UINT i; - for (i = 0; i < CLR_VERSION_MAX; i++) - { - a->clr_version[i] = is_assembly_installed( package->cache_net[i], a->display_name ); - if (a->clr_version[i]) - { - TRACE("runtime version %s\n", debugstr_w(get_clr_version_str( i ))); - a->installed = TRUE; - break; - } - } - } - } - TRACE("assembly is %s\n", a->installed ? "installed" : "not installed"); msiobj_release( &rec->hdr ); return a; } @@ -449,7 +396,6 @@ UINT msi_install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) return ERROR_FUNCTION_FAILED; } if (feature) feature->Action = INSTALLSTATE_LOCAL; - assembly->installed = TRUE; return ERROR_SUCCESS; }
@@ -491,7 +437,6 @@ UINT msi_uninstall_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) } } if (feature) feature->Action = INSTALLSTATE_ABSENT; - assembly->installed = FALSE; return ERROR_SUCCESS; }
diff --git a/dlls/msi/files.c b/dlls/msi/files.c index 75075a37b5f..8267691a94d 100644 --- a/dlls/msi/files.c +++ b/dlls/msi/files.c @@ -305,7 +305,7 @@ static msi_file_state calculate_install_state( MSIPACKAGE *package, MSIFILE *fil DWORD size;
comp->Action = msi_get_component_action( package, comp ); - if (!comp->Enabled || comp->Action != INSTALLSTATE_LOCAL || (comp->assembly && comp->assembly->installed)) + if (!comp->Enabled || comp->Action != INSTALLSTATE_LOCAL) { TRACE("skipping %s (not scheduled for install)\n", debugstr_w(file->File)); return msifs_skipped; @@ -315,8 +315,7 @@ static msi_file_state calculate_install_state( MSIPACKAGE *package, MSIFILE *fil TRACE("skipping %s (obsoleted by patch)\n", debugstr_w(file->File)); return msifs_skipped; } - if ((msi_is_global_assembly( comp ) && !comp->assembly->installed) || - msi_get_file_attributes( package, file->TargetPath ) == INVALID_FILE_ATTRIBUTES) + if (msi_get_file_attributes( package, file->TargetPath ) == INVALID_FILE_ATTRIBUTES) { TRACE("installing %s (missing)\n", debugstr_w(file->File)); return msifs_missing; @@ -650,22 +649,6 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) goto done; } } - LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) - { - 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) - { - ERR("Failed to install assembly\n"); - rc = ERROR_INSTALL_FAILURE; - break; - } - file->state = msifs_installed; - }
done: msi_free_media_info(mi); @@ -740,7 +723,7 @@ static UINT patch_file( MSIPACKAGE *package, MSIFILEPATCH *patch ) return r; }
-static UINT patch_assembly( MSIPACKAGE *package, MSIASSEMBLY *assembly, MSIFILEPATCH *patch ) +UINT msi_patch_assembly( MSIPACKAGE *package, MSIASSEMBLY *assembly, MSIFILEPATCH *patch ) { UINT r = ERROR_FUNCTION_FAILED; IAssemblyName *name; @@ -851,27 +834,14 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package ) { 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 (msi_is_global_assembly( comp ) || !patch->path) continue;
+ rc = patch_file( package, patch ); if (rc && !(patch->Attributes & msidbPatchAttributesNonVital)) { 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: diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 1db770481ef..902dd01205c 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -515,7 +515,6 @@ typedef struct tagMSIASSEMBLY DWORD attributes; LPWSTR display_name; LPWSTR tempdir; - BOOL installed; BOOL clr_version[CLR_VERSION_MAX]; } MSIASSEMBLY;
@@ -806,6 +805,7 @@ extern UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si extern UINT msi_apply_patches( MSIPACKAGE *package ) DECLSPEC_HIDDEN; extern UINT msi_apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code ) DECLSPEC_HIDDEN; extern void msi_free_patchinfo( MSIPATCHINFO *patch ) DECLSPEC_HIDDEN; +extern UINT msi_patch_assembly( MSIPACKAGE *, MSIASSEMBLY *, MSIFILEPATCH * ) DECLSPEC_HIDDEN;
/* action internals */ extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR ) DECLSPEC_HIDDEN;