From f1e59351ded497a7f9cd7c27c0fdfcf6db3765c2 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Mon, 7 Mar 2011 12:40:39 +0100 Subject: [PATCH] msi: Manage one assembly cache per major version of the .NET runtime. --- dlls/msi/assembly.c | 192 ++++++++++++++++++++++++++++---------------- dlls/msi/msipriv.h | 10 ++- dlls/msi/package.c | 6 +- 3 files changed, 137 insertions(+), 71 deletions(-) diff --git a/dlls/msi/assembly.c b/dlls/msi/assembly.c index a4d58d17c06..fcca6b8eb62 100644 --- a/dlls/msi/assembly.c +++ b/dlls/msi/assembly.c @@ -31,66 +31,72 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); -static HRESULT (WINAPI *pCreateAssemblyCacheNet)( IAssemblyCache **, DWORD ); +static HRESULT (WINAPI *pCreateAssemblyCacheNet11)( IAssemblyCache **, DWORD ); +static HRESULT (WINAPI *pCreateAssemblyCacheNet20)( 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 BOOL init_function_pointers( void ) { static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0}; - HMODULE hfusion, hmscoree, hsxs; - HRESULT hr; + static const WCHAR szVersion11[] = {'v','1','.','1','.','4','3','2','2',0}; + static const WCHAR szVersion20[] = {'v','2','.','0','.','5','0','7','2','7',0}; + HMODULE hfusion11 = NULL, hfusion20 = NULL, hmscoree, hsxs; - if (pCreateAssemblyCacheNet) return TRUE; + if (pCreateAssemblyCacheNet11 || pCreateAssemblyCacheNet20) return TRUE; - if (!(hmscoree = LoadLibraryA( "mscoree.dll" ))) - { - WARN("mscoree.dll not available\n"); - return FALSE; - } - if (!(pLoadLibraryShim = (void *)GetProcAddress( hmscoree, "LoadLibraryShim" ))) - { - WARN("LoadLibraryShim not available\n"); - FreeLibrary( hmscoree ); - return FALSE; - } - hr = pLoadLibraryShim( szFusion, NULL, NULL, &hfusion ); - if (FAILED( hr )) - { - WARN("fusion.dll not available 0x%08x\n", hr); - FreeLibrary( hmscoree ); - return FALSE; - } - pCreateAssemblyCacheNet = (void *)GetProcAddress( hfusion, "CreateAssemblyCache" ); - FreeLibrary( hmscoree ); - if (!(hsxs = LoadLibraryA( "sxs.dll" ))) - { - WARN("sxs.dll not available\n"); - FreeLibrary( hfusion ); - return FALSE; - } - pCreateAssemblyCacheSxs = (void *)GetProcAddress( hsxs, "CreateAssemblyCache" ); + if (!(hmscoree = LoadLibraryA( "mscoree.dll" ))) return FALSE; + if (!(pGetFileVersion = (void *)GetProcAddress( hmscoree, "GetFileVersion" ))) goto error; + if (!(pLoadLibraryShim = (void *)GetProcAddress( hmscoree, "LoadLibraryShim" ))) goto error; + + if (!pLoadLibraryShim( szFusion, szVersion11, NULL, &hfusion11 )) + pCreateAssemblyCacheNet11 = (void *)GetProcAddress( hfusion11, "CreateAssemblyCache" ); + + if (!pLoadLibraryShim( szFusion, szVersion20, NULL, &hfusion20 )) + pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" ); + + if (!pCreateAssemblyCacheNet11 && !pCreateAssemblyCacheNet20) goto error; + + if (!(hsxs = LoadLibraryA( "sxs.dll" ))) goto error; + if (!(pCreateAssemblyCacheSxs = (void *)GetProcAddress( hsxs, "CreateAssemblyCache" ))) goto error; return TRUE; + +error: + pCreateAssemblyCacheNet11 = NULL; + pCreateAssemblyCacheNet20 = NULL; + FreeLibrary( hfusion11 ); + FreeLibrary( hfusion20 ); + FreeLibrary( hmscoree ); + return FALSE; } static BOOL init_assembly_caches( MSIPACKAGE *package ) { - HRESULT hr; - if (!init_function_pointers()) return FALSE; - if (package->cache_net) return TRUE; + if (package->cache_net[CLR_VERSION_V11] || package->cache_net[CLR_VERSION_V20]) return TRUE; + if (pCreateAssemblyCacheSxs( &package->cache_sxs, 0 ) != S_OK) return FALSE; - hr = pCreateAssemblyCacheNet( &package->cache_net, 0 ); - if (hr != S_OK) return FALSE; + if (pCreateAssemblyCacheNet11) pCreateAssemblyCacheNet11( &package->cache_net[CLR_VERSION_V11], 0 ); + if (pCreateAssemblyCacheNet20) pCreateAssemblyCacheNet20( &package->cache_net[CLR_VERSION_V20], 0 ); - hr = pCreateAssemblyCacheSxs( &package->cache_sxs, 0 ); - if (hr != S_OK) + if (package->cache_net[CLR_VERSION_V11] || package->cache_net[CLR_VERSION_V20]) { - IAssemblyCache_Release( package->cache_net ); - package->cache_net = NULL; - return FALSE; + return TRUE; } - return TRUE; + if (package->cache_net[CLR_VERSION_V11]) + { + IAssemblyCache_Release( package->cache_net[CLR_VERSION_V11] ); + package->cache_net[CLR_VERSION_V11] = NULL; + } + if (package->cache_net[CLR_VERSION_V20]) + { + IAssemblyCache_Release( package->cache_net[CLR_VERSION_V20] ); + package->cache_net[CLR_VERSION_V20] = NULL; + } + IAssemblyCache_Release( package->cache_sxs ); + package->cache_sxs = NULL; + return FALSE; } MSIRECORD *get_assembly_record( MSIPACKAGE *package, const WCHAR *comp ) @@ -201,44 +207,50 @@ done: return display_name; } -static BOOL check_assembly_installed( MSIPACKAGE *package, MSIASSEMBLY *assembly ) +static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_name ) { - IAssemblyCache *cache; - ASSEMBLY_INFO info; HRESULT hr; - - if (assembly->application) - { - FIXME("we should probably check the manifest file here\n"); - if (msi_get_property_int( package->db, szInstalled, 0 )) return TRUE; - return FALSE; - } - - if (!init_assembly_caches( package )) - return FALSE; - - if (assembly->attributes == msidbAssemblyAttributesWin32) - cache = package->cache_sxs; - else - cache = package->cache_net; + ASSEMBLY_INFO info; memset( &info, 0, sizeof(info) ); info.cbAssemblyInfo = sizeof(info); - hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, assembly->display_name, &info ); - if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) + hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_GETSIZE, display_name, &info ); + if (FAILED( hr )) + { + TRACE("QueryAssemblyInfo returned 0x%08x\n", hr); return FALSE; - + } return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED); } +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}; +static const WCHAR clr_version_unknown[] = {'u','n','k','n','o','w','n',0}; + +static const WCHAR *clr_version[] = +{ + clr_version_v11, + clr_version_v20 +}; + +static const WCHAR *get_clr_version_str( enum clr_version version ) +{ + if (version >= sizeof(clr_version)/sizeof(clr_version[0])) return clr_version_unknown; + return clr_version[version]; +} + MSIASSEMBLY *load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) { MSIRECORD *rec; MSIASSEMBLY *a; - if (!(rec = get_assembly_record( package, comp->Component ))) + if (!(rec = get_assembly_record( package, comp->Component ))) return NULL; + if (!init_assembly_caches( package )) + { + ERR("can't initialize assembly caches\n"); + msiobj_release( &rec->hdr ); return NULL; - + } if (!(a = msi_alloc_zero( sizeof(MSIASSEMBLY) ))) { msiobj_release( &rec->hdr ); @@ -268,13 +280,57 @@ MSIASSEMBLY *load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) } TRACE("display name %s\n", debugstr_w(a->display_name)); - a->installed = check_assembly_installed( package, a ); + if (a->application) + { + FIXME("we should probably check the manifest file here\n"); + a->installed = (msi_get_property_int( package->db, szInstalled, 0 ) != 0); + } + 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; + } + } + } + } TRACE("assembly is %s\n", a->installed ? "installed" : "not installed"); - msiobj_release( &rec->hdr ); return a; } +static enum clr_version get_clr_version( const WCHAR *filename ) +{ + DWORD len; + HRESULT hr; + enum clr_version version = CLR_VERSION_V11; + WCHAR *strW; + + hr = pGetFileVersion( filename, NULL, 0, &len ); + if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) return CLR_VERSION_V11; + if ((strW = msi_alloc( len * sizeof(WCHAR) ))) + { + hr = pGetFileVersion( filename, strW, len, &len ); + if (hr == S_OK) + { + UINT i; + for (i = 0; i < CLR_VERSION_MAX; i++) + if (!strcmpW( strW, clr_version[i] )) version = i; + } + msi_free( strW ); + } + return version; +} + UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) { HRESULT hr; @@ -304,7 +360,7 @@ UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) else { manifest = get_loaded_file( package, comp->KeyPath )->TargetPath; - cache = package->cache_net; + cache = package->cache_net[get_clr_version( manifest )]; } TRACE("installing assembly %s\n", debugstr_w(manifest)); diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 0a649069db5..7c25ec9926c 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -324,6 +324,13 @@ enum platform PLATFORM_X64 }; +enum clr_version +{ + CLR_VERSION_V11, + CLR_VERSION_V20, + CLR_VERSION_MAX +}; + typedef struct tagMSIPACKAGE { MSIOBJECTHDR hdr; @@ -342,7 +349,7 @@ typedef struct tagMSIPACKAGE LPWSTR ActionFormat; LPWSTR LastAction; HANDLE log_file; - IAssemblyCache *cache_net; + IAssemblyCache *cache_net[CLR_VERSION_MAX]; IAssemblyCache *cache_sxs; struct list classes; @@ -423,6 +430,7 @@ typedef struct tagMSIASSEMBLY LPWSTR display_name; LPWSTR tempdir; BOOL installed; + BOOL clr_version[CLR_VERSION_MAX]; } MSIASSEMBLY; typedef struct tagMSICOMPONENT diff --git a/dlls/msi/package.c b/dlls/msi/package.c index 8d5fc18eb6f..c84c28a7516 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -313,7 +313,8 @@ static void free_package_structures( MSIPACKAGE *package ) static void MSI_FreePackage( MSIOBJECTHDR *arg) { - MSIPACKAGE *package= (MSIPACKAGE*) arg; + UINT i; + MSIPACKAGE *package = (MSIPACKAGE *)arg; if( package->dialog ) msi_dialog_destroy( package->dialog ); @@ -322,7 +323,8 @@ static void MSI_FreePackage( MSIOBJECTHDR *arg) free_package_structures(package); CloseHandle( package->log_file ); - if (package->cache_net) IAssemblyCache_Release( package->cache_net ); + for (i = 0; i < CLR_VERSION_MAX; i++) + if (package->cache_net[i]) IAssemblyCache_Release( package->cache_net[i] ); if (package->cache_sxs) IAssemblyCache_Release( package->cache_sxs ); }