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.
4 
5 using Internal.Runtime.Augments;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.IO;
9 using System.Reflection;
10 using System.Runtime.CompilerServices;
11 using System.Text;
12 
13 namespace System
14 {
15     public static partial class Environment
16     {
GetEnvironmentVariable(string variable)17         public static string GetEnvironmentVariable(string variable)
18         {
19             return EnvironmentAugments.GetEnvironmentVariable(variable);
20         }
21 
GetEnvironmentVariable(string variable, EnvironmentVariableTarget target)22         public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target)
23         {
24             return EnvironmentAugments.GetEnvironmentVariable(variable, target);
25         }
26 
GetEnvironmentVariables()27         public static IDictionary GetEnvironmentVariables()
28         {
29             // To maintain complete compatibility with prior versions we need to return a Hashtable.
30             // We did ship a prior version of Core with LowLevelDictionary, which does iterate the
31             // same (e.g. yields DictionaryEntry), but it is not a public type.
32             //
33             // While we could pass Hashtable back from CoreCLR the type is also defined here. We only
34             // want to surface the local Hashtable.
35             return EnvironmentAugments.EnumerateEnvironmentVariables().ToHashtable();
36         }
37 
GetEnvironmentVariables(EnvironmentVariableTarget target)38         public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target)
39         {
40             // See comments in GetEnvironmentVariables()
41             return EnvironmentAugments.EnumerateEnvironmentVariables(target).ToHashtable();
42         }
43 
ToHashtable(this IEnumerable<KeyValuePair<string, string>> pairs)44         private static Hashtable ToHashtable(this IEnumerable<KeyValuePair<string, string>> pairs)
45         {
46             Hashtable hashTable = new Hashtable();
47             foreach (KeyValuePair<string, string> pair in pairs)
48             {
49                 hashTable.Add(pair.Key, pair.Value);
50             }
51             return hashTable;
52         }
53 
SetEnvironmentVariable(string variable, string value)54         public static void SetEnvironmentVariable(string variable, string value)
55         {
56             EnvironmentAugments.SetEnvironmentVariable(variable, value);
57         }
58 
SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target)59         public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target)
60         {
61             EnvironmentAugments.SetEnvironmentVariable(variable, value, target);
62         }
63 
64         public static string CommandLine
65         {
66             get
67             {
68                 StringBuilder sb = StringBuilderCache.Acquire();
69 
70                 foreach (string arg in GetCommandLineArgs())
71                 {
72                     bool containsQuotes = false, containsWhitespace = false;
73                     foreach (char c in arg)
74                     {
75                         if (char.IsWhiteSpace(c))
76                         {
77                             containsWhitespace = true;
78                         }
79                         else if (c == '"')
80                         {
81                             containsQuotes = true;
82                         }
83                     }
84 
85                     string quote = containsWhitespace ? "\"" : "";
86                     string formattedArg = containsQuotes && containsWhitespace ? arg.Replace("\"", "\\\"") : arg;
87 
88                     sb.Append(quote).Append(formattedArg).Append(quote).Append(' ');
89                 }
90 
91                 if (sb.Length > 0)
92                 {
93                     sb.Length--;
94                 }
95 
96                 return StringBuilderCache.GetStringAndRelease(sb);
97             }
98         }
99 
100         public static string CurrentDirectory
101         {
102             get { return CurrentDirectoryCore; }
103             set
104             {
105                 if (value == null)
106                 {
107                     throw new ArgumentNullException(nameof(value));
108                 }
109 
110                 if (value.Length == 0)
111                 {
112                     throw new ArgumentException(SR.Argument_PathEmpty, nameof(value));
113                 }
114 
115                 CurrentDirectoryCore = value;
116             }
117         }
118 
119         public static int CurrentManagedThreadId => EnvironmentAugments.CurrentManagedThreadId;
120 
Exit(int exitCode)121         public static void Exit(int exitCode) => EnvironmentAugments.Exit(exitCode);
122 
FailFast(string message)123         public static void FailFast(string message) => FailFast(message, exception: null);
124 
FailFast(string message, Exception exception)125         public static void FailFast(string message, Exception exception) => EnvironmentAugments.FailFast(message, exception);
126 
ExpandEnvironmentVariables(string name)127         public static string ExpandEnvironmentVariables(string name)
128         {
129             if (name == null)
130             {
131                 throw new ArgumentNullException(nameof(name));
132             }
133 
134             if (name.Length == 0)
135             {
136                 return name;
137             }
138 
139             return ExpandEnvironmentVariablesCore(name);
140         }
141 
GetCommandLineArgs()142         public static string[] GetCommandLineArgs() => EnvironmentAugments.GetCommandLineArgs();
143 
144         public static string GetFolderPath(SpecialFolder folder) => GetFolderPath(folder, SpecialFolderOption.None);
145 
GetFolderPath(SpecialFolder folder, SpecialFolderOption option)146         public static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
147         {
148             if (!Enum.IsDefined(typeof(SpecialFolder), folder))
149             {
150                 throw new ArgumentOutOfRangeException(nameof(folder), folder, SR.Format(SR.Arg_EnumIllegalVal, folder));
151             }
152 
153             if (option != SpecialFolderOption.None && !Enum.IsDefined(typeof(SpecialFolderOption), option))
154             {
155                 throw new ArgumentOutOfRangeException(nameof(option), option, SR.Format(SR.Arg_EnumIllegalVal, option));
156             }
157 
158             return GetFolderPathCore(folder, option);
159         }
160 
161         public static bool HasShutdownStarted => EnvironmentAugments.HasShutdownStarted;
162 
163         public static bool Is64BitProcess => IntPtr.Size == 8;
164 
165         public static bool Is64BitOperatingSystem => Is64BitProcess || Is64BitOperatingSystemWhen32BitProcess;
166 
167         public static OperatingSystem OSVersion => s_osVersion.Value;
168 
169         public static int ProcessorCount => EnvironmentAugments.ProcessorCount;
170 
171         public static string StackTrace
172         {
173             [MethodImpl(MethodImplOptions.NoInlining)] // Prevent inlining from affecting where the stacktrace starts
174             get
175             {
176                 return EnvironmentAugments.StackTrace;
177             }
178         }
179 
180         public static int TickCount => EnvironmentAugments.TickCount;
181 
182         public static bool UserInteractive => true;
183 
184         public static Version Version
185         {
186             // Previously this represented the File version of mscorlib.dll.  Many other libraries in the framework and outside took dependencies on the first three parts of this version
187             // remaining constant throughout 4.x.  From 4.0 to 4.5.2 this was fine since the file version only incremented the last part. Starting with 4.6 we switched to a file versioning
188             // scheme that matched the product version.  In order to preserve compatibility with existing libraries, this needs to be hard-coded.
189             get { return new Version(4, 0, 30319, 42000); }
190         }
191 
192         public static long WorkingSet
193         {
194             get
195             {
196                 // Use reflection to access the implementation in System.Diagnostics.Process.dll.  While far from ideal,
197                 // we do this to avoid duplicating the Windows, Linux, macOS, and potentially other platform-specific implementations
198                 // present in Process.  If it proves important, we could look at separating that functionality out of Process into
199                 // Common files which could also be included here.
200                 Type processType = Type.GetType("System.Diagnostics.Process, System.Diagnostics.Process, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
201                 IDisposable currentProcess = processType?.GetTypeInfo().GetDeclaredMethod("GetCurrentProcess")?.Invoke(null, null) as IDisposable;
202                 if (currentProcess != null)
203                 {
204                     try
205                     {
206                         object result = processType.GetTypeInfo().GetDeclaredProperty("WorkingSet64")?.GetMethod?.Invoke(currentProcess, null);
207                         if (result is long) return (long)result;
208                     }
209                     catch (TargetInvocationException tie)
210                     {
211                         if(tie.InnerException != null)
212                             throw tie.InnerException;
213 
214                         throw tie;
215                     }
216                     finally { currentProcess.Dispose(); }
217                 }
218 
219                 // Could not get the current working set.
220                 return 0;
221             }
222         }
223     }
224 }
225