Commit 2c450fd6 authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

msi: Install and patch global assemblies in InstallFinalize.

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
parent 6e7a54f7
......@@ -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);
......
......@@ -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;
}
......
......@@ -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 ) || !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(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:
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment