diff --git a/dlls/msi/action.c b/dlls/msi/action.c index c0ab23d872f..0fe7d385643 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -7103,8 +7103,8 @@ static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param ) { MSIPACKAGE *package = param; LPCWSTR name, value, component; - LPWSTR deformatted = NULL; - DWORD flags; + WCHAR *p, *q, *deformatted = NULL, *new_value = NULL; + DWORD flags, type, size, len, len_value = 0, len_new_value; HKEY env; MSICOMPONENT *comp; MSIRECORD *uirow; @@ -7141,7 +7141,20 @@ static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param ) if (value && !deformat_string( package, value, &deformatted )) return ERROR_OUTOFMEMORY; - value = deformatted; + if ((value = deformatted)) + { + if (flags & ENV_MOD_PREFIX) + { + p = strchrW( value, ';' ); + len_value = p - value; + } + else if (flags & ENV_MOD_APPEND) + { + value = strchrW( value, ';' ) + 1; + len_value = strlenW( value ); + } + else len_value = strlenW( value ); + } r = open_env_key( flags, &env ); if (r != ERROR_SUCCESS) @@ -7153,13 +7166,48 @@ static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param ) if (flags & ENV_MOD_MACHINE) action |= 0x20000000; - TRACE("Removing %s\n", debugstr_w(name)); + size = 0; + type = REG_SZ; + res = RegQueryValueExW( env, name, NULL, &type, NULL, &size ); + if (res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) + goto done; - res = RegDeleteValueW( env, name ); + if (!(new_value = msi_alloc( size ))) goto done; + + res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)new_value, &size ); if (res != ERROR_SUCCESS) + goto done; + + len_new_value = size / sizeof(WCHAR) - 1; + p = q = new_value; + for (;;) { - WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res); - r = ERROR_SUCCESS; + while (*q && *q != ';') q++; + len = q - p; + if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) )) + { + if (*q == ';') q++; + memmove( p, q, (len_new_value - (q - new_value) + 1) * sizeof(WCHAR) ); + break; + } + if (!*q) break; + p = ++q; + } + + if (!new_value[0] || !value) + { + TRACE("removing %s\n", debugstr_w(name)); + res = RegDeleteValueW( env, name ); + if (res != ERROR_SUCCESS) + WARN("failed to delete value %s (%d)\n", debugstr_w(name), res); + } + else + { + TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(new_value)); + size = (strlenW( new_value ) + 1) * sizeof(WCHAR); + res = RegSetValueExW( env, name, 0, type, (BYTE *)new_value, size ); + if (res != ERROR_SUCCESS) + WARN("failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(new_value), res); } done: @@ -7172,6 +7220,7 @@ done: if (env) RegCloseKey( env ); msi_free( deformatted ); + msi_free( new_value ); return r; } diff --git a/dlls/msi/tests/action.c b/dlls/msi/tests/action.c index 60562f1a729..9512410f900 100644 --- a/dlls/msi/tests/action.c +++ b/dlls/msi/tests/action.c @@ -1205,7 +1205,13 @@ static const char res_environment_dat[] = "var2\t=+-MSITESTVAR2\t1\tenvvar\n" "var3\t=MSITESTVAR3\t1\tenvvar\n" "var4\t=-MSITESTVAR4\t\tenvvar\n" - "var5\t=MSITESTVAR5\t\tenvvar\n"; + "var5\t=MSITESTVAR5\t\tenvvar\n" + "Var6\t-MSITESTVAR6\t1;[~]\tenvvar\n" + "Var7\t-MSITESTVAR7\t[~];1\tenvvar\n" + "Var8\t-MSITESTVAR8\t1;[~]\tenvvar\n" + "Var9\t-MSITESTVAR9\t[~];1\tenvvar\n" + "Var10\t-MSITESTVAR10\t1\tenvvar\n" + "Var11\t-MSITESTVAR11\t2\tenvvar\n"; static const char res_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" @@ -6192,6 +6198,12 @@ static void test_remove_env_strings(void) RegSetValueExA(key, "MSITESTVAR3", 0, REG_SZ, (const BYTE *)"1", 2); RegSetValueExA(key, "MSITESTVAR4", 0, REG_SZ, (const BYTE *)"1", 2); RegSetValueExA(key, "MSITESTVAR5", 0, REG_SZ, (const BYTE *)"1", 2); + RegSetValueExA(key, "MSITESTVAR6", 0, REG_SZ, (const BYTE *)"1;2", 4); + RegSetValueExA(key, "MSITESTVAR7", 0, REG_SZ, (const BYTE *)"1;2", 4); + RegSetValueExA(key, "MSITESTVAR8", 0, REG_SZ, (const BYTE *)"2;1;0", 6); + RegSetValueExA(key, "MSITESTVAR9", 0, REG_SZ, (const BYTE *)"0;1;2", 6); + RegSetValueExA(key, "MSITESTVAR10", 0, REG_SZ, (const BYTE *)"1", 2); + RegSetValueExA(key, "MSITESTVAR11", 0, REG_SZ, (const BYTE *)"1", 2); RegCloseKey(key); @@ -6281,6 +6293,57 @@ static void test_remove_env_strings(void) ok(!lstrcmpA(buffer, "1"), "expected \"1\", got \"%s\"\n", buffer); RegDeleteValueA(key, "MSITESTVAR5"); + type = REG_NONE; + buffer[0] = 0; + size = sizeof(buffer); + res = RegQueryValueExA(key, "MSITESTVAR6", NULL, &type, (LPBYTE)buffer, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(type == REG_SZ, "expected REG_SZ, got %u\n", type); + ok(!lstrcmpA(buffer, "2"), "expected \"2\", got \"%s\"\n", buffer); + RegDeleteValueA(key, "MSITESTVAR6"); + + type = REG_NONE; + buffer[0] = 0; + size = sizeof(buffer); + res = RegQueryValueExA(key, "MSITESTVAR7", NULL, &type, (LPBYTE)buffer, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(type == REG_SZ, "expected REG_SZ, got %u\n", type); + ok(!lstrcmpA(buffer, "2"), "expected \"2\", got \"%s\"\n", buffer); + RegDeleteValueA(key, "MSITESTVAR7"); + + type = REG_NONE; + buffer[0] = 0; + size = sizeof(buffer); + res = RegQueryValueExA(key, "MSITESTVAR8", NULL, &type, (LPBYTE)buffer, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(type == REG_SZ, "expected REG_SZ, got %u\n", type); + ok(!lstrcmpA(buffer, "2;0"), "expected \"2;0\", got \"%s\"\n", buffer); + RegDeleteValueA(key, "MSITESTVAR8"); + + type = REG_NONE; + buffer[0] = 0; + size = sizeof(buffer); + res = RegQueryValueExA(key, "MSITESTVAR9", NULL, &type, (LPBYTE)buffer, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(type == REG_SZ, "expected REG_SZ, got %u\n", type); + ok(!lstrcmpA(buffer, "0;2"), "expected \"0;2\", got \"%s\"\n", buffer); + RegDeleteValueA(key, "MSITESTVAR9"); + + type = REG_NONE; + buffer[0] = 0; + size = sizeof(buffer); + res = RegQueryValueExA(key, "MSITESTVAR10", NULL, &type, (LPBYTE)buffer, &size); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + type = REG_NONE; + buffer[0] = 0; + size = sizeof(buffer); + res = RegQueryValueExA(key, "MSITESTVAR11", NULL, &type, (LPBYTE)buffer, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(type == REG_SZ, "expected REG_SZ, got %u\n", type); + ok(!lstrcmpA(buffer, "1"), "expected \"1\", got \"%s\"\n", buffer); + RegDeleteValueA(key, "MSITESTVAR11"); + ok(!delete_pf("msitest\\envvar.txt", TRUE), "file not removed\n"); ok(!delete_pf("msitest", FALSE), "directory not removed\n"); @@ -6290,6 +6353,12 @@ error: RegDeleteValueA(key, "MSITESTVAR3"); RegDeleteValueA(key, "MSITESTVAR4"); RegDeleteValueA(key, "MSITESTVAR5"); + RegDeleteValueA(key, "MSITESTVAR6"); + RegDeleteValueA(key, "MSITESTVAR7"); + RegDeleteValueA(key, "MSITESTVAR8"); + RegDeleteValueA(key, "MSITESTVAR9"); + RegDeleteValueA(key, "MSITESTVAR10"); + RegDeleteValueA(key, "MSITESTVAR11"); RegCloseKey(key); DeleteFileA("msitest\\envvar.txt");