mirror of
https://github.com/microsoft/PowerToys
synced 2025-09-02 15:35:12 +00:00
[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:
@@ -65,6 +65,9 @@ namespace EnvironmentVariables.Helpers
|
|||||||
return baseKey.OpenSubKey(keyName, writable: writable);
|
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)
|
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
|
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
|
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)
|
internal static void GetVariables(EnvironmentVariableTarget target, VariablesSet set)
|
||||||
{
|
{
|
||||||
var variables = Environment.GetEnvironmentVariables(target);
|
|
||||||
var sortedList = new SortedList<string, Variable>();
|
var sortedList = new SortedList<string, Variable>();
|
||||||
|
|
||||||
foreach (DictionaryEntry variable in variables)
|
bool fromMachine = target == EnvironmentVariableTarget.Machine ? true : false;
|
||||||
{
|
|
||||||
string key = variable.Key as string;
|
|
||||||
string value = variable.Value as string;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(key))
|
using (RegistryKey environmentKey = OpenEnvironmentKeyIfExists(fromMachine, writable: false))
|
||||||
{
|
{
|
||||||
continue;
|
if (environmentKey != null)
|
||||||
|
{
|
||||||
|
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);
|
set.Variables = new System.Collections.ObjectModel.ObservableCollection<Variable>(sortedList.Values);
|
||||||
|
@@ -132,10 +132,13 @@ namespace EnvironmentVariables.ViewModels
|
|||||||
var variables = new List<Variable>();
|
var variables = new List<Variable>();
|
||||||
if (AppliedProfile != null)
|
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
|
// 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();
|
var profilePath = variables.Where(x => x.Name.Equals("PATH", StringComparison.OrdinalIgnoreCase) && x.ParentType == VariablesSetType.Profile).FirstOrDefault();
|
||||||
|
Reference in New Issue
Block a user