Hans Leidekker : msi: Add support for patching global assembly files.

Alexandre Julliard julliard at wine.codeweavers.com
Fri Apr 10 08:56:27 CDT 2015


Module: wine
Branch: master
Commit: dc2228305c821897091836b4d9593551a5ff9a65
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=dc2228305c821897091836b4d9593551a5ff9a65

Author: Hans Leidekker <hans at codeweavers.com>
Date:   Fri Apr 10 12:59:01 2015 +0200

msi: Add support for patching global assembly files.

---

 dlls/msi/assembly.c |  71 ++++++++++++++++++++++++++++++++-
 dlls/msi/files.c    | 110 ++++++++++++++++++++++++++++++++++++++++++----------
 dlls/msi/msipriv.h  |   2 +
 3 files changed, 161 insertions(+), 22 deletions(-)

diff --git a/dlls/msi/assembly.c b/dlls/msi/assembly.c
index a25b19d..7151a8b 100644
--- a/dlls/msi/assembly.c
+++ b/dlls/msi/assembly.c
@@ -38,6 +38,8 @@ static HRESULT (WINAPI *pCreateAssemblyCacheNet40)( 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 HRESULT (WINAPI *pCreateAssemblyNameObject)( IAssemblyName **, LPCWSTR, DWORD, LPVOID );
+static HRESULT (WINAPI *pCreateAssemblyEnum)( IAssemblyEnum **, IUnknown *, IAssemblyName *, DWORD, LPVOID );
 
 static HMODULE hfusion10, hfusion11, hfusion20, hfusion40, hmscoree, hsxs;
 
@@ -79,8 +81,11 @@ static BOOL init_function_pointers( void )
         pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" );
 
     if (!pLoadLibraryShim( szFusion, szVersion40, NULL, &hfusion40 ))
+    {
         pCreateAssemblyCacheNet40 = (void *)GetProcAddress( hfusion40, "CreateAssemblyCache" );
-
+        pCreateAssemblyNameObject = (void *)GetProcAddress( hfusion40, "CreateAssemblyNameObject" );
+        pCreateAssemblyEnum = (void *)GetProcAddress( hfusion40, "CreateAssemblyEnum" );
+    }
     return TRUE;
 }
 
@@ -259,6 +264,70 @@ static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_n
     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_v11[] = {'v','1','.','1','.','4','3','2','2',0};
 static const WCHAR clr_version_v20[] = {'v','2','.','0','.','5','0','7','2','7',0};
diff --git a/dlls/msi/files.c b/dlls/msi/files.c
index ca758dd..26e4cb1 100644
--- a/dlls/msi/files.c
+++ b/dlls/msi/files.c
@@ -32,6 +32,8 @@
 
 #include <stdarg.h>
 
+#define COBJMACROS
+
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
@@ -493,6 +495,78 @@ static BOOL patchfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
     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 )
 {
     MSIFILEPATCH *patch;
@@ -549,34 +623,28 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package )
 
     LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
     {
-        WCHAR *tmpfile;
-        BOOL ret;
+        MSICOMPONENT *comp = patch->File->Component;
 
         if (!patch->path) continue;
 
-        if (!(tmpfile = msi_create_temp_file( package->db )))
-        {
-            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 );
-        }
+        if (msi_is_global_assembly( comp ))
+            rc = patch_assembly( package, comp->assembly, patch );
         else
-            WARN("failed to patch %s: %08x\n", debugstr_w(patch->File->TargetPath), GetLastError());
-
-        DeleteFileW( patch->path );
-        DeleteFileW( tmpfile );
-        msi_free( tmpfile );
+            rc = patch_file( package, patch );
 
-        if (!ret && !(patch->Attributes & msidbPatchAttributesNonVital))
+        if (rc && !(patch->Attributes & msidbPatchAttributesNonVital))
         {
             ERR("Failed to apply patch to file: %s\n", debugstr_w(patch->File->File));
-            rc = ERROR_INSTALL_FAILURE;
-            goto done;
+            break;
+        }
+
+        if (msi_is_global_assembly( comp ))
+        {
+            if ((rc = msi_install_assembly( package, comp )))
+            {
+                ERR("Failed to install patched assembly\n");
+                break;
+            }
         }
     }
 
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 9bec75f..d457a54 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -1042,6 +1042,8 @@ extern UINT msi_uninstall_assembly(MSIPACKAGE *, MSICOMPONENT *) DECLSPEC_HIDDEN
 extern BOOL msi_init_assembly_caches(MSIPACKAGE *) DECLSPEC_HIDDEN;
 extern void msi_destroy_assembly_caches(MSIPACKAGE *) 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_split_string(const WCHAR *, WCHAR) DECLSPEC_HIDDEN;
 extern UINT msi_set_original_database_property(MSIDATABASE *, const WCHAR *) DECLSPEC_HIDDEN;




More information about the wine-cvs mailing list