Commit f1e59351 authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

msi: Manage one assembly cache per major version of the .NET runtime.

parent 40ad619a
...@@ -31,66 +31,72 @@ ...@@ -31,66 +31,72 @@
WINE_DEFAULT_DEBUG_CHANNEL(msi); 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 *pCreateAssemblyCacheSxs)( IAssemblyCache **, DWORD );
static HRESULT (WINAPI *pLoadLibraryShim)( LPCWSTR, LPCWSTR, LPVOID, HMODULE * ); static HRESULT (WINAPI *pLoadLibraryShim)( LPCWSTR, LPCWSTR, LPVOID, HMODULE * );
static HRESULT (WINAPI *pGetFileVersion)( LPCWSTR, LPWSTR, DWORD, DWORD * );
static BOOL init_function_pointers( void ) static BOOL init_function_pointers( void )
{ {
static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0}; static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
HMODULE hfusion, hmscoree, hsxs; static const WCHAR szVersion11[] = {'v','1','.','1','.','4','3','2','2',0};
HRESULT hr; 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" ))) if (!(hmscoree = LoadLibraryA( "mscoree.dll" ))) return FALSE;
{ if (!(pGetFileVersion = (void *)GetProcAddress( hmscoree, "GetFileVersion" ))) goto error;
WARN("mscoree.dll not available\n"); if (!(pLoadLibraryShim = (void *)GetProcAddress( hmscoree, "LoadLibraryShim" ))) goto error;
return FALSE;
} if (!pLoadLibraryShim( szFusion, szVersion11, NULL, &hfusion11 ))
if (!(pLoadLibraryShim = (void *)GetProcAddress( hmscoree, "LoadLibraryShim" ))) pCreateAssemblyCacheNet11 = (void *)GetProcAddress( hfusion11, "CreateAssemblyCache" );
{
WARN("LoadLibraryShim not available\n"); if (!pLoadLibraryShim( szFusion, szVersion20, NULL, &hfusion20 ))
FreeLibrary( hmscoree ); pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" );
return FALSE;
} if (!pCreateAssemblyCacheNet11 && !pCreateAssemblyCacheNet20) goto error;
hr = pLoadLibraryShim( szFusion, NULL, NULL, &hfusion );
if (FAILED( hr )) if (!(hsxs = LoadLibraryA( "sxs.dll" ))) goto error;
{ if (!(pCreateAssemblyCacheSxs = (void *)GetProcAddress( hsxs, "CreateAssemblyCache" ))) goto error;
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" );
return TRUE; return TRUE;
error:
pCreateAssemblyCacheNet11 = NULL;
pCreateAssemblyCacheNet20 = NULL;
FreeLibrary( hfusion11 );
FreeLibrary( hfusion20 );
FreeLibrary( hmscoree );
return FALSE;
} }
static BOOL init_assembly_caches( MSIPACKAGE *package ) static BOOL init_assembly_caches( MSIPACKAGE *package )
{ {
HRESULT hr;
if (!init_function_pointers()) return FALSE; 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 (pCreateAssemblyCacheNet11) pCreateAssemblyCacheNet11( &package->cache_net[CLR_VERSION_V11], 0 );
if (hr != S_OK) return FALSE; if (pCreateAssemblyCacheNet20) pCreateAssemblyCacheNet20( &package->cache_net[CLR_VERSION_V20], 0 );
hr = pCreateAssemblyCacheSxs( &package->cache_sxs, 0 ); if (package->cache_net[CLR_VERSION_V11] || package->cache_net[CLR_VERSION_V20])
if (hr != S_OK)
{ {
IAssemblyCache_Release( package->cache_net ); return TRUE;
package->cache_net = NULL;
return FALSE;
} }
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 ) MSIRECORD *get_assembly_record( MSIPACKAGE *package, const WCHAR *comp )
...@@ -201,34 +207,36 @@ done: ...@@ -201,34 +207,36 @@ done:
return display_name; 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; 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"); TRACE("QueryAssemblyInfo returned 0x%08x\n", hr);
if (msi_get_property_int( package->db, szInstalled, 0 )) return TRUE;
return FALSE; return FALSE;
} }
return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED);
}
if (!init_assembly_caches( package )) static const WCHAR clr_version_v11[] = {'v','1','.','1','.','4','3','2','2',0};
return FALSE; 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};
if (assembly->attributes == msidbAssemblyAttributesWin32)
cache = package->cache_sxs;
else
cache = package->cache_net;
memset( &info, 0, sizeof(info) ); static const WCHAR *clr_version[] =
info.cbAssemblyInfo = sizeof(info); {
hr = IAssemblyCache_QueryAssemblyInfo( cache, QUERYASMINFO_FLAG_VALIDATE, assembly->display_name, &info ); clr_version_v11,
if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) clr_version_v20
return FALSE; };
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 ) MSIASSEMBLY *load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
...@@ -236,9 +244,13 @@ MSIASSEMBLY *load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) ...@@ -236,9 +244,13 @@ MSIASSEMBLY *load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
MSIRECORD *rec; MSIRECORD *rec;
MSIASSEMBLY *a; 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; return NULL;
}
if (!(a = msi_alloc_zero( sizeof(MSIASSEMBLY) ))) if (!(a = msi_alloc_zero( sizeof(MSIASSEMBLY) )))
{ {
msiobj_release( &rec->hdr ); msiobj_release( &rec->hdr );
...@@ -268,13 +280,57 @@ MSIASSEMBLY *load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) ...@@ -268,13 +280,57 @@ MSIASSEMBLY *load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
} }
TRACE("display name %s\n", debugstr_w(a->display_name)); 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"); TRACE("assembly is %s\n", a->installed ? "installed" : "not installed");
msiobj_release( &rec->hdr ); msiobj_release( &rec->hdr );
return a; 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 ) UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
{ {
HRESULT hr; HRESULT hr;
...@@ -304,7 +360,7 @@ UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) ...@@ -304,7 +360,7 @@ UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
else else
{ {
manifest = get_loaded_file( package, comp->KeyPath )->TargetPath; 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)); TRACE("installing assembly %s\n", debugstr_w(manifest));
......
...@@ -324,6 +324,13 @@ enum platform ...@@ -324,6 +324,13 @@ enum platform
PLATFORM_X64 PLATFORM_X64
}; };
enum clr_version
{
CLR_VERSION_V11,
CLR_VERSION_V20,
CLR_VERSION_MAX
};
typedef struct tagMSIPACKAGE typedef struct tagMSIPACKAGE
{ {
MSIOBJECTHDR hdr; MSIOBJECTHDR hdr;
...@@ -342,7 +349,7 @@ typedef struct tagMSIPACKAGE ...@@ -342,7 +349,7 @@ typedef struct tagMSIPACKAGE
LPWSTR ActionFormat; LPWSTR ActionFormat;
LPWSTR LastAction; LPWSTR LastAction;
HANDLE log_file; HANDLE log_file;
IAssemblyCache *cache_net; IAssemblyCache *cache_net[CLR_VERSION_MAX];
IAssemblyCache *cache_sxs; IAssemblyCache *cache_sxs;
struct list classes; struct list classes;
...@@ -423,6 +430,7 @@ typedef struct tagMSIASSEMBLY ...@@ -423,6 +430,7 @@ typedef struct tagMSIASSEMBLY
LPWSTR display_name; LPWSTR display_name;
LPWSTR tempdir; LPWSTR tempdir;
BOOL installed; BOOL installed;
BOOL clr_version[CLR_VERSION_MAX];
} MSIASSEMBLY; } MSIASSEMBLY;
typedef struct tagMSICOMPONENT typedef struct tagMSICOMPONENT
......
...@@ -313,7 +313,8 @@ static void free_package_structures( MSIPACKAGE *package ) ...@@ -313,7 +313,8 @@ static void free_package_structures( MSIPACKAGE *package )
static void MSI_FreePackage( MSIOBJECTHDR *arg) static void MSI_FreePackage( MSIOBJECTHDR *arg)
{ {
MSIPACKAGE *package= (MSIPACKAGE*) arg; UINT i;
MSIPACKAGE *package = (MSIPACKAGE *)arg;
if( package->dialog ) if( package->dialog )
msi_dialog_destroy( package->dialog ); msi_dialog_destroy( package->dialog );
...@@ -322,7 +323,8 @@ static void MSI_FreePackage( MSIOBJECTHDR *arg) ...@@ -322,7 +323,8 @@ static void MSI_FreePackage( MSIOBJECTHDR *arg)
free_package_structures(package); free_package_structures(package);
CloseHandle( package->log_file ); 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 ); if (package->cache_sxs) IAssemblyCache_Release( package->cache_sxs );
} }
......
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