diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 751462b2b7f..4d7e8b99fa0 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -5285,9 +5285,46 @@ static UINT msi_unpublish_icons( MSIPACKAGE *package ) return ERROR_SUCCESS; } +static void remove_product_upgrade_code( MSIPACKAGE *package ) +{ + WCHAR *code, product[SQUASHED_GUID_SIZE]; + HKEY hkey; + LONG res; + DWORD count; + + squash_guid( package->ProductCode, product ); + if (!(code = msi_dup_property( package->db, szUpgradeCode ))) + { + WARN( "upgrade code not found\n" ); + return; + } + if (!MSIREG_OpenUpgradeCodesKey( code, &hkey, FALSE )) + { + RegDeleteValueW( hkey, product ); + res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL ); + RegCloseKey( hkey ); + if (!res && !count) MSIREG_DeleteUpgradeCodesKey( code ); + } + if (!MSIREG_OpenUserUpgradeCodesKey( code, &hkey, FALSE )) + { + RegDeleteValueW( hkey, product ); + res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL ); + RegCloseKey( hkey ); + if (!res && !count) MSIREG_DeleteUserUpgradeCodesKey( code ); + } + if (!MSIREG_OpenClassesUpgradeCodesKey( code, &hkey, FALSE )) + { + RegDeleteValueW( hkey, product ); + res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL ); + RegCloseKey( hkey ); + if (!res && !count) MSIREG_DeleteClassesUpgradeCodesKey( code ); + } + + msi_free( code ); +} + static UINT ACTION_UnpublishProduct(MSIPACKAGE *package) { - WCHAR *upgrade; MSIPATCHINFO *patch; MSIREG_DeleteProductKey(package->ProductCode); @@ -5299,13 +5336,7 @@ static UINT ACTION_UnpublishProduct(MSIPACKAGE *package) MSIREG_DeleteUserProductKey(package->ProductCode); MSIREG_DeleteUserFeaturesKey(package->ProductCode); - upgrade = msi_dup_property(package->db, szUpgradeCode); - if (upgrade) - { - MSIREG_DeleteUserUpgradeCodesKey(upgrade); - MSIREG_DeleteClassesUpgradeCodesKey(upgrade); - msi_free(upgrade); - } + remove_product_upgrade_code( package ); LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry) { diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index a2939b3982c..56ba72540ae 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -919,6 +919,7 @@ extern UINT MSIREG_DeleteUserDataProductKey(LPCWSTR, MSIINSTALLCONTEXT) DECLSPEC extern UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct) DECLSPEC_HIDDEN; extern UINT MSIREG_DeleteUserDataComponentKey(LPCWSTR szComponent, LPCWSTR szUserSid) DECLSPEC_HIDDEN; extern UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode) DECLSPEC_HIDDEN; +extern UINT MSIREG_DeleteUpgradeCodesKey(const WCHAR *) DECLSPEC_HIDDEN; extern UINT MSIREG_DeleteClassesUpgradeCodesKey(LPCWSTR szUpgradeCode) DECLSPEC_HIDDEN; extern UINT MSIREG_OpenClassesUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create) DECLSPEC_HIDDEN; extern UINT MSIREG_DeleteLocalClassesProductKey(LPCWSTR szProductCode) DECLSPEC_HIDDEN; diff --git a/dlls/msi/registry.c b/dlls/msi/registry.c index 8852f57a2f0..1f87cbb5066 100644 --- a/dlls/msi/registry.c +++ b/dlls/msi/registry.c @@ -940,6 +940,18 @@ UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL creat return RegOpenKeyW(HKEY_CURRENT_USER, keypath, key); } +UINT MSIREG_DeleteUpgradeCodesKey( const WCHAR *code ) +{ + WCHAR squashed_code[SQUASHED_GUID_SIZE], keypath[0x200]; + + if (!squash_guid( code, squashed_code )) return ERROR_FUNCTION_FAILED; + TRACE( "%s squashed %s\n", debugstr_w(code), debugstr_w(squashed_code) ); + + strcpyW( keypath, szInstaller_UpgradeCodes ); + strcatW( keypath, squashed_code ); + return RegDeleteTreeW( HKEY_LOCAL_MACHINE, keypath ); +} + UINT MSIREG_DeleteUserUpgradeCodesKey(LPCWSTR szUpgradeCode) { WCHAR squashed_uc[SQUASHED_GUID_SIZE], keypath[0x200]; diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c index e1113e788d2..a3771845314 100644 --- a/dlls/msi/tests/install.c +++ b/dlls/msi/tests/install.c @@ -5888,6 +5888,57 @@ static void test_shared_component(void) DeleteFileA(msifile2); } +static void test_remove_upgrade_code(void) +{ + UINT r; + LONG res; + HKEY hkey; + REGSAM access = KEY_ALL_ACCESS; + DWORD type, size; + char buf[1]; + + if (is_process_limited()) + { + skip( "process is limited\n" ); + return; + } + if (is_wow64) access |= KEY_WOW64_64KEY; + + create_test_files(); + create_database( msifile, icon_base_tables, sizeof(icon_base_tables)/sizeof(icon_base_tables[0]) ); + + MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL ); + + r = MsiInstallProductA( msifile, "FULL=1" ); + ok(r == ERROR_SUCCESS, "got %u\n", r); + + res = RegOpenKeyExA( HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\51AAE0C44620A5E4788506E91F249BD2", + 0, access, &hkey ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + type = 0xdeadbeef; + buf[0] = 0x55; + size = sizeof(buf); + res = RegQueryValueExA( hkey, "94A88FD7F6998CE40A22FB59F6B9C2BB", NULL, &type, (BYTE *)buf, &size ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + ok( type == REG_SZ, "got %u\n", type ); + ok( size == 1, "got %u\n", size ); + ok( !buf[0], "wrong data\n" ); + RegCloseKey( hkey ); + + r = MsiInstallProductA( msifile, "REMOVE=ALL" ); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + res = RegOpenKeyExA( HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\51AAE0C44620A5E4788506E91F249BD2", + 0, access, &hkey ); + ok( res == ERROR_FILE_NOT_FOUND, "got %d\n", res ); + + RemoveDirectoryA( "msitest" ); + DeleteFileA( msifile ); +} + START_TEST(install) { DWORD len; @@ -5974,6 +6025,7 @@ START_TEST(install) test_mixed_package(); test_volume_props(); test_shared_component(); + test_remove_upgrade_code(); DeleteFileA(log_file);