diff --git a/rostests/winetests/msi/action.c b/rostests/winetests/msi/action.c index c281d3b06e8..11e244c6e22 100644 --- a/rostests/winetests/msi/action.c +++ b/rostests/winetests/msi/action.c @@ -227,7 +227,7 @@ static const char service_install_dat[] = "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n" "ServiceInstall\tServiceInstall\n" "TestService\t[SERVNAME]\t[SERVDISP]\t2\t3\t0\t\tservice1[~]+group1[~]service2[~]+group2[~][~]\tTestService\t\t-a arg\tservice_comp\tdescription\n" - "TestService2\tSERVNAME2]\t[SERVDISP2]\t2\t3\t0\t\tservice1[~]+group1[~]service2[~]+group2[~][~]\tTestService2\t\t-a arg\tservice_comp2\tdescription"; + "TestService2\t[SERVNAME2]\t[SERVDISP2]\t2\t3\t0\t\tservice1[~]+group1[~]service2[~]+group2[~][~]\tTestService2\t\t-a arg\tservice_comp2\tdescription\n"; static const char service_install2_dat[] = "ServiceInstall\tName\tDisplayName\tServiceType\tStartType\tErrorControl\t" @@ -5427,28 +5427,23 @@ static void test_start_stop_services(void) DeleteFileA(msifile); } -static void delete_TestService(void) +static void delete_test_service(const char *name) { BOOL ret; SC_HANDLE manager, service; manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS); ok(manager != NULL, "can't open service manager\n"); - if (!manager) - return; - - service = OpenServiceA(manager, "TestService", GENERIC_ALL); - ok(service != NULL, "TestService doesn't exist\n"); + if (!manager) return; + service = OpenServiceA(manager, name, GENERIC_ALL); if (service) { ret = DeleteService( service ); ok( ret, "failed to delete service %u\n", GetLastError() ); - CloseServiceHandle(service); } CloseServiceHandle(manager); - } static void test_delete_services(void) @@ -5473,7 +5468,7 @@ static void test_delete_services(void) ok(service != NULL, "can't create service %u\n", GetLastError()); CloseServiceHandle(service); CloseServiceHandle(manager); - if (!service) goto error; + if (!service) return; create_test_files(); create_database(msifile, sds_tables, sizeof(sds_tables) / sizeof(msi_table)); @@ -5516,7 +5511,9 @@ static void test_delete_services(void) ok(delete_pf("msitest", FALSE), "Directory not created\n"); error: - delete_TestService(); + delete_test_service("TestService"); + delete_test_service("TestService2"); + delete_test_service("TestService3"); delete_test_files(); DeleteFileA(msifile); } @@ -5558,7 +5555,6 @@ static void test_install_services(void) service = OpenServiceA(manager, "TestService4", GENERIC_ALL); ok(service == NULL, "TestService4 installed\n"); - CloseServiceHandle(manager); res = RegOpenKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\TestService", &hKey); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); @@ -5576,6 +5572,11 @@ static void test_install_services(void) r = MsiInstallProductA(msifile, "REMOVE=ALL"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + service = OpenServiceA(manager, "TestService", GENERIC_ALL); + ok(service != NULL, "TestService deleted\n"); + CloseServiceHandle(service); + CloseServiceHandle(manager); + ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n"); ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); @@ -5591,7 +5592,7 @@ static void test_install_services(void) ok(delete_pf("msitest", FALSE), "Directory not created\n"); error: - delete_TestService(); + delete_test_service("TestService"); delete_test_files(); DeleteFileA(msifile); } diff --git a/rostests/winetests/msi/db.c b/rostests/winetests/msi/db.c index 9c1fcbad391..278b45f9580 100644 --- a/rostests/winetests/msi/db.c +++ b/rostests/winetests/msi/db.c @@ -470,6 +470,7 @@ static void test_msidecomposedesc(void) /* test a valid feature descriptor */ desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk."; len = 0; + prod[0] = feature[0] = comp[0] = 0; r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len); ok(r == ERROR_SUCCESS, "returned an error\n"); ok(len == strlen(desc), "length was wrong\n"); @@ -485,6 +486,28 @@ static void test_msidecomposedesc(void) r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len); ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n"); + /* test a feature descriptor with < instead of > */ + desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit<3w2x^IGfe?CxI5heAvk."; + len = 0; + prod[0] = feature[0] = 0; + comp[0] = 0x55; + r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len); + ok(r == ERROR_SUCCESS, "returned an error\n"); + ok(len == 41, "got %u\n", len); + ok(!strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}"), "got '%s'\n", prod); + ok(!strcmp(feature,"FollowTheWhiteRabbit"), "got '%s'\n", feature); + ok(!comp[0], "got '%s'\n", comp); + + len = 0; + prod[0] = feature[0] = 0; + comp[0] = 0x55; + r = pMsiDecomposeDescriptorA("yh1BVN)8A$!!!!!MKKSkAlwaysInstalledIntl_1033<", prod, feature, comp, &len); + ok(r == ERROR_SUCCESS, "got %u\n", r); + ok(len == 45, "got %u\n", len); + ok(!strcmp(prod, "{90150000-006E-0409-0000-0000000FF1CE}"), "got '%s'\n", prod); + ok(!strcmp(feature, "AlwaysInstalledIntl_1033"), "got '%s'\n", feature); + ok(!comp[0], "got '%s'\n", comp); + /* * Test a valid feature descriptor with the * maximum number of characters and some trailing characters. diff --git a/rostests/winetests/msi/install.c b/rostests/winetests/msi/install.c index edf92f6925c..fe809682d24 100644 --- a/rostests/winetests/msi/install.c +++ b/rostests/winetests/msi/install.c @@ -5886,6 +5886,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; @@ -5972,6 +6023,7 @@ START_TEST(install) test_mixed_package(); test_volume_props(); test_shared_component(); + test_remove_upgrade_code(); DeleteFileA(log_file); diff --git a/rostests/winetests/msi/msi.c b/rostests/winetests/msi/msi.c index be9d6d8265c..f0bb461fd75 100644 --- a/rostests/winetests/msi/msi.c +++ b/rostests/winetests/msi/msi.c @@ -557,6 +557,18 @@ static const char property_dat[] = "UpgradeCode\t{9574448F-9B86-4E07-B6F6-8D199DA12127}\n" "MSIFASTINSTALL\t1\n"; +static const char ci2_property_dat[] = + "Property\tValue\n" + "s72\tl0\n" + "Property\tProperty\n" + "INSTALLLEVEL\t3\n" + "Manufacturer\tWine\n" + "ProductCode\t{FF4AFE9C-6AC2-44F9-A060-9EA6BD16C75E}\n" + "ProductName\tMSITEST2\n" + "ProductVersion\t1.1.1\n" + "UpgradeCode\t{6B60C3CA-B8CA-4FB7-A395-092D98FF5D2A}\n" + "MSIFASTINSTALL\t1\n"; + static const char mcp_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" "s72\tS38\ts72\ti2\tS255\tS72\n" @@ -828,22 +840,26 @@ static const char ci_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" "s72\tS255\tI2\n" "InstallExecuteSequence\tAction\n" - "CostFinalize\t\t1000\n" "CostInitialize\t\t800\n" "FileCost\t\t900\n" - "InstallFiles\t\t4000\n" - "InstallServices\t\t5000\n" - "InstallFinalize\t\t6600\n" - "InstallInitialize\t\t1500\n" - "RunInstall\t\t1600\n" + "CostFinalize\t\t1000\n" "InstallValidate\t\t1400\n" - "LaunchConditions\t\t100"; + "InstallInitialize\t\t1500\n" + "RunInstall\tnot Installed\t1550\n" + "ProcessComponents\t\t1600\n" + "UnpublishFeatures\t\t1800\n" + "RemoveFiles\t\t3500\n" + "InstallFiles\t\t4000\n" + "RegisterProduct\t\t6100\n" + "PublishFeatures\t\t6300\n" + "PublishProduct\t\t6400\n" + "InstallFinalize\t\t6600\n"; static const char ci_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n" "s72\ti2\tS64\tS0\tS255\n" "CustomAction\tAction\n" - "RunInstall\t87\tmsitest\\concurrent.msi\tMYPROP=[UILevel]\t\n"; + "RunInstall\t23\tmsitest\\concurrent.msi\tMYPROP=[UILevel]\t\n"; static const char ci_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" @@ -1009,7 +1025,7 @@ static const msi_table ci2_tables[] = ADD_TABLE(ci2_file), ADD_TABLE(install_exec_seq), ADD_TABLE(lus0_media), - ADD_TABLE(property), + ADD_TABLE(ci2_property), }; static const msi_table cl_tables[] = @@ -3505,6 +3521,146 @@ static void test_MsiProvideComponent(void) DeleteFileA(msifile); } +static void test_MsiProvideQualifiedComponentEx(void) +{ + UINT r; + INSTALLSTATE state; + char comp[39], comp_squashed[33], comp2[39], comp2_base85[21], comp2_squashed[33]; + char prod[39], prod_base85[21], prod_squashed[33]; + char desc[MAX_PATH], buf[MAX_PATH], keypath[MAX_PATH], path[MAX_PATH]; + DWORD len = sizeof(buf); + REGSAM access = KEY_ALL_ACCESS; + HKEY hkey, hkey2, hkey3, hkey4, hkey5; + LONG res; + + if (is_process_limited()) + { + skip( "process is limited\n" ); + return; + } + + create_test_guid( comp, comp_squashed ); + compose_base85_guid( comp2, comp2_base85, comp2_squashed ); + compose_base85_guid( prod, prod_base85, prod_squashed ); + + r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len ); + ok( r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r ); + + lstrcpyA( keypath, "Software\\Classes\\Installer\\Components\\" ); + lstrcatA( keypath, comp_squashed ); + + if (is_wow64) access |= KEY_WOW64_64KEY; + res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &hkey, NULL ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + lstrcpyA( desc, prod_base85 ); + memcpy( desc + lstrlenA(desc), "feature<\0", sizeof("feature<\0") ); + res = RegSetValueExA( hkey, "qualifier", 0, REG_MULTI_SZ, (const BYTE *)desc, + lstrlenA(prod_base85) + sizeof("feature<\0") ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len ); + ok( r == ERROR_UNKNOWN_PRODUCT, "got %u\n", r ); + + r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, NULL, 0, 0, buf, &len ); + ok( r == ERROR_UNKNOWN_PRODUCT, "got %u\n", r ); + + state = MsiQueryProductStateA( prod ); + ok( state == INSTALLSTATE_UNKNOWN, "got %d\n", state ); + + lstrcpyA( keypath, "Software\\Classes\\Installer\\Products\\" ); + lstrcatA( keypath, prod_squashed ); + + res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &hkey2, NULL ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + state = MsiQueryProductStateA( prod ); + ok( state == INSTALLSTATE_ADVERTISED, "got %d\n", state ); + + r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len ); + todo_wine ok( r == ERROR_UNKNOWN_FEATURE, "got %u\n", r ); + + lstrcpyA( keypath, "Software\\Classes\\Installer\\Features\\" ); + lstrcatA( keypath, prod_squashed ); + + res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &hkey3, NULL ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + state = MsiQueryFeatureStateA( prod, "feature" ); + ok( state == INSTALLSTATE_UNKNOWN, "got %d\n", state ); + + res = RegSetValueExA( hkey3, "feature", 0, REG_SZ, (const BYTE *)"", 1 ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + state = MsiQueryFeatureStateA( prod, "feature" ); + ok( state == INSTALLSTATE_ADVERTISED, "got %d\n", state ); + + r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len ); + ok( r == ERROR_FILE_NOT_FOUND, "got %u\n", r ); + + len = sizeof(buf); + r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, NULL, 0, 0, buf, &len ); + ok( r == ERROR_FILE_NOT_FOUND, "got %u\n", r ); + + lstrcpyA( keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Products\\" ); + lstrcatA( keypath, prod_squashed ); + lstrcatA( keypath, "\\Features" ); + + res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &hkey4, NULL ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + res = RegSetValueExA( hkey4, "feature", 0, REG_SZ, (const BYTE *)comp2_base85, sizeof(comp2_base85) ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + state = MsiQueryFeatureStateA( prod, "feature" ); + ok( state == INSTALLSTATE_ADVERTISED, "got %d\n", state ); + + lstrcpyA( keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Components\\" ); + lstrcatA( keypath, comp2_squashed ); + + res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, keypath, 0, NULL, 0, access, NULL, &hkey5, NULL ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + res = RegSetValueExA( hkey5, prod_squashed, 0, REG_SZ, (const BYTE *)"c:\\nosuchfile", sizeof("c:\\nosuchfile") ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + state = MsiQueryFeatureStateA( prod, "feature" ); + ok( state == INSTALLSTATE_LOCAL, "got %d\n", state ); + + r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len ); + ok( r == ERROR_FILE_NOT_FOUND, "got %u\n", r ); + + GetCurrentDirectoryA( MAX_PATH, path ); + lstrcatA( path, "\\msitest" ); + CreateDirectoryA( path, NULL ); + lstrcatA( path, "\\test.txt" ); + create_file( path, "test", 100 ); + + res = RegSetValueExA( hkey5, prod_squashed, 0, REG_SZ, (const BYTE *)path, lstrlenA(path) + 1 ); + ok( res == ERROR_SUCCESS, "got %d\n", res ); + + buf[0] = 0; + len = sizeof(buf); + r = MsiProvideQualifiedComponentExA( comp, "qualifier", INSTALLMODE_EXISTING, prod, 0, 0, buf, &len ); + ok( r == ERROR_SUCCESS, "got %u\n", r ); + ok( len == lstrlenA(path), "got %u\n", len ); + ok( !lstrcmpA( path, buf ), "got '%s'\n", buf ); + + DeleteFileA( "msitest\\text.txt" ); + RemoveDirectoryA( "msitest" ); + + delete_key( hkey5, "", access & KEY_WOW64_64KEY ); + RegCloseKey( hkey5 ); + delete_key( hkey4, "", access & KEY_WOW64_64KEY ); + RegCloseKey( hkey4 ); + delete_key( hkey3, "", access & KEY_WOW64_64KEY ); + RegCloseKey( hkey3 ); + delete_key( hkey2, "", access & KEY_WOW64_64KEY ); + RegCloseKey( hkey2 ); + delete_key( hkey, "", access & KEY_WOW64_64KEY ); + RegCloseKey( hkey ); +} + static void test_MsiGetProductCode(void) { HKEY compkey, prodkey; @@ -14181,22 +14337,23 @@ static void test_concurrentinstall(void) if (r == ERROR_INSTALL_PACKAGE_REJECTED) { skip("Not enough rights to perform tests\n"); - DeleteFileA(path); goto error; } ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); - if (!delete_pf("msitest\\augustus", TRUE)) - trace("concurrent installs not supported\n"); + ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n"); ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); ok(delete_pf("msitest", FALSE), "Directory not created\n"); r = MsiConfigureProductA("{38847338-1BBC-4104-81AC-2FAAC7ECDDCD}", INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(r == ERROR_SUCCESS, "got %u\n", r); - DeleteFileA(path); + r = MsiConfigureProductA("{FF4AFE9C-6AC2-44F9-A060-9EA6BD16C75E}", INSTALLLEVEL_DEFAULT, + INSTALLSTATE_ABSENT); + ok(r == ERROR_SUCCESS, "got %u\n", r); error: + DeleteFileA(path); DeleteFileA(msifile); DeleteFileA("msitest\\msitest\\augustus"); DeleteFileA("msitest\\maximus"); @@ -14437,6 +14594,7 @@ START_TEST(msi) if (pMsiGetComponentPathExA) test_concurrentinstall(); test_command_line_parsing(); + test_MsiProvideQualifiedComponentEx(); SetCurrentDirectoryA(prev_path); }