[EnvVar]Fix how expanded variables are processed (#29418)

* Read variables from registry (without expanding), not by using Environment API
Fix seting variables to registry

* Expand in Applied variables list

* Remove using

* Add comments
This commit is contained in:
Stefan Markovic
2023-10-25 20:03:15 +02:00
committed by GitHub
parent ef6b17c5d1
commit 04a7adf6a4
2 changed files with 36 additions and 13 deletions

View File

@@ -65,6 +65,9 @@ namespace EnvironmentVariables.Helpers
return baseKey.OpenSubKey(keyName, writable: writable);
}
// Code taken from https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Environment.Win32.cs
// Set variables directly to registry instead of using Environment API - Environment.SetEnvironmentVariable() has 1 second timeout for SendNotifyMessage(WM_SETTINGSCHANGED).
// When applying profile, this would take num_of_variables * 1s to propagate the changes. We do manually SendNotifyMessage with no timeout where needed.
private static void SetEnvironmentVariableFromRegistryWithoutNotify(string variable, string value, bool fromMachine)
{
const int MaxUserEnvVariableLength = 255; // User-wide env vars stored in the registry have names limited to 255 chars
@@ -84,7 +87,15 @@ namespace EnvironmentVariables.Helpers
}
else
{
environmentKey.SetValue(variable, value);
// If a variable contains %, we save it as a REG_EXPAND_SZ, which is the same behavior as the Windows default environment variables editor.
if (value.Contains('%'))
{
environmentKey.SetValue(variable, value, RegistryValueKind.ExpandString);
}
else
{
environmentKey.SetValue(variable, value, RegistryValueKind.String);
}
}
}
}
@@ -102,23 +113,32 @@ namespace EnvironmentVariables.Helpers
}
}
// Code taken from https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Environment.Win32.cs
// Reading variables from registry instead of using Environment API, because Environment API expands variables by default.
internal static void GetVariables(EnvironmentVariableTarget target, VariablesSet set)
{
var variables = Environment.GetEnvironmentVariables(target);
var sortedList = new SortedList<string, Variable>();
foreach (DictionaryEntry variable in variables)
bool fromMachine = target == EnvironmentVariableTarget.Machine ? true : false;
using (RegistryKey environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: false))
{
string key = variable.Key as string;
string value = variable.Value as string;
if (string.IsNullOrEmpty(key))
if (environmentKey != null)
{
continue;
foreach (string name in environmentKey.GetValueNames())
{
string value = environmentKey.GetValue(name, string.Empty, RegistryValueOptions.DoNotExpandEnvironmentNames).ToString();
try
{
Variable entry = new Variable(name, value, set.Type);
sortedList.Add(name, entry);
}
catch (ArgumentException)
{
// Throw and catch intentionally to provide non-fatal notification about corrupted environment block
}
}
}
Variable entry = new Variable(key, value, set.Type);
sortedList.Add(key, entry);
}
set.Variables = new System.Collections.ObjectModel.ObservableCollection<Variable>(sortedList.Values);

View File

@@ -132,10 +132,13 @@ namespace EnvironmentVariables.ViewModels
var variables = new List<Variable>();
if (AppliedProfile != null)
{
variables = variables.Concat(AppliedProfile.Variables.OrderBy(x => x.Name)).ToList();
variables = variables.Concat(AppliedProfile.Variables.Select(x => new Variable(x.Name, Environment.ExpandEnvironmentVariables(x.Values), VariablesSetType.Profile)).OrderBy(x => x.Name)).ToList();
}
variables = variables.Concat(UserDefaultSet.Variables.OrderBy(x => x.Name)).Concat(SystemDefaultSet.Variables.OrderBy(x => x.Name)).ToList();
// Variables are expanded to be shown in the applied variables section, so the user sees their actual values.
variables = variables.Concat(UserDefaultSet.Variables.Select(x => new Variable(x.Name, Environment.ExpandEnvironmentVariables(x.Values), VariablesSetType.User)).OrderBy(x => x.Name))
.Concat(SystemDefaultSet.Variables.Select(x => new Variable(x.Name, Environment.ExpandEnvironmentVariables(x.Values), VariablesSetType.System)).OrderBy(x => x.Name))
.ToList();
// Handle PATH variable - add USER value to the end of the SYSTEM value
var profilePath = variables.Where(x => x.Name.Equals("PATH", StringComparison.OrdinalIgnoreCase) && x.ParentType == VariablesSetType.Profile).FirstOrDefault();