[5/5] msi: Manage one assembly cache per major version of the .NET runtime.

Hans Leidekker hans at codeweavers.com
Mon Mar 7 05:40:39 CST 2011


---
 dlls/msi/assembly.c |  188 +++++++++++++++++++++++++++++++++------------------
 dlls/msi/msipriv.h  |   10 +++-
 dlls/msi/package.c  |    6 +-
 3 files changed, 135 insertions(+), 69 deletions(-)

diff --git a/dlls/msi/assembly.c b/dlls/msi/assembly.c
index a4d58d1..fcca6b8 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,34 +207,36 @@ 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;
+    ASSEMBLY_INFO info;
 
-    if (assembly->application)
+    memset( &info, 0, sizeof(info) );
+    info.cbAssemblyInfo = sizeof(info);
+    hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_GETSIZE, display_name, &info );
+    if (FAILED( hr ))
     {
-        FIXME("we should probably check the manifest file here\n");
-        if (msi_get_property_int( package->db, szInstalled, 0 )) return TRUE;
+        TRACE("QueryAssemblyInfo returned 0x%08x\n", hr);
         return FALSE;
     }
+    return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
+}
 
-    if (!init_assembly_caches( package ))
-        return FALSE;
-
-    if (assembly->attributes == msidbAssemblyAttributesWin32)
-        cache = package->cache_sxs;
-    else
-        cache = package->cache_net;
+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};
 
-    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))
-        return FALSE;
+static const WCHAR *clr_version[] =
+{
+    clr_version_v11,
+    clr_version_v20
+};
 
-    return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
+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 )
@@ -236,9 +244,13 @@ 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 0a64906..7c25ec9 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 8d5fc18..c84c28a 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 );
 }
 
-- 
1.7.1






More information about the wine-patches mailing list