[2/2] msi: Implement the MsiPublishAssemblies and MsiUnpublishAssemblies standard actions.

Hans Leidekker hans at codeweavers.com
Mon Jan 24 08:22:11 CST 2011


---
 dlls/msi/action.c       |    7 --
 dlls/msi/assembly.c     |  239 ++++++++++++++++++++++++++++++++++++++++++++++-
 dlls/msi/msipriv.h      |    1 +
 dlls/msi/tests/action.c |    6 +-
 4 files changed, 237 insertions(+), 16 deletions(-)

diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index 5a97d17..061d2f3 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -7172,13 +7172,6 @@ static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
     return msi_unimplemented_action_stub( package, "IsolateComponents", table );
 }
 
-static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
-{
-    static const WCHAR table[] = {
-        'M','s','i','A','s','s','e','m','b','l','y',0 };
-    return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
-}
-
 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
 {
     static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
diff --git a/dlls/msi/assembly.c b/dlls/msi/assembly.c
index f59d2eb..a4d58d1 100644
--- a/dlls/msi/assembly.c
+++ b/dlls/msi/assembly.c
@@ -24,6 +24,7 @@
 
 #include "windef.h"
 #include "winbase.h"
+#include "winreg.h"
 #include "wine/debug.h"
 #include "wine/unicode.h"
 #include "msipriv.h"
@@ -318,20 +319,250 @@ UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
     return ERROR_SUCCESS;
 }
 
