Note that the test is interactive since it requires a reboot (on windows) and a rerun on wine. AFAIK there's no way around those limitations, so this is the test I came up with.
Signed-off-by: Fabian Maurer dark.shadow4@web.de --- dlls/ntdll/tests/env.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+)
diff --git a/dlls/ntdll/tests/env.c b/dlls/ntdll/tests/env.c index 4e2ef8222d..41cb44ecd2 100644 --- a/dlls/ntdll/tests/env.c +++ b/dlls/ntdll/tests/env.c @@ -515,6 +515,59 @@ static void test_process_params(void) } }
+static BOOL setup_environment(void) +{ + HKEY key; + LSTATUS status; + LPCSTR value1 = "%WINETESTVAR2%"; + LPCSTR value2 = "test ok"; + BOOL is_ready; + const char *path = "System\CurrentControlSet\Control\Session Manager\Environment"; + status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, path, 0, KEY_ALL_ACCESS, &key); + ok(status == ERROR_SUCCESS, "RegOpenKeyExA failed with %d\n", status); + + status = RegQueryValueExA(key, "WINETESTVAR1", NULL, NULL, NULL, NULL); + ok(status == ERROR_SUCCESS || status == ERROR_FILE_NOT_FOUND, "RegQueryValueExA failed with %d\n", status); + is_ready = (status == ERROR_SUCCESS); + if (!is_ready) + { + status = RegSetValueExA(key, "WINETESTVAR1", 0, REG_EXPAND_SZ,(LPBYTE)value1, strlen(value1) + 1); + ok(status == ERROR_SUCCESS, "RegSetValueExA failed with %d\n", status); + status = RegSetValueExA(key, "WINETESTVAR2", 0, REG_EXPAND_SZ,(LPBYTE)value2, strlen(value2) + 1); + ok(status == ERROR_SUCCESS, "RegSetValueExA failed with %d\n", status); + } + RegCloseKey(key); + + return is_ready; +} + +static void test_peb_environment(void) +{ + static const WCHAR result1[] = {'W','I','N','E','T','E','S','T','V','A','R','1','=','t','e','s','t',' ','o','k',0}; + static const WCHAR result2[] = {'W','I','N','E','T','E','S','T','V','A','R','2','=','t','e','s','t',' ','o','k',0}; + BOOL found1 = FALSE; + BOOL found2 = FALSE; + BOOL is_ready = setup_environment(); + if (is_ready) + { + WCHAR *env = NtCurrentTeb()->Peb->ProcessParameters->Environment; + for (; *env; env += lstrlenW(env) + 1) + { + if (lstrcmpW(env, result1) == 0) + found1 = TRUE; + if (lstrcmpW(env, result2) == 0) + found2 = TRUE; + } + todo_wine + ok(found1, "Didn't find %s in the PEB environment variables\n", wine_dbgstr_w(result1)); + ok(found2, "Didn't find %s in the PEB environment variables\n", wine_dbgstr_w(result2)); + } + else + { + skip("Preparation finished. Restart when running windows, then rerun the test for the results.\n"); + } +} + START_TEST(env) { HMODULE mod = GetModuleHandleA("ntdll.dll"); @@ -535,4 +588,8 @@ START_TEST(env) testSet(); testExpand(); test_process_params(); + if (winetest_interactive) + { + test_peb_environment(); + } } -- 2.21.0
Signed-off-by: Fabian Maurer dark.shadow4@web.de --- dlls/kernel32/process.c | 68 +++++++++++++++++++++++++++++++---------- dlls/ntdll/tests/env.c | 1 - 2 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index 09f0433deb..0f13879c1f 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -62,6 +62,7 @@ #include "wine/server.h" #include "wine/unicode.h" #include "wine/debug.h" +#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(process); WINE_DECLARE_DEBUG_CHANNEL(relay); @@ -502,6 +503,14 @@ static BOOL build_initial_environment(void) return TRUE; }
+struct environment_variable +{ + struct list entry; + UNICODE_STRING name; + UNICODE_STRING value; + ULONG type; +}; +
/*********************************************************************** * set_registry_variables @@ -510,7 +519,7 @@ static BOOL build_initial_environment(void) * helper for set_registry_environment(). * Note that Windows happily truncates the value if it's too big. */ -static void set_registry_variables( HANDLE hkey, ULONG type ) +static void set_registry_variables( HANDLE hkey ) { static const WCHAR pathW[] = {'P','A','T','H'}; static const WCHAR sep[] = {';',0}; @@ -522,6 +531,11 @@ static void set_registry_variables( HANDLE hkey, ULONG type ) WCHAR tmpbuf[1024]; UNICODE_STRING tmp; KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer; + struct list registry_variables = LIST_INIT(registry_variables); + struct environment_variable *variable, *variable_next; + PWSTR penv = NULL; + + RtlCreateEnvironment(FALSE, &penv);
tmp.Buffer = tmpbuf; tmp.MaximumLength = sizeof(tmpbuf); @@ -532,8 +546,10 @@ static void set_registry_variables( HANDLE hkey, ULONG type ) buffer, sizeof(buffer), &size ); if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) break; - if (info->Type != type) + if (info->Type != REG_SZ && info->Type != REG_EXPAND_SZ) continue; + + variable = malloc(sizeof(struct environment_variable)); env_name.Buffer = info->Name; env_name.Length = env_name.MaximumLength = info->NameLength; env_value.Buffer = (WCHAR *)(buffer + info->DataOffset); @@ -542,12 +558,6 @@ static void set_registry_variables( HANDLE hkey, ULONG type ) if (env_value.Length && !env_value.Buffer[env_value.Length/sizeof(WCHAR)-1]) env_value.Length -= sizeof(WCHAR); /* don't count terminating null if any */ if (!env_value.Length) continue; - if (info->Type == REG_EXPAND_SZ) - { - status = RtlExpandEnvironmentStrings_U( NULL, &env_value, &tmp, NULL ); - if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) continue; - RtlCopyUnicodeString( &env_value, &tmp ); - } /* PATH is magic */ if (env_name.Length == sizeof(pathW) && !memicmpW( env_name.Buffer, pathW, ARRAY_SIZE( pathW )) && @@ -557,8 +567,37 @@ static void set_registry_variables( HANDLE hkey, ULONG type ) if (RtlAppendUnicodeStringToString( &tmp, &env_value )) continue; RtlCopyUnicodeString( &env_value, &tmp ); } - RtlSetEnvironmentVariable( NULL, &env_name, &env_value ); + + RtlDuplicateUnicodeString(0, &env_name, &variable->name); + RtlDuplicateUnicodeString(0, &env_value, &variable->value); + variable->type = info->Type; + list_add_head(®istry_variables, &variable->entry); + RtlSetEnvironmentVariable(&penv, &env_name, &env_value); } + + LIST_FOR_EACH_ENTRY_SAFE(variable, variable_next, ®istry_variables, struct environment_variable, entry) + { + if (variable->type == REG_EXPAND_SZ) + { + /* Expand values found inside outside environment */ + status = RtlExpandEnvironmentStrings_U(NULL, &variable->value, &tmp, NULL); + if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) continue; + RtlCopyUnicodeString(&variable->value, &tmp); + + /* Expand values found inside the registry environment we're currently adding */ + status = RtlExpandEnvironmentStrings_U(penv, &variable->value, &tmp, NULL); + if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) continue; + RtlCopyUnicodeString(&variable->value, &tmp); + } + + RtlSetEnvironmentVariable(NULL, &variable->name, &variable->value); + + RtlFreeUnicodeString(&variable->name); + RtlFreeUnicodeString(&variable->value); + free(variable); + } + + RtlDestroyEnvironment(penv); }
@@ -572,7 +611,7 @@ static void set_registry_variables( HANDLE hkey, ULONG type ) * on the order in which the variables are processed. But on Windows it * does not really matter since they only use %SystemDrive% and * %SystemRoot% which are predefined. But Wine defines these in the - * registry, so we need two passes. + * registry, so we need two passes inside set_registry_variables */ static BOOL set_registry_environment( BOOL volatile_only ) { @@ -602,8 +641,7 @@ static BOOL set_registry_environment( BOOL volatile_only ) RtlInitUnicodeString( &nameW, env_keyW ); if (!volatile_only && NtOpenKey( &hkey, KEY_READ, &attr ) == STATUS_SUCCESS) { - set_registry_variables( hkey, REG_SZ ); - set_registry_variables( hkey, REG_EXPAND_SZ ); + set_registry_variables( hkey ); NtClose( hkey ); ret = TRUE; } @@ -613,16 +651,14 @@ static BOOL set_registry_environment( BOOL volatile_only ) RtlInitUnicodeString( &nameW, envW ); if (!volatile_only && NtOpenKey( &hkey, KEY_READ, &attr ) == STATUS_SUCCESS) { - set_registry_variables( hkey, REG_SZ ); - set_registry_variables( hkey, REG_EXPAND_SZ ); + set_registry_variables( hkey ); NtClose( hkey ); }
RtlInitUnicodeString( &nameW, volatile_envW ); if (NtOpenKey( &hkey, KEY_READ, &attr ) == STATUS_SUCCESS) { - set_registry_variables( hkey, REG_SZ ); - set_registry_variables( hkey, REG_EXPAND_SZ ); + set_registry_variables( hkey ); NtClose( hkey ); }
diff --git a/dlls/ntdll/tests/env.c b/dlls/ntdll/tests/env.c index 41cb44ecd2..e295fb97b2 100644 --- a/dlls/ntdll/tests/env.c +++ b/dlls/ntdll/tests/env.c @@ -558,7 +558,6 @@ static void test_peb_environment(void) if (lstrcmpW(env, result2) == 0) found2 = TRUE; } - todo_wine ok(found1, "Didn't find %s in the PEB environment variables\n", wine_dbgstr_w(result1)); ok(found2, "Didn't find %s in the PEB environment variables\n", wine_dbgstr_w(result2)); } -- 2.21.0