From: Ratchanan Srirattanamet peathot+winehq@hotmail.com
For some reason, MsiEnumFeaturesW() still look for the list of features in the registry key which Wine itself has not been writing to since commit af56e28f ("msi: Don't publish features to an invalid location."), authored in 2008. Make it look in the new registry location which is used by ACTION_PublishFeatures().
While we're at it, remove the helper function used only by MsiEnumFeaturesW().
A conformance test is added. --- dlls/msi/registry.c | 22 +++------- dlls/msi/tests/msi.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 16 deletions(-)
diff --git a/dlls/msi/registry.c b/dlls/msi/registry.c index ad220eaa756..4f49284cb6a 100644 --- a/dlls/msi/registry.c +++ b/dlls/msi/registry.c @@ -454,21 +454,6 @@ UINT MSIREG_DeleteUserFeaturesKey(LPCWSTR szProduct) return RegDeleteTreeW(HKEY_CURRENT_USER, keypath); }
-static UINT MSIREG_OpenInstallerFeaturesKey(LPCWSTR szProduct, HKEY *key, BOOL create) -{ - REGSAM access = KEY_WOW64_64KEY | KEY_ALL_ACCESS; - WCHAR squashed_pc[SQUASHED_GUID_SIZE], keypath[0x200]; - - if (!squash_guid( szProduct, squashed_pc )) return ERROR_FUNCTION_FAILED; - TRACE("%s squashed %s\n", debugstr_w(szProduct), debugstr_w(squashed_pc)); - - lstrcpyW(keypath, L"Software\Microsoft\Windows\CurrentVersion\Installer\Features\"); - lstrcatW( keypath, squashed_pc ); - - if (create) return RegCreateKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, key, NULL); - return RegOpenKeyExW(HKEY_LOCAL_MACHINE, keypath, 0, access, key); -} - UINT MSIREG_OpenUserDataFeaturesKey(LPCWSTR szProduct, LPCWSTR szUserSid, MSIINSTALLCONTEXT context, HKEY *key, BOOL create) { @@ -1079,13 +1064,18 @@ UINT WINAPI MsiEnumFeaturesW( const WCHAR *szProduct, DWORD index, WCHAR *szFeat { HKEY hkeyProduct = 0; DWORD r, sz; + MSIINSTALLCONTEXT context;
TRACE( "%s, %lu, %p, %p\n", debugstr_w(szProduct), index, szFeature, szParent );
if( !szProduct ) return ERROR_INVALID_PARAMETER;
- r = MSIREG_OpenInstallerFeaturesKey(szProduct,&hkeyProduct,FALSE); + r = msi_locate_product(szProduct, &context); + if ( r != ERROR_SUCCESS ) + return r; + + r = MSIREG_OpenUserDataFeaturesKey(szProduct, NULL, context, &hkeyProduct, FALSE); if( r != ERROR_SUCCESS ) return ERROR_NO_MORE_ITEMS;
diff --git a/dlls/msi/tests/msi.c b/dlls/msi/tests/msi.c index a0ae814b7bb..1cf6887e444 100644 --- a/dlls/msi/tests/msi.c +++ b/dlls/msi/tests/msi.c @@ -12257,6 +12257,100 @@ done: LocalFree( usersid ); }
+static void test_MsiEnumFeatures(void) +{ + UINT r; + BOOL found1, found2; + DWORD index; + WCHAR feature[MAX_FEATURE_CHARS+1], feature_parent[MAX_FEATURE_CHARS+1]; + + if (!is_process_elevated()) + { + skip("process is limited\n"); + return; + } + create_test_files(); + create_database( msifile, tables, ARRAY_SIZE( tables )); + + 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); + + found1 = FALSE; + found2 = FALSE; + index = 0; + + while (!MsiEnumFeaturesW(L"{38847338-1BBC-4104-81AC-2FAAC7ECDDCD}", index, feature, feature_parent)) + { + if (!lstrcmpW(feature, L"One")) + { + ok(!found1, "Feature 'One' found more than once\n"); + found1 = TRUE; + } + else if (!lstrcmpW(feature, L"Two")) + { + ok(!found2, "Feature 'Two' found more than once\n"); + found2 = TRUE; + } + else + { + ok(FALSE, "Unexpected feature '%ls' found\n", feature); + } + + index++; + } + ok(found1 && found2, "found1 = %c, found2 = %c\n", + found1 ? 'T' : 'F', found2 ? 'T' : 'F'); + + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + r = MsiInstallProductA(msifile, "ALLUSERS=1"); + 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); + + found1 = FALSE; + found2 = FALSE; + index = 0; + + while (!MsiEnumFeaturesW(L"{38847338-1BBC-4104-81AC-2FAAC7ECDDCD}", index, feature, feature_parent)) + { + if (!lstrcmpW(feature, L"One")) + { + ok(!found1, "Feature 'One' found more than once\n"); + found1 = TRUE; + } + else if (!lstrcmpW(feature, L"Two")) + { + ok(!found2, "Feature 'Two' found more than once\n"); + found2 = TRUE; + } + else + { + ok(FALSE, "Unexpected feature '%ls' found\n", feature); + } + + index++; + } + ok(found1 && found2, "found1 = %c, found2 = %c\n", + found1 ? 'T' : 'F', found2 ? 'T' : 'F'); + + r = MsiInstallProductA(msifile, "REMOVE=ALL ALLUSERS=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + +error: + delete_test_files(); + DeleteFileA(msifile); +} + static void test_MsiEnumComponents(void) { UINT r; @@ -13460,6 +13554,7 @@ START_TEST(msi) test_MsiGetPatchInfo(); test_MsiEnumProducts(); test_MsiEnumProductsEx(); + test_MsiEnumFeatures(); test_MsiEnumComponents(); test_MsiEnumComponentsEx(); test_MsiGetFileVersion();