+static WCHAR *build_local_assembly_path( const WCHAR *filename )
+{
+    UINT i;
+    WCHAR *ret;
+
+    if (!(ret = msi_alloc( (strlenW( filename ) + 1) * sizeof(WCHAR) )))
+        return NULL;
+
+    for (i = 0; filename[i]; i++)
+    {
+        if (filename[i] == '\\' || filename[i] == '/') ret[i] = '|';
+        else ret[i] = filename[i];
+    }
+    ret[i] = 0;
+    return ret;
+}
+
+static LONG open_assemblies_key( UINT context, BOOL win32, HKEY *hkey )
+{
+    static const WCHAR path_win32[] =
+        {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+          'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
+    static const WCHAR path_dotnet[] =
+        {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+         'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
+    static const WCHAR classes_path_win32[] =
+        {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0};
+    static const WCHAR classes_path_dotnet[] =
+        {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0};
+    HKEY root;
+    const WCHAR *path;
+
+    if (context == MSIINSTALLCONTEXT_MACHINE)
+    {
+        root = HKEY_CLASSES_ROOT;
+        if (win32) path = classes_path_win32;
+        else path = classes_path_dotnet;
+    }
+    else
+    {
+        root = HKEY_CURRENT_USER;
+        if (win32) path = path_win32;
+        else path = path_dotnet;
+    }
+    return RegCreateKeyW( root, path, hkey );
+}
+
+static LONG open_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename, HKEY *hkey )
+{
+    LONG res;
+    HKEY root;
+    WCHAR *path;
+
+    if (!(path = build_local_assembly_path( filename )))
+        return ERROR_OUTOFMEMORY;
+
+    if ((res = open_assemblies_key( context, win32, &root )))
+    {
+        msi_free( path );
+        return res;
+    }
+    res = RegCreateKeyW( root, path, hkey );
+    RegCloseKey( root );
+    msi_free( path );
+    return res;
+}
+
+static LONG delete_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename )
+{
+    LONG res;
+    HKEY root;
+    WCHAR *path;
+
+    if (!(path = build_local_assembly_path( filename )))
+        return ERROR_OUTOFMEMORY;
+
+    if ((res = open_assemblies_key( context, win32, &root )))
+    {
+        msi_free( path );
+        return res;
+    }
+    res = RegDeleteKeyW( root, path );
+    RegCloseKey( root );
+    msi_free( path );
+    return res;
+}
+
+static LONG open_global_assembly_key( UINT context, BOOL win32, HKEY *hkey )
+{
+    static const WCHAR path_win32[] =
+        {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+         'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
+         'G','l','o','b','a','l',0};
+    static const WCHAR path_dotnet[] =
+        {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+         'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',
+         'G','l','o','b','a','l',0};
+    static const WCHAR classes_path_win32[] =
+        {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',
+         'G','l','o','b','a','l',0};
+    static const WCHAR classes_path_dotnet[] =
+        {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\','G','l','o','b','a','l',0};
+    HKEY root;
+    const WCHAR *path;
+
+    if (context == MSIINSTALLCONTEXT_MACHINE)
+    {
+        root = HKEY_CLASSES_ROOT;
+        if (win32) path = classes_path_win32;
+        else path = classes_path_dotnet;
+    }
+    else
+    {
+        root = HKEY_CURRENT_USER;
+        if (win32) path = path_win32;
+        else path = path_dotnet;
+    }
+    return RegCreateKeyW( root, path, hkey );
+}
+
 UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
 {
-    MSIRECORD *uirow;
     MSICOMPONENT *comp;
 
     LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
     {
-        if (!comp->assembly || !comp->Enabled)
+        LONG res;
+        HKEY hkey;
+        GUID guid;
+        DWORD size;
+        WCHAR buffer[43];
+        MSIRECORD *uirow;
+        MSIASSEMBLY *assembly = comp->assembly;
+        BOOL win32;
+
+        if (!assembly || !comp->ComponentId) continue;
+
+        if (!comp->Enabled)
+        {
+            TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
+            continue;
+        }
+
+        if (comp->ActionRequest != INSTALLSTATE_LOCAL)
+        {
+            TRACE("Component not scheduled for installation: %s\n", debugstr_w(comp->Component));
+            comp->Action = comp->Installed;
+            continue;
+        }
+        comp->Action = INSTALLSTATE_LOCAL;
+
+        TRACE("publishing %s\n", debugstr_w(comp->Component));
+
+        CLSIDFromString( package->ProductCode, &guid );
+        encode_base85_guid( &guid, buffer );
+        buffer[20] = '>';
+        CLSIDFromString( comp->ComponentId, &guid );
+        encode_base85_guid( &guid, buffer + 21 );
+        buffer[42] = 0;
+
+        win32 = assembly->attributes & msidbAssemblyAttributesWin32;
+        if (assembly->application)
+        {
+            MSIFILE *file = get_loaded_file( package, assembly->application );
+            if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey )))
+            {
+                WARN("failed to open local assembly key %d\n", res);
+                return ERROR_FUNCTION_FAILED;
+            }
+        }
+        else
+        {
+            if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
+            {
+                WARN("failed to open global assembly key %d\n", res);
+                return ERROR_FUNCTION_FAILED;
+            }
+        }
+        size = sizeof(buffer);
+        if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size )))
+        {
+            WARN("failed to set assembly value %d\n", res);
+        }
+        RegCloseKey( hkey );
+
+        uirow = MSI_CreateRecord( 2 );
+        MSI_RecordSetStringW( uirow, 2, assembly->display_name );
+        ui_actiondata( package, szMsiPublishAssemblies, uirow );
+        msiobj_release( &uirow->hdr );
+    }
+    return ERROR_SUCCESS;
+}
+
+UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
+{
+    MSICOMPONENT *comp;
+
+    LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
+    {
+        LONG res;
+        MSIRECORD *uirow;
+        MSIASSEMBLY *assembly = comp->assembly;
+        BOOL win32;
+
+        if (!assembly || !comp->ComponentId) continue;
+
+        if (!comp->Enabled)
+        {
+            TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
             continue;
+        }
+
+        if (comp->ActionRequest != INSTALLSTATE_ABSENT)
+        {
+            TRACE("Component not scheduled for removal: %s\n", debugstr_w(comp->Component));
+            comp->Action = comp->Installed;
+            continue;
+        }
+        comp->Action = INSTALLSTATE_ABSENT;
 
-        /* FIXME: write assembly registry values */
+        TRACE("unpublishing %s\n", debugstr_w(comp->Component));
+
+        win32 = assembly->attributes & msidbAssemblyAttributesWin32;
+        if (assembly->application)
+        {
+            MSIFILE *file = get_loaded_file( package, assembly->application );
+            if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath )))
+                WARN("failed to delete local assembly key %d\n", res);
+        }
+        else
+        {
+            HKEY hkey;
+            if ((res = open_global_assembly_key( package->Context, win32, &hkey )))
+                WARN("failed to delete global assembly key %d\n", res);
+            else
+            {
+                if ((res = RegDeleteValueW( hkey, assembly->display_name )))
+                    WARN("failed to delete global assembly value %d\n", res);
+                RegCloseKey( hkey );
+            }
+        }
 
         uirow = MSI_CreateRecord( 2 );
