Alexandre Julliard : ntdll: Set environment variables from the registry on the Unix side.

Alexandre Julliard julliard at winehq.org
Thu Mar 4 15:53:36 CST 2021


Module: wine
Branch: master
Commit: f6e64c55f2ddcb92a9ff53f18d1b12f366dd4036
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=f6e64c55f2ddcb92a9ff53f18d1b12f366dd4036

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Mar  3 11:25:43 2021 +0100

ntdll: Set environment variables from the registry on the Unix side.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/env.c      |   2 +-
 dlls/ntdll/unix/env.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+), 1 deletion(-)

diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c
index 4931e407e57..ade6aefc2d5 100644
--- a/dlls/ntdll/env.c
+++ b/dlls/ntdll/env.c
@@ -1023,7 +1023,7 @@ void init_user_process_params(void)
 
     if (!params->DllPath.MaximumLength)  /* not inherited from parent process */
     {
-        first_prefix_start = set_registry_environment( &params->Environment, TRUE );
+        first_prefix_start = !ENV_FindVariable( params->Environment, L"COMSPEC", 7 );
         set_additional_environment( &params->Environment );
 
         get_image_path( params->ImagePathName.Buffer, image, sizeof(image) );
diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c
index 92498318665..97a43a90000 100644
--- a/dlls/ntdll/unix/env.c
+++ b/dlls/ntdll/unix/env.c
@@ -1242,6 +1242,148 @@ static void add_dynamic_environment( WCHAR **env, SIZE_T *pos, SIZE_T *size )
 }
 
 
+static WCHAR *expand_value( WCHAR *env, SIZE_T size, const WCHAR *src, SIZE_T src_len )
+{
+    SIZE_T len, retlen = src_len, count = 0;
+    const WCHAR *var;
+    WCHAR *ret;
+
+    ret = malloc( retlen * sizeof(WCHAR) );
+    while (src_len)
+    {
+        if (*src != '%')
+        {
+            for (len = 0; len < src_len; len++) if (src[len] == '%') break;
+            var = src;
+            src += len;
+            src_len -= len;
+        }
+        else  /* we are at the start of a variable */
+        {
+            for (len = 1; len < src_len; len++) if (src[len] == '%') break;
+            if (len < src_len)
+            {
+                if ((var = find_env_var( env, size, src + 1, len - 1 )))
+                {
+                    src += len + 1;  /* skip the variable name */
+                    src_len -= len + 1;
+                    var += len;
+                    len = wcslen(var);
+                }
+                else
+                {
+                    var = src;  /* copy original name instead */
+                    len++;
+                    src += len;
+                    src_len -= len;
+                }
+            }
+            else  /* unfinished variable name, ignore it */
+            {
+                var = src;
+                src += len;
+                src_len = 0;
+            }
+        }
+        if (len >= retlen - count)
+        {
+            retlen *= 2;
+            ret = realloc( ret, retlen * sizeof(WCHAR) );
+        }
+        memcpy( ret + count, var, len * sizeof(WCHAR) );
+        count += len;
+    }
+    ret[count] = 0;
+    return ret;
+}
+
+/***********************************************************************
+ *           add_registry_variables
+ *
+ * Set environment variables by enumerating the values of a key;
+ * helper for add_registry_environment().
+ * Note that Windows happily truncates the value if it's too big.
+ */
+static void add_registry_variables( WCHAR **env, SIZE_T *pos, SIZE_T *size, HANDLE key, BOOL append )
+{
+    static const WCHAR pathW[] = {'P','A','T','H'};
+    NTSTATUS status;
+    DWORD index = 0, info_size, namelen, datalen;
+    WCHAR *data, *value, *p;
+    WCHAR buffer[offsetof(KEY_VALUE_FULL_INFORMATION, Name[1024]) / sizeof(WCHAR)];
+    KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
+
+    for (;;)
+    {
+        status = NtEnumerateValueKey( key, index++, KeyValueFullInformation,
+                                      buffer, sizeof(buffer) - sizeof(WCHAR), &info_size );
+        if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) break;
+
+        value = data = buffer + info->DataOffset / sizeof(WCHAR);
+        datalen = info->DataLength / sizeof(WCHAR);
+        namelen = info->NameLength / sizeof(WCHAR);
+
+        if (datalen && !data[datalen - 1]) datalen--;  /* don't count terminating null if any */
+        if (!datalen) continue;
+        data[datalen] = 0;
+        if (info->Type == REG_EXPAND_SZ) value = expand_value( *env, *pos, data, datalen );
+
+        /* PATH is magic */
+        if (append && namelen == 4 && !wcsnicmp( info->Name, pathW, 4 ) && (p = find_env_var( *env, *pos, pathW, 4 )))
+        {
+            static const WCHAR sepW[] = {';',0};
+            WCHAR *newpath = malloc( (wcslen(p) - 4 + datalen) * sizeof(WCHAR) );
+            wcscpy( newpath, p + 5 );
+            wcscat( newpath, sepW );
+            wcscat( newpath, data );
+            if (value != data) free( value );
+            value = newpath;
+        }
+
+        set_env_var( env, pos, size, info->Name, namelen, value );
+        if (value != data) free( value );
+    }
+}
+
+
+/***********************************************************************
+ *           add_registry_environment
+ *
+ * Set the environment variables specified in the registry.
+ */
+static void add_registry_environment( WCHAR **env, SIZE_T *pos, SIZE_T *size )
+{
+    static const WCHAR syskeyW[] = {'\\','R','e','g','i','s','t','r','y',
+        '\\','M','a','c','h','i','n','e',
+        '\\','S','y','s','t','e','m',
+        '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
+        '\\','C','o','n','t','r','o','l',
+        '\\','S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',
+        '\\','E','n','v','i','r','o','n','m','e','n','t',0};
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+    HANDLE key;
+
+    InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
+    init_unicode_string( &nameW, syskeyW );
+    if (!NtOpenKey( &key, KEY_READ, &attr ))
+    {
+        add_registry_variables( env, pos, size, key, FALSE );
+        NtClose( key );
+    }
+    if (!open_hkcu_key( "Environment", &key ))
+    {
+        add_registry_variables( env, pos, size, key, TRUE );
+        NtClose( key );
+    }
+    if (!open_hkcu_key( "Volatile Environment", &key ))
+    {
+        add_registry_variables( env, pos, size, key, TRUE );
+        NtClose( key );
+    }
+}
+
+
 /*************************************************************************
  *		get_initial_console
  *
@@ -1485,6 +1627,7 @@ static RTL_USER_PROCESS_PARAMETERS *build_initial_params(void)
     NTSTATUS status;
 
     add_dynamic_environment( &env, &env_pos, &env_size );
+    add_registry_environment( &env, &env_pos, &env_size );
     env[env_pos++] = 0;
 
     size = (sizeof(*params)




More information about the wine-cvs mailing list