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
.Diagnostics
;
7 using System
.Reflection
;
8 using System
.Threading
;
12 public static partial class Environment
14 public static string? GetEnvironmentVariable(string variable
)
17 throw new ArgumentNullException(nameof(variable
));
19 return GetEnvironmentVariableCore(variable
);
22 public static string? GetEnvironmentVariable(string variable
, EnvironmentVariableTarget target
)
24 if (target
== EnvironmentVariableTarget
.Process
)
25 return GetEnvironmentVariable(variable
);
28 throw new ArgumentNullException(nameof(variable
));
30 bool fromMachine
= ValidateAndConvertRegistryTarget(target
);
31 return GetEnvironmentVariableFromRegistry(variable
, fromMachine
);
34 public static IDictionary
GetEnvironmentVariables(EnvironmentVariableTarget target
)
36 if (target
== EnvironmentVariableTarget
.Process
)
37 return GetEnvironmentVariables();
39 bool fromMachine
= ValidateAndConvertRegistryTarget(target
);
40 return GetEnvironmentVariablesFromRegistry(fromMachine
);
43 public static void SetEnvironmentVariable(string variable
, string? value)
45 ValidateVariableAndValue(variable
, ref value);
46 SetEnvironmentVariableCore(variable
, value);
49 public static void SetEnvironmentVariable(string variable
, string? value, EnvironmentVariableTarget target
)
51 if (target
== EnvironmentVariableTarget
.Process
)
53 SetEnvironmentVariable(variable
, value);
57 ValidateVariableAndValue(variable
, ref value);
59 bool fromMachine
= ValidateAndConvertRegistryTarget(target
);
60 SetEnvironmentVariableFromRegistry(variable
, value, fromMachine
: fromMachine
);
63 public static string CommandLine
=> PasteArguments
.Paste(GetCommandLineArgs(), pasteFirstArgumentUsingArgV0Rules
: true);
65 public static string CurrentDirectory
67 get => CurrentDirectoryCore
;
71 throw new ArgumentNullException(nameof(value));
73 if (value.Length
== 0)
74 throw new ArgumentException(SR
.Argument_PathEmpty
, nameof(value));
76 CurrentDirectoryCore
= value;
80 public static string ExpandEnvironmentVariables(string name
)
83 throw new ArgumentNullException(nameof(name
));
88 return ExpandEnvironmentVariablesCore(name
);
91 private static string[]? s_commandLineArgs
;
93 internal static void SetCommandLineArgs(string[] cmdLineArgs
) // invoked from VM
95 s_commandLineArgs
= cmdLineArgs
;
98 public static string GetFolderPath(SpecialFolder folder
) => GetFolderPath(folder
, SpecialFolderOption
.None
);
100 public static string GetFolderPath(SpecialFolder folder
, SpecialFolderOption option
)
102 if (!Enum
.IsDefined(typeof(SpecialFolder
), folder
))
103 throw new ArgumentOutOfRangeException(nameof(folder
), folder
, SR
.Format(SR
.Arg_EnumIllegalVal
, folder
));
105 if (option
!= SpecialFolderOption
.None
&& !Enum
.IsDefined(typeof(SpecialFolderOption
), option
))
106 throw new ArgumentOutOfRangeException(nameof(option
), option
, SR
.Format(SR
.Arg_EnumIllegalVal
, option
));
108 return GetFolderPathCore(folder
, option
);
111 public static bool Is64BitProcess
=> IntPtr
.Size
== 8;
113 public static bool Is64BitOperatingSystem
=> Is64BitProcess
|| Is64BitOperatingSystemWhen32BitProcess
;
115 private static OperatingSystem
? s_osVersion
;
117 public static OperatingSystem OSVersion
121 if (s_osVersion
== null)
123 Interlocked
.CompareExchange(ref s_osVersion
, GetOSVersion(), null);
129 public static bool UserInteractive
=> true;
131 public static Version Version
135 // FX_PRODUCT_VERSION is expected to be set by the host
136 string? versionString
= (string?)AppContext
.GetData("FX_PRODUCT_VERSION");
138 if (versionString
== null)
140 // Use AssemblyInformationalVersionAttribute as fallback if the exact product version is not specified by the host
141 versionString
= typeof(object).Assembly
.GetCustomAttribute
<AssemblyInformationalVersionAttribute
>()?.InformationalVersion
;
144 ReadOnlySpan
<char> versionSpan
= versionString
.AsSpan();
146 // Strip optional suffixes
147 int separatorIndex
= versionSpan
.IndexOfAny("-+ ");
148 if (separatorIndex
!= -1)
149 versionSpan
= versionSpan
.Slice(0, separatorIndex
);
151 // Return zeros rather then failing if the version string fails to parse
152 return Version
.TryParse(versionSpan
, out Version
? version
) ? version
: new Version();
156 public static long WorkingSet
160 // Use reflection to access the implementation in System.Diagnostics.Process.dll. While far from ideal,
161 // we do this to avoid duplicating the Windows, Linux, macOS, and potentially other platform-specific implementations
162 // present in Process. If it proves important, we could look at separating that functionality out of Process into
163 // Common files which could also be included here.
164 Type
? processType
= Type
.GetType("System.Diagnostics.Process, System.Diagnostics.Process, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError
: false);
165 if (processType
?.GetMethod("GetCurrentProcess")?.Invoke(null, BindingFlags
.DoNotWrapExceptions
, null, null, null) is IDisposable currentProcess
)
167 using (currentProcess
)
169 object? result
= processType
!.GetMethod("get_WorkingSet64")?.Invoke(currentProcess
, BindingFlags
.DoNotWrapExceptions
, null, null, null);
170 if (result
is long) return (long)result
;
174 // Could not get the current working set.
179 private static bool ValidateAndConvertRegistryTarget(EnvironmentVariableTarget target
)
181 Debug
.Assert(target
!= EnvironmentVariableTarget
.Process
);
183 if (target
== EnvironmentVariableTarget
.Machine
)
186 if (target
== EnvironmentVariableTarget
.User
)
189 throw new ArgumentOutOfRangeException(nameof(target
), target
, SR
.Format(SR
.Arg_EnumIllegalVal
, target
));
192 private static void ValidateVariableAndValue(string variable
, ref string? value)
194 if (variable
== null)
195 throw new ArgumentNullException(nameof(variable
));
197 if (variable
.Length
== 0)
198 throw new ArgumentException(SR
.Argument_StringZeroLength
, nameof(variable
));
200 if (variable
[0] == '\0')
201 throw new ArgumentException(SR
.Argument_StringFirstCharIsZero
, nameof(variable
));
203 if (variable
.Contains('='))
204 throw new ArgumentException(SR
.Argument_IllegalEnvVarName
, nameof(variable
));
206 if (string.IsNullOrEmpty(value) || value[0] == '\0')
208 // Explicitly null out value if it's empty