[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