1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System.Collections;
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Reflection;
9 using System.Threading;
13 public static partial class Environment
15 public static string GetEnvironmentVariable(string variable)
18 throw new ArgumentNullException(nameof(variable));
20 return GetEnvironmentVariableCore(variable);
23 public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target)
25 if (target == EnvironmentVariableTarget.Process)
26 return GetEnvironmentVariable(variable);
29 throw new ArgumentNullException(nameof(variable));
31 bool fromMachine = ValidateAndConvertRegistryTarget(target);
32 return GetEnvironmentVariableFromRegistry(variable, fromMachine);
35 public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target)
37 if (target == EnvironmentVariableTarget.Process)
38 return GetEnvironmentVariables();
40 bool fromMachine = ValidateAndConvertRegistryTarget(target);
41 return GetEnvironmentVariablesFromRegistry(fromMachine);
44 public static void SetEnvironmentVariable(string variable, string value)
46 ValidateVariableAndValue(variable, ref value);
47 SetEnvironmentVariableCore(variable, value);
50 public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target)
52 if (target == EnvironmentVariableTarget.Process)
54 SetEnvironmentVariable(variable, value);
58 ValidateVariableAndValue(variable, ref value);
60 bool fromMachine = ValidateAndConvertRegistryTarget(target);
61 SetEnvironmentVariableFromRegistry(variable, value, fromMachine: fromMachine);
64 public static string CommandLine => PasteArguments.Paste(GetCommandLineArgs(), pasteFirstArgumentUsingArgV0Rules: true);
66 public static string CurrentDirectory
68 get => CurrentDirectoryCore;
72 throw new ArgumentNullException(nameof(value));
74 if (value.Length == 0)
75 throw new ArgumentException(SR.Argument_PathEmpty, nameof(value));
77 CurrentDirectoryCore = value;
81 public static string ExpandEnvironmentVariables(string name)
84 throw new ArgumentNullException(nameof(name));
89 return ExpandEnvironmentVariablesCore(name);
92 private static string[] s_commandLineArgs;
94 internal static void SetCommandLineArgs(string[] cmdLineArgs) // invoked from VM
96 s_commandLineArgs = cmdLineArgs;
99 public static string GetFolderPath(SpecialFolder folder) => GetFolderPath(folder, SpecialFolderOption.None);
101 public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
103 if (!Enum.IsDefined(typeof(SpecialFolder), folder))
104 throw new ArgumentOutOfRangeException(nameof(folder), folder, SR.Format(SR.Arg_EnumIllegalVal, folder));
106 if (option != SpecialFolderOption.None && !Enum.IsDefined(typeof(SpecialFolderOption), option))
107 throw new ArgumentOutOfRangeException(nameof(option), option, SR.Format(SR.Arg_EnumIllegalVal, option));
109 return GetFolderPathCore(folder, option);
112 public static bool Is64BitProcess => IntPtr.Size == 8;
114 public static bool Is64BitOperatingSystem => Is64BitProcess || Is64BitOperatingSystemWhen32BitProcess;
116 private static OperatingSystem s_osVersion;
118 public static OperatingSystem OSVersion
122 if (s_osVersion == null)
124 Interlocked.CompareExchange(ref s_osVersion, GetOSVersion(), null);
130 public static bool UserInteractive => true;
132 public static Version Version
136 // FX_PRODUCT_VERSION is expected to be set by the host
137 string versionString = (string)AppContext.GetData("FX_PRODUCT_VERSION");
139 if (versionString == null)
141 // Use AssemblyInformationalVersionAttribute as fallback if the exact product version is not specified by the host
142 versionString = typeof(object).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
145 ReadOnlySpan<char> versionSpan = versionString.AsSpan();
147 // Strip optional suffixes
148 int separatorIndex = versionSpan.IndexOfAny("-+ ");
149 if (separatorIndex != -1)
150 versionSpan = versionSpan.Slice(0, separatorIndex);
152 // Return zeros rather then failing if the version string fails to parse
153 return Version.TryParse(versionSpan, out Version version) ? version : new Version();
157 public static long WorkingSet
161 // Use reflection to access the implementation in System.Diagnostics.Process.dll. While far from ideal,
162 // we do this to avoid duplicating the Windows, Linux, macOS, and potentially other platform-specific implementations
163 // present in Process. If it proves important, we could look at separating that functionality out of Process into
164 // Common files which could also be included here.
165 Type processType = Type.GetType("System.Diagnostics.Process, System.Diagnostics.Process, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
166 IDisposable currentProcess = processType?.GetMethod("GetCurrentProcess")?.Invoke(null, BindingFlags.DoNotWrapExceptions, null, null, null) as IDisposable;
167 if (currentProcess != null)
169 using (currentProcess)
171 object result = processType.GetMethod("get_WorkingSet64")?.Invoke(currentProcess, BindingFlags.DoNotWrapExceptions, null, null, null);
172 if (result is long) return (long)result;
176 // Could not get the current working set.
181 private static bool ValidateAndConvertRegistryTarget(EnvironmentVariableTarget target)
183 Debug.Assert(target != EnvironmentVariableTarget.Process);
185 if (target == EnvironmentVariableTarget.Machine)
188 if (target == EnvironmentVariableTarget.User)
191 throw new ArgumentOutOfRangeException(nameof(target), target, SR.Format(SR.Arg_EnumIllegalVal, target));
194 private static void ValidateVariableAndValue(string variable, ref string value)
196 if (variable == null)
197 throw new ArgumentNullException(nameof(variable));
199 if (variable.Length == 0)
200 throw new ArgumentException(SR.Argument_StringZeroLength, nameof(variable));
202 if (variable[0] == '\0')
203 throw new ArgumentException(SR.Argument_StringFirstCharIsZero, nameof(variable));
205 if (variable.Contains('='))
206 throw new ArgumentException(SR.Argument_IllegalEnvVarName, nameof(variable));
208 if (string.IsNullOrEmpty(value) || value[0] == '\0')
210 // Explicitly null out value if it's empty