From f0ea60049c4c0a484f7006a14ca3375cb0fd9260 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Mon, 11 Jun 2012 15:36:03 +0200 Subject: [PATCH] msi: Add support for 64-bit registry components. --- dlls/msi/action.c | 30 ++++++---- dlls/msi/msi_main.c | 1 + dlls/msi/msipriv.h | 1 + dlls/msi/package.c | 2 - dlls/msi/tests/install.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 12 deletions(-) diff --git a/dlls/msi/action.c b/dlls/msi/action.c index ec008867b2d..17e86963f8d 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -2554,12 +2554,13 @@ static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key return ret; } -static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path ) +static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path ) { static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'}; static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]); - if (is_64bit && package->platform == PLATFORM_INTEL && + if ((is_64bit || is_wow64) && + !(comp->Attributes & msidbComponentAttributes64bit) && root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len )) { UINT size; @@ -2574,7 +2575,6 @@ static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path ) strcatW( path_32node, path + len ); return path_32node; } - return strdupW( path ); } @@ -2634,9 +2634,9 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) strcpyW(uikey,szRoot); strcatW(uikey,deformated); - keypath = get_keypath( package, root_key, deformated ); + keypath = get_keypath( comp, root_key, deformated ); msi_free( deformated ); - if (RegCreateKeyW( root_key, keypath, &hkey )) + if (RegCreateKeyExW( root_key, keypath, 0, NULL, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, NULL, &hkey, NULL )) { ERR("Could not create key %s\n", debugstr_w(keypath)); msi_free(uikey); @@ -2722,7 +2722,7 @@ static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *valu HKEY hkey; DWORD num_subkeys, num_values; - if (!(res = RegOpenKeyW( root, keypath, &hkey ))) + if (!(res = RegOpenKeyExW( root, keypath, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey ))) { if ((res = RegDeleteValueW( hkey, value ))) { @@ -2734,7 +2734,7 @@ static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *valu if (!res && !num_subkeys && !num_values) { TRACE("removing empty key %s\n", debugstr_w(keypath)); - RegDeleteKeyW( root, keypath ); + RegDeleteKeyExW( root, keypath, KEY_WOW64_64KEY, 0 ); } return; } @@ -2743,8 +2743,18 @@ static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *valu static void delete_reg_key( HKEY root, const WCHAR *keypath ) { - LONG res = RegDeleteTreeW( root, keypath ); + HKEY hkey; + LONG res = RegOpenKeyExW( root, keypath, 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey ); + if (res) + { + TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res); + return; + } + res = RegDeleteTreeW( hkey, NULL ); + if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(keypath), res); + res = RegDeleteKeyExW( root, keypath, KEY_WOW64_64KEY, 0 ); if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res); + RegCloseKey( hkey ); } static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param ) @@ -2800,7 +2810,7 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para deformat_string( package, name, &deformated_name ); - keypath = get_keypath( package, hkey_root, deformated_key ); + keypath = get_keypath( comp, hkey_root, deformated_key ); msi_free( deformated_key ); if (delete_key) delete_reg_key( hkey_root, keypath ); else delete_reg_value( hkey_root, keypath, deformated_name ); @@ -2865,7 +2875,7 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param deformat_string( package, name, &deformated_name ); - keypath = get_keypath( package, hkey_root, deformated_key ); + keypath = get_keypath( comp, hkey_root, deformated_key ); msi_free( deformated_key ); if (delete_key) delete_reg_key( hkey_root, keypath ); else delete_reg_value( hkey_root, keypath, deformated_name ); diff --git a/dlls/msi/msi_main.c b/dlls/msi/msi_main.c index 669d93bce3e..de0534af131 100644 --- a/dlls/msi/msi_main.c +++ b/dlls/msi/msi_main.c @@ -73,6 +73,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_ATTACH: msi_hInstance = hinstDLL; DisableThreadLibraryCalls(hinstDLL); + IsWow64Process( GetCurrentProcess(), &is_wow64 ); break; case DLL_PROCESS_DETACH: msi_dialog_unregister_class(); diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 605ee8d4b38..a0657f4ce90 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -39,6 +39,7 @@ #include "wine/debug.h" static const BOOL is_64bit = sizeof(void *) > sizeof(int); +BOOL is_wow64; #define MSI_DATASIZEMASK 0x00ff #define MSITYPE_VALID 0x0100 diff --git a/dlls/msi/package.c b/dlls/msi/package.c index b1668d3bf08..7c8b1b443fc 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -1339,7 +1339,6 @@ static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package ) static UINT validate_package( MSIPACKAGE *package ) { - BOOL is_wow64; UINT i; if (package->platform == PLATFORM_INTEL64) @@ -1348,7 +1347,6 @@ static UINT validate_package( MSIPACKAGE *package ) if (package->platform == PLATFORM_ARM) return ERROR_INSTALL_PLATFORM_UNSUPPORTED; #endif - IsWow64Process( GetCurrentProcess(), &is_wow64 ); if (package->platform == PLATFORM_X64) { if (!is_64bit && !is_wow64) diff --git a/dlls/msi/tests/install.c b/dlls/msi/tests/install.c index 8e4e4b79ecc..ad3ea66c548 100644 --- a/dlls/msi/tests/install.c +++ b/dlls/msi/tests/install.c @@ -1237,6 +1237,53 @@ static const CHAR uc_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" "PublishProduct\t\t1200\n" "InstallFinalize\t\t1300\n"; +static const char mixed_feature_dat[] = + "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n" + "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n" + "Feature\tFeature\n" + "feature1\t\t\t\t1\t2\tMSITESTDIR\t0\n" + "feature2\t\t\t\t1\t2\tMSITESTDIR\t0\n"; + +static const char mixed_feature_comp_dat[] = + "Feature_\tComponent_\n" + "s38\ts72\n" + "FeatureComponents\tFeature_\tComponent_\n" + "feature1\tcomp1\n" + "feature2\tcomp2\n"; + +static const char mixed_component_dat[] = + "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" + "s72\tS38\ts72\ti2\tS255\tS72\n" + "Component\tComponent\n" + "comp1\t{DE9F0EF4-0ED3-495A-8105-060C0EA457B8}\tTARGETDIR\t4\t\tregdata1\n" + "comp2\t{4912DBE7-FC3A-4F91-BB5C-88F5C15C19A5}\tTARGETDIR\t260\t\tregdata2\n"; + +static const char mixed_registry_dat[] = + "Registry\tRoot\tKey\tName\tValue\tComponent_\n" + "s72\ti2\tl255\tL255\tL0\ts72\n" + "Registry\tRegistry\n" + "regdata1\t2\tSOFTWARE\\Wine\\msitest\ttest1\t\tcomp1\n" + "regdata2\t2\tSOFTWARE\\Wine\\msitest\ttest2\t\tcomp2\n"; + +static const char mixed_install_exec_seq_dat[] = + "Action\tCondition\tSequence\n" + "s72\tS255\tI2\n" + "InstallExecuteSequence\tAction\n" + "LaunchConditions\t\t100\n" + "CostInitialize\t\t200\n" + "FileCost\t\t300\n" + "CostFinalize\t\t400\n" + "InstallValidate\t\t500\n" + "InstallInitialize\t\t600\n" + "ProcessComponents\t\t700\n" + "UnpublishFeatures\t\t800\n" + "RemoveRegistryValues\t\t900\n" + "WriteRegistryValues\t\t1000\n" + "RegisterProduct\t\t1100\n" + "PublishFeatures\t\t1200\n" + "PublishProduct\t\t1300\n" + "InstallFinalize\t\t1400\n"; + typedef struct _msi_table { const CHAR *filename; @@ -1928,6 +1975,18 @@ static const msi_table uc_tables[] = ADD_TABLE(uc_property) }; +static const msi_table mixed_tables[] = +{ + ADD_TABLE(directory), + ADD_TABLE(mixed_component), + ADD_TABLE(mixed_feature), + ADD_TABLE(mixed_feature_comp), + ADD_TABLE(mixed_install_exec_seq), + ADD_TABLE(mixed_registry), + ADD_TABLE(media), + ADD_TABLE(property) +}; + /* cabinet definitions */ /* make the max size large so there is only one cab file */ @@ -6618,6 +6677,86 @@ static void test_MsiSetFeatureAttributes(void) DeleteFileA( msifile ); } +static void test_mixed_package(void) +{ + UINT r; + LONG res; + HKEY hkey; + + if (is_process_limited()) + { + skip("process is limited\n"); + return; + } + if (!is_wow64 && !is_64bit) + { + skip("this test must be run on 64-bit\n"); + return; + } + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + create_database_template(msifile, mixed_tables, sizeof(mixed_tables)/sizeof(msi_table), 200, "x64;1033"); + + r = MsiInstallProductA(msifile, NULL); + if (r == ERROR_INSTALL_PACKAGE_REJECTED) + { + skip("Not enough rights to perform tests\n"); + goto error; + } + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine\\msitest", 0, KEY_ALL_ACCESS|KEY_WOW64_32KEY, &hkey); + ok(!res, "can't open 32-bit component key\n"); + res = RegQueryValueExA(hkey, "test1", NULL, NULL, NULL, NULL); + ok(!res, "value test1 not found\n"); + RegCloseKey(hkey); + + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine\\msitest", 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey); + ok(!res, "can't open 64-bit component key\n"); + res = RegQueryValueExA(hkey, "test2", NULL, NULL, NULL, NULL); + ok(!res, "value test2 not found\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\\Wine\\msitest", 0, KEY_ALL_ACCESS|KEY_WOW64_32KEY, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "32-bit component key not removed\n"); + + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine\\msitest", 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "64-bit component key not removed\n"); + + DeleteFileA( msifile ); + create_database_template(msifile, mixed_tables, sizeof(mixed_tables)/sizeof(msi_table), 200, "Intel;1033"); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine\\msitest", 0, KEY_ALL_ACCESS|KEY_WOW64_32KEY, &hkey); + ok(!res, "can't open 32-bit component key\n"); + res = RegQueryValueExA(hkey, "test1", NULL, NULL, NULL, NULL); + ok(!res, "value test1 not found\n"); + RegCloseKey(hkey); + + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine\\msitest", 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey); + ok(!res, "can't open 64-bit component key\n"); + res = RegQueryValueExA(hkey, "test2", NULL, NULL, NULL, NULL); + ok(!res, "value test2 not found\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\\Wine\\msitest", 0, KEY_ALL_ACCESS|KEY_WOW64_32KEY, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "32-bit component key not removed\n"); + + res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine\\msitest", 0, KEY_ALL_ACCESS|KEY_WOW64_64KEY, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "64-bit component key not removed\n"); + +error: + DeleteFileA( msifile ); + return; +} + START_TEST(install) { DWORD len; @@ -6709,6 +6848,7 @@ START_TEST(install) test_upgrade_code(); test_MsiGetFeatureInfo(); test_MsiSetFeatureAttributes(); + test_mixed_package(); DeleteFileA(log_file); -- 2.11.4.GIT