msi: Add support for patching global assembly files.
This commit is contained in:
parent
d263c91ce2
commit
dc2228305c
|
@ -38,6 +38,8 @@ static HRESULT (WINAPI *pCreateAssemblyCacheNet40)( 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 HRESULT (WINAPI *pGetFileVersion)( LPCWSTR, LPWSTR, DWORD, DWORD * );
|
||||||
|
static HRESULT (WINAPI *pCreateAssemblyNameObject)( IAssemblyName **, LPCWSTR, DWORD, LPVOID );
|
||||||
|
static HRESULT (WINAPI *pCreateAssemblyEnum)( IAssemblyEnum **, IUnknown *, IAssemblyName *, DWORD, LPVOID );
|
||||||
|
|
||||||
static HMODULE hfusion10, hfusion11, hfusion20, hfusion40, hmscoree, hsxs;
|
static HMODULE hfusion10, hfusion11, hfusion20, hfusion40, hmscoree, hsxs;
|
||||||
|
|
||||||
|
@ -79,8 +81,11 @@ static BOOL init_function_pointers( void )
|
||||||
pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" );
|
pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" );
|
||||||
|
|
||||||
if (!pLoadLibraryShim( szFusion, szVersion40, NULL, &hfusion40 ))
|
if (!pLoadLibraryShim( szFusion, szVersion40, NULL, &hfusion40 ))
|
||||||
|
{
|
||||||
pCreateAssemblyCacheNet40 = (void *)GetProcAddress( hfusion40, "CreateAssemblyCache" );
|
pCreateAssemblyCacheNet40 = (void *)GetProcAddress( hfusion40, "CreateAssemblyCache" );
|
||||||
|
pCreateAssemblyNameObject = (void *)GetProcAddress( hfusion40, "CreateAssemblyNameObject" );
|
||||||
|
pCreateAssemblyEnum = (void *)GetProcAddress( hfusion40, "CreateAssemblyEnum" );
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,6 +264,70 @@ static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_n
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WCHAR *msi_get_assembly_path( MSIPACKAGE *package, const WCHAR *displayname )
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
ASSEMBLY_INFO info;
|
||||||
|
IAssemblyCache *cache = package->cache_net[CLR_VERSION_V40];
|
||||||
|
|
||||||
|
if (!cache) return NULL;
|
||||||
|
|
||||||
|
memset( &info, 0, sizeof(info) );
|
||||||
|
info.cbAssemblyInfo = sizeof(info);
|
||||||
|
hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info );
|
||||||
|
if (hr != E_NOT_SUFFICIENT_BUFFER) return NULL;
|
||||||
|
|
||||||
|
if (!(info.pszCurrentAssemblyPathBuf = msi_alloc( info.cchBuf * sizeof(WCHAR) ))) return NULL;
|
||||||
|
|
||||||
|
hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, displayname, &info );
|
||||||
|
if (FAILED( hr ))
|
||||||
|
{
|
||||||
|
msi_free( info.pszCurrentAssemblyPathBuf );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
TRACE("returning %s\n", debugstr_w(info.pszCurrentAssemblyPathBuf));
|
||||||
|
return info.pszCurrentAssemblyPathBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAssemblyEnum *msi_create_assembly_enum( MSIPACKAGE *package, const WCHAR *displayname )
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
IAssemblyName *name;
|
||||||
|
IAssemblyEnum *ret;
|
||||||
|
WCHAR *str;
|
||||||
|
UINT len = 0;
|
||||||
|
|
||||||
|
if (!pCreateAssemblyNameObject || !pCreateAssemblyEnum) return NULL;
|
||||||
|
|
||||||
|
hr = pCreateAssemblyNameObject( &name, displayname, CANOF_PARSE_DISPLAY_NAME, NULL );
|
||||||
|
if (FAILED( hr )) return NULL;
|
||||||
|
|
||||||
|
hr = IAssemblyName_GetName( name, &len, NULL );
|
||||||
|
if (hr != E_NOT_SUFFICIENT_BUFFER || !(str = msi_alloc( len * sizeof(WCHAR) )))
|
||||||
|
{
|
||||||
|
IAssemblyName_Release( name );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IAssemblyName_GetName( name, &len, str );
|
||||||
|
IAssemblyName_Release( name );
|
||||||
|
if (FAILED( hr ))
|
||||||
|
{
|
||||||
|
msi_free( str );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = pCreateAssemblyNameObject( &name, str, 0, NULL );
|
||||||
|
msi_free( str );
|
||||||
|
if (FAILED( hr )) return NULL;
|
||||||
|
|
||||||
|
hr = pCreateAssemblyEnum( &ret, NULL, name, ASM_CACHE_GAC, NULL );
|
||||||
|
IAssemblyName_Release( name );
|
||||||
|
if (FAILED( hr )) return NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static const WCHAR clr_version_v10[] = {'v','1','.','0','.','3','7','0','5',0};
|
static const WCHAR clr_version_v10[] = {'v','1','.','0','.','3','7','0','5',0};
|
||||||
static const WCHAR clr_version_v11[] = {'v','1','.','1','.','4','3','2','2',0};
|
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_v20[] = {'v','2','.','0','.','5','0','7','2','7',0};
|
||||||
|
|
110
dlls/msi/files.c
110
dlls/msi/files.c
|
@ -32,6 +32,8 @@
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define COBJMACROS
|
||||||
|
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
|
@ -493,6 +495,78 @@ static BOOL patchfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT patch_file( MSIPACKAGE *package, MSIFILEPATCH *patch )
|
||||||
|
{
|
||||||
|
UINT r = ERROR_SUCCESS;
|
||||||
|
WCHAR *tmpfile = msi_create_temp_file( package->db );
|
||||||
|
|
||||||
|
if (!tmpfile) return ERROR_INSTALL_FAILURE;
|
||||||
|
if (ApplyPatchToFileW( patch->path, patch->File->TargetPath, tmpfile, 0 ))
|
||||||
|
{
|
||||||
|
DeleteFileW( patch->File->TargetPath );
|
||||||
|
MoveFileW( tmpfile, patch->File->TargetPath );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WARN("failed to patch %s: %08x\n", debugstr_w(patch->File->TargetPath), GetLastError());
|
||||||
|
r = ERROR_INSTALL_FAILURE;
|
||||||
|
}
|
||||||
|
DeleteFileW( patch->path );
|
||||||
|
DeleteFileW( tmpfile );
|
||||||
|
msi_free( tmpfile );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT patch_assembly( MSIPACKAGE *package, MSIASSEMBLY *assembly, MSIFILEPATCH *patch )
|
||||||
|
{
|
||||||
|
UINT r = ERROR_FUNCTION_FAILED;
|
||||||
|
IAssemblyName *name;
|
||||||
|
IAssemblyEnum *iter;
|
||||||
|
|
||||||
|
if (!(iter = msi_create_assembly_enum( package, assembly->display_name )))
|
||||||
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
|
while ((IAssemblyEnum_GetNextAssembly( iter, NULL, &name, 0 ) == S_OK))
|
||||||
|
{
|
||||||
|
WCHAR *displayname, *path;
|
||||||
|
UINT len = 0;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = IAssemblyName_GetDisplayName( name, NULL, &len, 0 );
|
||||||
|
if (hr != E_NOT_SUFFICIENT_BUFFER || !(displayname = msi_alloc( len * sizeof(WCHAR) )))
|
||||||
|
break;
|
||||||
|
|
||||||
|
hr = IAssemblyName_GetDisplayName( name, displayname, &len, 0 );
|
||||||
|
if (FAILED( hr ))
|
||||||
|
{
|
||||||
|
msi_free( displayname );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((path = msi_get_assembly_path( package, displayname )))
|
||||||
|
{
|
||||||
|
if (!CopyFileW( path, patch->File->TargetPath, FALSE ))
|
||||||
|
{
|
||||||
|
ERR("Failed to copy file %s -> %s (%u)\n", debugstr_w(path),
|
||||||
|
debugstr_w(patch->File->TargetPath), GetLastError() );
|
||||||
|
msi_free( path );
|
||||||
|
msi_free( displayname );
|
||||||
|
IAssemblyName_Release( name );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r = patch_file( package, patch );
|
||||||
|
msi_free( path );
|
||||||
|
}
|
||||||
|
|
||||||
|
msi_free( displayname );
|
||||||
|
IAssemblyName_Release( name );
|
||||||
|
if (r == ERROR_SUCCESS) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAssemblyEnum_Release( iter );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
UINT ACTION_PatchFiles( MSIPACKAGE *package )
|
UINT ACTION_PatchFiles( MSIPACKAGE *package )
|
||||||
{
|
{
|
||||||
MSIFILEPATCH *patch;
|
MSIFILEPATCH *patch;
|
||||||
|
@ -549,34 +623,28 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package )
|
||||||
|
|
||||||
LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
|
LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
|
||||||
{
|
{
|
||||||
WCHAR *tmpfile;
|
MSICOMPONENT *comp = patch->File->Component;
|
||||||
BOOL ret;
|
|
||||||
|
|
||||||
if (!patch->path) continue;
|
if (!patch->path) continue;
|
||||||
|
|
||||||
if (!(tmpfile = msi_create_temp_file( package->db )))
|
if (msi_is_global_assembly( comp ))
|
||||||
{
|
rc = patch_assembly( package, comp->assembly, patch );
|
||||||
rc = ERROR_INSTALL_FAILURE;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
ret = ApplyPatchToFileW( patch->path, patch->File->TargetPath, tmpfile, 0 );
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
DeleteFileW( patch->File->TargetPath );
|
|
||||||
MoveFileW( tmpfile, patch->File->TargetPath );
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
WARN("failed to patch %s: %08x\n", debugstr_w(patch->File->TargetPath), GetLastError());
|
rc = patch_file( package, patch );
|
||||||
|
|
||||||
DeleteFileW( patch->path );
|
if (rc && !(patch->Attributes & msidbPatchAttributesNonVital))
|
||||||
DeleteFileW( tmpfile );
|
|
||||||
msi_free( tmpfile );
|
|
||||||
|
|
||||||
if (!ret && !(patch->Attributes & msidbPatchAttributesNonVital))
|
|
||||||
{
|
{
|
||||||
ERR("Failed to apply patch to file: %s\n", debugstr_w(patch->File->File));
|
ERR("Failed to apply patch to file: %s\n", debugstr_w(patch->File->File));
|
||||||
rc = ERROR_INSTALL_FAILURE;
|
break;
|
||||||
goto done;
|
}
|
||||||
|
|
||||||
|
if (msi_is_global_assembly( comp ))
|
||||||
|
{
|
||||||
|
if ((rc = msi_install_assembly( package, comp )))
|
||||||
|
{
|
||||||
|
ERR("Failed to install patched assembly\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1042,6 +1042,8 @@ extern UINT msi_uninstall_assembly(MSIPACKAGE *, MSICOMPONENT *) DECLSPEC_HIDDEN
|
||||||
extern BOOL msi_init_assembly_caches(MSIPACKAGE *) DECLSPEC_HIDDEN;
|
extern BOOL msi_init_assembly_caches(MSIPACKAGE *) DECLSPEC_HIDDEN;
|
||||||
extern void msi_destroy_assembly_caches(MSIPACKAGE *) DECLSPEC_HIDDEN;
|
extern void msi_destroy_assembly_caches(MSIPACKAGE *) DECLSPEC_HIDDEN;
|
||||||
extern BOOL msi_is_global_assembly(MSICOMPONENT *) DECLSPEC_HIDDEN;
|
extern BOOL msi_is_global_assembly(MSICOMPONENT *) DECLSPEC_HIDDEN;
|
||||||
|
extern IAssemblyEnum *msi_create_assembly_enum(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
|
||||||
|
extern WCHAR *msi_get_assembly_path(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
|
||||||
extern WCHAR *msi_font_version_from_file(const WCHAR *) DECLSPEC_HIDDEN;
|
extern WCHAR *msi_font_version_from_file(const WCHAR *) DECLSPEC_HIDDEN;
|
||||||
extern WCHAR **msi_split_string(const WCHAR *, WCHAR) DECLSPEC_HIDDEN;
|
extern WCHAR **msi_split_string(const WCHAR *, WCHAR) DECLSPEC_HIDDEN;
|
||||||
extern UINT msi_set_original_database_property(MSIDATABASE *, const WCHAR *) DECLSPEC_HIDDEN;
|
extern UINT msi_set_original_database_property(MSIDATABASE *, const WCHAR *) DECLSPEC_HIDDEN;
|
||||||
|
|
Loading…
Reference in New Issue