From 1ee3be6e8092af933d5a4e09fc3503fc1bea4001 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Tue, 11 Sep 2012 16:20:59 +0200 Subject: [PATCH] msi: Only remove a component if the number of clients drops to zero. --- dlls/msi/action.c | 47 ++++++++++++++++++++++++++++++++++++++++------ dlls/msi/msipriv.h | 1 + 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/dlls/msi/action.c b/dlls/msi/action.c index f8745285cf7..845a0fd831c 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -809,6 +809,11 @@ INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp ) return INSTALLSTATE_UNKNOWN; } if (package->need_rollback) return comp->Installed; + if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT) + { + TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients); + return comp->Installed; + } return comp->ActionRequest; } @@ -1620,6 +1625,27 @@ static UINT ACTION_FileCost(MSIPACKAGE *package) return ERROR_SUCCESS; } +static void get_client_counts( MSIPACKAGE *package ) +{ + MSICOMPONENT *comp; + HKEY hkey; + + LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) + { + if (!comp->ComponentId) continue; + + if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, szLocalSid, &hkey, FALSE ) && + MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE )) + { + comp->num_clients = 0; + continue; + } + RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients, + NULL, NULL, NULL, NULL ); + RegCloseKey( hkey ); + } +} + static void ACTION_GetComponentInstallStates(MSIPACKAGE *package) { MSICOMPONENT *comp; @@ -1983,6 +2009,11 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) TRACE("component %s (installed %d request %d action %d)\n", debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action); + + if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE) + component->num_clients++; + else if (component->Action == INSTALLSTATE_ABSENT) + component->num_clients--; } return ERROR_SUCCESS; @@ -2368,6 +2399,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) else comp->Enabled = TRUE; } + get_client_counts( package ); /* read components states from the registry */ ACTION_GetComponentInstallStates(package); @@ -3307,9 +3339,9 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) if (package->need_rollback) action = comp->Installed; else action = comp->ActionRequest; - TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n", + TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n", debugstr_w(comp->Component), debugstr_w(squished_cc), - debugstr_w(comp->FullKeypath), comp->RefCount, action); + debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action); if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE) { @@ -3372,10 +3404,13 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) } else if (action == INSTALLSTATE_ABSENT) { - if (package->Context == MSIINSTALLCONTEXT_MACHINE) - MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid); - else - MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL); + if (comp->num_clients <= 0) + { + if (package->Context == MSIINSTALLCONTEXT_MACHINE) + MSIREG_DeleteUserDataComponentKey( comp->ComponentId, szLocalSid ); + else + MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL ); + } } /* UI stuff */ diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 43ac194f98e..73bccecd94f 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -481,6 +481,7 @@ typedef struct tagMSICOMPONENT LPWSTR FullKeypath; LPWSTR AdvertiseString; MSIASSEMBLY *assembly; + int num_clients; unsigned int anyAbsent:1; unsigned int hasAdvertiseFeature:1;