-        MSI_RecordSetStringW( uirow, 2, comp->assembly->display_name );
+        MSI_RecordSetStringW( uirow, 2, assembly->display_name );
         ui_actiondata( package, szMsiPublishAssemblies, uirow );
         msiobj_release( &uirow->hdr );
     }
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index b9eb3ea..0f5a33c 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -922,6 +922,7 @@ extern UINT ACTION_UnregisterFonts(MSIPACKAGE *package);
 extern UINT ACTION_UnregisterMIMEInfo(MSIPACKAGE *package);
 extern UINT ACTION_UnregisterProgIdInfo(MSIPACKAGE *package);
 extern UINT ACTION_MsiPublishAssemblies(MSIPACKAGE *package);
+extern UINT ACTION_MsiUnpublishAssemblies(MSIPACKAGE *package);
 
 /* Helpers */
 extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
diff --git a/dlls/msi/tests/action.c b/dlls/msi/tests/action.c
index d018439..9d90b42 100644
--- a/dlls/msi/tests/action.c
+++ b/dlls/msi/tests/action.c
@@ -5903,7 +5903,6 @@ static void test_publish_assemblies(void)
     }
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
 
-    todo_wine {
     res = RegOpenKeyA(HKEY_CURRENT_USER, path_dotnet, &hkey);
     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
     CHECK_REG_STR(hkey, name_dotnet, "rcHQPHq?CA at Uv-XqMI1e>Z'q,T*76M@=YEg6My?~]");
@@ -5925,7 +5924,6 @@ static void test_publish_assemblies(void)
     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
     CHECK_REG_STR(hkey, name_win32_local, "rcHQPHq?CA at Uv-XqMI1e>C)Uvlj*53A)u(QQ9=)X!");
     RegCloseKey(hkey);
-    }
 
     r = MsiInstallProductA(msifile, "REMOVE=ALL");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
@@ -5959,7 +5957,6 @@ static void test_publish_assemblies(void)
     r = MsiInstallProductA(msifile, "ALLUSERS=1");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
 
-    todo_wine {
     res = RegOpenKeyA(HKEY_CLASSES_ROOT, classes_path_dotnet, &hkey);
     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
     CHECK_REG_STR(hkey, name_dotnet, "rcHQPHq?CA at Uv-XqMI1e>Z'q,T*76M@=YEg6My?~]");
@@ -5981,9 +5978,8 @@ static void test_publish_assemblies(void)
     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
     CHECK_REG_STR(hkey, name_win32_local, "rcHQPHq?CA at Uv-XqMI1e>C)Uvlj*53A)u(QQ9=)X!");
     RegCloseKey(hkey);
-    }
 
-    r = MsiInstallProductA(msifile, "REMOVE=ALL");
+    r = MsiInstallProductA(msifile, "REMOVE=ALL ALLUSERS=1");
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
 
     res = RegOpenKeyA(HKEY_CLASSES_ROOT, classes_path_dotnet, &hkey);
-- 
1.7.1






More information about the wine-patches mailing list