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