Add field to Exception to hold the unmanaged backtrace.
[mono-project.git] / mcs / class / corlib / System / Environment.cs
blobf0c433207e49bf844e49920a76db319d46ada405
1 //------------------------------------------------------------------------------
2 //
3 // System.Environment.cs
4 //
5 // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
6 //
7 // Author: Jim Richardson, develop@wtfo-guru.com
8 // Dan Lewis (dihlewis@yahoo.co.uk)
9 // Created: Saturday, August 11, 2001
11 //------------------------------------------------------------------------------
13 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 //
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 //
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.IO;
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Security;
39 using System.Security.Permissions;
40 using System.Text;
41 using System.Runtime.InteropServices;
43 namespace System {
45 [ComVisible (true)]
46 public static class Environment {
49 * This is the version number of the corlib-runtime interface. When
50 * making changes to this interface (by changing the layout
51 * of classes the runtime knows about, changing icall signature or
52 * semantics etc), increment this variable. Also increment the
53 * pair of this variable in the runtime in metadata/appdomain.c.
54 * Changes which are already detected at runtime, like the addition
55 * of icalls, do not require an increment.
57 #pragma warning disable 169
58 private const int mono_corlib_version = 105 + 0x0210;
59 #pragma warning restore 169
61 [ComVisible (true)]
62 public enum SpecialFolder
64 MyDocuments = 0x05,
65 Desktop = 0x00,
66 MyComputer = 0x11,
67 Programs = 0x02,
68 Personal = 0x05,
69 Favorites = 0x06,
70 Startup = 0x07,
71 Recent = 0x08,
72 SendTo = 0x09,
73 StartMenu = 0x0b,
74 MyMusic = 0x0d,
75 DesktopDirectory = 0x10,
76 Templates = 0x15,
77 ApplicationData = 0x1a,
78 LocalApplicationData = 0x1c,
79 InternetCache = 0x20,
80 Cookies = 0x21,
81 History = 0x22,
82 CommonApplicationData = 0x23,
83 System = 0x25,
84 ProgramFiles = 0x26,
85 MyPictures = 0x27,
86 CommonProgramFiles = 0x2b,
87 #if NET_4_0 || MOONLIGHT || MOBILE
88 MyVideos = 0x0e,
89 #endif
90 #if NET_4_0
91 NetworkShortcuts = 0x13,
92 Fonts = 0x14,
93 CommonStartMenu = 0x16,
94 CommonPrograms = 0x17,
95 CommonStartup = 0x18,
96 CommonDesktopDirectory = 0x19,
97 PrinterShortcuts = 0x1b,
98 Windows = 0x24,
99 UserProfile = 0x28,
100 SystemX86 = 0x29,
101 ProgramFilesX86 = 0x2a,
102 CommonProgramFilesX86 = 0x2c,
103 CommonTemplates = 0x2d,
104 CommonDocuments = 0x2e,
105 CommonAdminTools = 0x2f,
106 AdminTools = 0x30,
107 CommonMusic = 0x35,
108 CommonPictures = 0x36,
109 CommonVideos = 0x37,
110 Resources = 0x38,
111 LocalizedResources = 0x39,
112 CommonOemLinks = 0x3a,
113 CDBurning = 0x3b,
114 #endif
117 #if NET_4_0
118 public
119 #else
120 internal
121 #endif
122 enum SpecialFolderOption {
123 None = 0,
124 DoNotVerify = 0x4000,
125 Create = 0x8000
128 /// <summary>
129 /// Gets the command line for this process
130 /// </summary>
131 public static string CommandLine {
132 // note: security demand inherited from calling GetCommandLineArgs
133 get {
134 StringBuilder sb = new StringBuilder ();
135 foreach (string str in GetCommandLineArgs ()) {
136 bool escape = false;
137 string quote = "";
138 string s = str;
139 for (int i = 0; i < s.Length; i++) {
140 if (quote.Length == 0 && Char.IsWhiteSpace (s [i])) {
141 quote = "\"";
142 } else if (s [i] == '"') {
143 escape = true;
146 if (escape && quote.Length != 0) {
147 s = s.Replace ("\"", "\\\"");
149 sb.AppendFormat ("{0}{1}{0} ", quote, s);
151 if (sb.Length > 0)
152 sb.Length--;
153 return sb.ToString ();
157 /// <summary>
158 /// Gets or sets the current directory. Actually this is supposed to get
159 /// and/or set the process start directory acording to the documentation
160 /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
161 /// </summary>
162 public static string CurrentDirectory
164 get {
165 return Directory.GetCurrentDirectory ();
167 set {
168 Directory.SetCurrentDirectory (value);
172 /// <summary>
173 /// Gets or sets the exit code of this process
174 /// </summary>
175 public extern static int ExitCode
177 [MethodImplAttribute (MethodImplOptions.InternalCall)]
178 get;
179 [MethodImplAttribute (MethodImplOptions.InternalCall)]
180 set;
183 static public extern bool HasShutdownStarted
185 [MethodImplAttribute (MethodImplOptions.InternalCall)]
186 get;
190 /// <summary>
191 /// Gets the name of the local computer
192 /// </summary>
193 public extern static string MachineName {
194 [MethodImplAttribute (MethodImplOptions.InternalCall)]
195 [EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
196 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
197 get;
200 [MethodImplAttribute (MethodImplOptions.InternalCall)]
201 extern static string GetNewLine ();
203 static string nl;
204 /// <summary>
205 /// Gets the standard new line value
206 /// </summary>
207 public static string NewLine {
208 get {
209 if (nl != null)
210 return nl;
212 nl = GetNewLine ();
213 return nl;
218 // Support methods and fields for OSVersion property
220 static OperatingSystem os;
222 static extern PlatformID Platform {
223 [MethodImplAttribute (MethodImplOptions.InternalCall)]
224 get;
227 [MethodImplAttribute (MethodImplOptions.InternalCall)]
228 internal static extern string GetOSVersionString ();
230 /// <summary>
231 /// Gets the current OS version information
232 /// </summary>
233 public static OperatingSystem OSVersion {
234 get {
235 if (os == null) {
236 Version v = Version.CreateFromString (GetOSVersionString ());
237 PlatformID p = Platform;
238 if (p == PlatformID.MacOSX)
239 p = PlatformID.Unix;
240 os = new OperatingSystem (p, v);
242 return os;
246 /// <summary>
247 /// Get StackTrace
248 /// </summary>
249 public static string StackTrace {
250 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
251 get {
252 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (0, true);
253 return trace.ToString ();
256 #if !NET_2_1
257 /// <summary>
258 /// Get a fully qualified path to the system directory
259 /// </summary>
260 public static string SystemDirectory {
261 get {
262 return GetFolderPath (SpecialFolder.System);
265 #endif
266 /// <summary>
267 /// Get the number of milliseconds that have elapsed since the system was booted
268 /// </summary>
269 public extern static int TickCount {
270 [MethodImplAttribute (MethodImplOptions.InternalCall)]
271 get;
274 /// <summary>
275 /// Get UserDomainName
276 /// </summary>
277 public static string UserDomainName {
278 // FIXME: this variable doesn't exist (at least not on WinXP) - reported to MS as FDBK20562
279 [EnvironmentPermission (SecurityAction.Demand, Read="USERDOMAINNAME")]
280 get {
281 return MachineName;
285 /// <summary>
286 /// Gets a flag indicating whether the process is in interactive mode
287 /// </summary>
288 [MonoTODO ("Currently always returns false, regardless of interactive state")]
289 public static bool UserInteractive {
290 get {
291 return false;
295 /// <summary>
296 /// Get the user name of current process is running under
297 /// </summary>
298 public extern static string UserName {
299 [MethodImplAttribute (MethodImplOptions.InternalCall)]
300 [EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
301 get;
304 /// <summary>
305 /// Get the version of the common language runtime
306 /// </summary>
307 public static Version Version {
308 get {
309 return new Version (Consts.FxFileVersion);
313 /// <summary>
314 /// Get the amount of physical memory mapped to process
315 /// </summary>
316 [MonoTODO ("Currently always returns zero")]
317 public static long WorkingSet {
318 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
319 get { return 0; }
322 [MethodImplAttribute (MethodImplOptions.InternalCall)]
323 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
324 public extern static void Exit (int exitCode);
326 /// <summary>
327 /// Substitute environment variables in the argument "name"
328 /// </summary>
329 public static string ExpandEnvironmentVariables (string name)
331 if (name == null)
332 throw new ArgumentNullException ("name");
334 int off1 = name.IndexOf ('%');
335 if (off1 == -1)
336 return name;
338 int len = name.Length;
339 int off2 = 0;
340 if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
341 return name;
343 StringBuilder result = new StringBuilder ();
344 result.Append (name, 0, off1);
345 Hashtable tbl = null;
346 do {
347 string var = name.Substring (off1 + 1, off2 - off1 - 1);
348 string value = GetEnvironmentVariable (var);
349 if (value == null && Environment.IsRunningOnWindows) {
350 // On windows, env. vars. are case insensitive
351 if (tbl == null)
352 tbl = GetEnvironmentVariablesNoCase ();
354 value = tbl [var] as string;
357 // If value not found, add %FOO to stream,
358 // and use the closing % for the next iteration.
359 // If value found, expand it in place of %FOO%
360 if (value == null) {
361 result.Append ('%');
362 result.Append (var);
363 off2--;
364 } else {
365 result.Append (value);
367 int oldOff2 = off2;
368 off1 = name.IndexOf ('%', off2 + 1);
369 // If no % found for off1, don't look for one for off2
370 off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
371 // textLen is the length of text between the closing % of current iteration
372 // and the starting % of the next iteration if any. This text is added to output
373 int textLen;
374 // If no new % found, use all the remaining text
375 if (off1 == -1 || off2 == -1)
376 textLen = len - oldOff2 - 1;
377 // If value found in current iteration, use text after current closing % and next %
378 else if(value != null)
379 textLen = off1 - oldOff2 - 1;
380 // If value not found in current iteration, but a % was found for next iteration,
381 // use text from current closing % to the next %.
382 else
383 textLen = off1 - oldOff2;
384 if(off1 >= oldOff2 || off1 == -1)
385 result.Append (name, oldOff2+1, textLen);
386 } while (off2 > -1 && off2 < len);
388 return result.ToString ();
392 /// <summary>
393 /// Return an array of the command line arguments of the current process
394 /// </summary>
395 [MethodImplAttribute (MethodImplOptions.InternalCall)]
396 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
397 public extern static string[] GetCommandLineArgs ();
399 [MethodImplAttribute (MethodImplOptions.InternalCall)]
400 internal extern static string internalGetEnvironmentVariable (string variable);
402 /// <summary>
403 /// Return a string containing the value of the environment
404 /// variable identifed by parameter "variable"
405 /// </summary>
406 public static string GetEnvironmentVariable (string variable)
408 #if !NET_2_1
409 if (SecurityManager.SecurityEnabled) {
410 new EnvironmentPermission (EnvironmentPermissionAccess.Read, variable).Demand ();
412 #endif
413 return internalGetEnvironmentVariable (variable);
416 static Hashtable GetEnvironmentVariablesNoCase ()
418 Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
419 CaseInsensitiveComparer.Default);
421 foreach (string name in GetEnvironmentVariableNames ()) {
422 vars [name] = internalGetEnvironmentVariable (name);
425 return vars;
428 /// <summary>
429 /// Return a set of all environment variables and their values
430 /// </summary>
431 #if !NET_2_1
432 public static IDictionary GetEnvironmentVariables ()
434 StringBuilder sb = null;
435 if (SecurityManager.SecurityEnabled) {
436 // we must have access to each variable to get the lot
437 sb = new StringBuilder ();
438 // but (performance-wise) we do not want a stack-walk
439 // for each of them so we concatenate them
442 Hashtable vars = new Hashtable ();
443 foreach (string name in GetEnvironmentVariableNames ()) {
444 vars [name] = internalGetEnvironmentVariable (name);
445 if (sb != null) {
446 sb.Append (name);
447 sb.Append (";");
451 if (sb != null) {
452 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
454 return vars;
456 #else
457 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
458 public static IDictionary GetEnvironmentVariables ()
460 Hashtable vars = new Hashtable ();
461 foreach (string name in GetEnvironmentVariableNames ()) {
462 vars [name] = internalGetEnvironmentVariable (name);
464 return vars;
466 #endif
468 [MethodImplAttribute (MethodImplOptions.InternalCall)]
469 private extern static string GetWindowsFolderPath (int folder);
471 /// <summary>
472 /// Returns the fully qualified path of the
473 /// folder specified by the "folder" parameter
474 /// </summary>
475 public static string GetFolderPath (SpecialFolder folder)
477 return GetFolderPath (folder, SpecialFolderOption.None);
479 #if NET_4_0
480 public
481 #endif
482 static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
484 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
486 string dir = null;
488 if (Environment.IsRunningOnWindows)
489 dir = GetWindowsFolderPath ((int) folder);
490 else
491 dir = UnixGetFolderPath (folder, option);
493 #if !NET_2_1
494 if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
495 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
497 #endif
498 return dir;
501 private static string ReadXdgUserDir (string config_dir, string home_dir, string key, string fallback)
503 string env_path = internalGetEnvironmentVariable (key);
504 if (env_path != null && env_path != String.Empty) {
505 return env_path;
508 string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
510 if (!File.Exists (user_dirs_path)) {
511 return Path.Combine (home_dir, fallback);
514 try {
515 using(StreamReader reader = new StreamReader (user_dirs_path)) {
516 string line;
517 while ((line = reader.ReadLine ()) != null) {
518 line = line.Trim ();
519 int delim_index = line.IndexOf ('=');
520 if(delim_index > 8 && line.Substring (0, delim_index) == key) {
521 string path = line.Substring (delim_index + 1).Trim ('"');
522 bool relative = false;
524 if (path.StartsWith ("$HOME/")) {
525 relative = true;
526 path = path.Substring (6);
527 } else if (!path.StartsWith ("/")) {
528 relative = true;
531 return relative ? Path.Combine (home_dir, path) : path;
535 } catch (FileNotFoundException) {
538 return Path.Combine (home_dir, fallback);
542 // the security runtime (and maybe other parts of corlib) needs the
543 // information to initialize themselves before permissions can be checked
544 internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOption option)
546 string home = internalGetHome ();
548 // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
550 // note: skip security check for environment variables
551 string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
552 if ((data == null) || (data == String.Empty)) {
553 data = Path.Combine (home, ".local");
554 data = Path.Combine (data, "share");
557 // note: skip security check for environment variables
558 string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
559 if ((config == null) || (config == String.Empty)) {
560 config = Path.Combine (home, ".config");
563 switch (folder) {
564 // MyComputer is a virtual directory
565 case SpecialFolder.MyComputer:
566 return String.Empty;
568 // personal == ~
569 case SpecialFolder.Personal:
570 #if MONOTOUCH
571 return Path.Combine (home, "Documents");
572 #else
573 return home;
574 #endif
575 // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
576 case SpecialFolder.ApplicationData:
577 #if MONOTOUCH
579 string dir = Path.Combine (Path.Combine (home, "Documents"), ".config");
580 if (option == SpecialFolderOption.Create){
581 if (!Directory.Exists (dir))
582 Directory.CreateDirectory (dir);
584 return dir;
586 #else
587 return config;
588 #endif
589 //use FDO's DATA_HOME. This is *NOT* synced
590 case SpecialFolder.LocalApplicationData:
591 #if MONOTOUCH
593 string dir = Path.Combine (home, "Documents");
594 if (!Directory.Exists (dir))
595 Directory.CreateDirectory (dir);
597 return dir;
599 #else
600 return data;
601 #endif
603 case SpecialFolder.Desktop:
604 case SpecialFolder.DesktopDirectory:
605 return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
607 case SpecialFolder.MyMusic:
608 if (Platform == PlatformID.MacOSX)
609 return Path.Combine (home, "Music");
610 else
611 return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
613 case SpecialFolder.MyPictures:
614 if (Platform == PlatformID.MacOSX)
615 return Path.Combine (home, "Pictures");
616 else
617 return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
619 case SpecialFolder.Templates:
620 return ReadXdgUserDir (config, home, "XDG_TEMPLATES_DIR", "Templates");
621 #if NET_4_0 || MOONLIGHT || MOBILE
622 case SpecialFolder.MyVideos:
623 return ReadXdgUserDir (config, home, "XDG_VIDEOS_DIR", "Videos");
624 #endif
625 #if NET_4_0
626 case SpecialFolder.CommonTemplates:
627 return "/usr/share/templates";
628 case SpecialFolder.Fonts:
629 if (Platform == PlatformID.MacOSX)
630 return Path.Combine (home, "Library", "Fonts");
632 return Path.Combine (home, ".fonts");
633 #endif
634 // these simply dont exist on Linux
635 // The spec says if a folder doesnt exist, we
636 // should return ""
637 case SpecialFolder.Favorites:
638 if (Platform == PlatformID.MacOSX)
639 return Path.Combine (home, "Library", "Favorites");
640 else
641 return String.Empty;
643 case SpecialFolder.ProgramFiles:
644 if (Platform == PlatformID.MacOSX)
645 return "/Applications";
646 else
647 return String.Empty;
649 case SpecialFolder.InternetCache:
650 if (Platform == PlatformID.MacOSX)
651 return Path.Combine (home, "Library", "Caches");
652 else
653 return String.Empty;
655 #if NET_4_0
656 // #2873
657 case SpecialFolder.UserProfile:
658 return home;
659 #endif
661 case SpecialFolder.Programs:
662 case SpecialFolder.SendTo:
663 case SpecialFolder.StartMenu:
664 case SpecialFolder.Startup:
665 case SpecialFolder.Cookies:
666 case SpecialFolder.History:
667 case SpecialFolder.Recent:
668 case SpecialFolder.CommonProgramFiles:
669 case SpecialFolder.System:
670 #if NET_4_0
671 case SpecialFolder.NetworkShortcuts:
672 case SpecialFolder.CommonStartMenu:
673 case SpecialFolder.CommonPrograms:
674 case SpecialFolder.CommonStartup:
675 case SpecialFolder.CommonDesktopDirectory:
676 case SpecialFolder.PrinterShortcuts:
677 case SpecialFolder.Windows:
678 case SpecialFolder.SystemX86:
679 case SpecialFolder.ProgramFilesX86:
680 case SpecialFolder.CommonProgramFilesX86:
681 case SpecialFolder.CommonDocuments:
682 case SpecialFolder.CommonAdminTools:
683 case SpecialFolder.AdminTools:
684 case SpecialFolder.CommonMusic:
685 case SpecialFolder.CommonPictures:
686 case SpecialFolder.CommonVideos:
687 case SpecialFolder.Resources:
688 case SpecialFolder.LocalizedResources:
689 case SpecialFolder.CommonOemLinks:
690 case SpecialFolder.CDBurning:
691 #endif
692 return String.Empty;
693 // This is where data common to all users goes
694 case SpecialFolder.CommonApplicationData:
695 return "/usr/share";
696 default:
697 throw new ArgumentException ("Invalid SpecialFolder");
702 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
703 public static string[] GetLogicalDrives ()
705 return GetLogicalDrivesInternal ();
708 #if !NET_2_1
709 [MethodImplAttribute (MethodImplOptions.InternalCall)]
710 private static extern void internalBroadcastSettingChange ();
712 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
714 switch (target) {
715 case EnvironmentVariableTarget.Process:
716 return GetEnvironmentVariable (variable);
717 case EnvironmentVariableTarget.Machine:
718 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
719 if (!IsRunningOnWindows)
720 return null;
721 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
722 object regvalue = env.GetValue (variable);
723 return (regvalue == null) ? null : regvalue.ToString ();
725 case EnvironmentVariableTarget.User:
726 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
727 if (!IsRunningOnWindows)
728 return null;
729 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
730 object regvalue = env.GetValue (variable);
731 return (regvalue == null) ? null : regvalue.ToString ();
733 default:
734 throw new ArgumentException ("target");
738 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
740 IDictionary variables = (IDictionary)new Hashtable ();
741 switch (target) {
742 case EnvironmentVariableTarget.Process:
743 variables = GetEnvironmentVariables ();
744 break;
745 case EnvironmentVariableTarget.Machine:
746 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
747 if (IsRunningOnWindows) {
748 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
749 string[] value_names = env.GetValueNames ();
750 foreach (string value_name in value_names)
751 variables.Add (value_name, env.GetValue (value_name));
754 break;
755 case EnvironmentVariableTarget.User:
756 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
757 if (IsRunningOnWindows) {
758 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
759 string[] value_names = env.GetValueNames ();
760 foreach (string value_name in value_names)
761 variables.Add (value_name, env.GetValue (value_name));
764 break;
765 default:
766 throw new ArgumentException ("target");
768 return variables;
771 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
772 public static void SetEnvironmentVariable (string variable, string value)
774 SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
777 [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
778 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
780 if (variable == null)
781 throw new ArgumentNullException ("variable");
782 if (variable == String.Empty)
783 throw new ArgumentException ("String cannot be of zero length.", "variable");
784 if (variable.IndexOf ('=') != -1)
785 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
786 if (variable[0] == '\0')
787 throw new ArgumentException ("The first char in the string is the null character.", "variable");
789 switch (target) {
790 case EnvironmentVariableTarget.Process:
791 InternalSetEnvironmentVariable (variable, value);
792 break;
793 case EnvironmentVariableTarget.Machine:
794 if (!IsRunningOnWindows)
795 return;
796 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
797 if (String.IsNullOrEmpty (value))
798 env.DeleteValue (variable, false);
799 else
800 env.SetValue (variable, value);
801 internalBroadcastSettingChange ();
803 break;
804 case EnvironmentVariableTarget.User:
805 if (!IsRunningOnWindows)
806 return;
807 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
808 if (String.IsNullOrEmpty (value))
809 env.DeleteValue (variable, false);
810 else
811 env.SetValue (variable, value);
812 internalBroadcastSettingChange ();
814 break;
815 default:
816 throw new ArgumentException ("target");
820 [MethodImplAttribute (MethodImplOptions.InternalCall)]
821 internal static extern void InternalSetEnvironmentVariable (string variable, string value);
822 #endif
823 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
824 public static void FailFast (string message)
826 throw new NotImplementedException ();
829 #if NET_4_0 || MOONLIGHT || MOBILE
830 [SecurityCritical]
831 public static void FailFast (string message, Exception exception)
833 throw new NotImplementedException ();
835 #endif
837 #if NET_4_0
838 public static bool Is64BitOperatingSystem {
839 get { return IntPtr.Size == 8; } // FIXME: is this good enough?
842 public static bool Is64BitProcess {
843 get { return Is64BitOperatingSystem; }
846 public static int SystemPageSize {
847 get { return GetPageSize (); }
849 #endif
851 public static extern int ProcessorCount {
852 [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
853 [MethodImplAttribute (MethodImplOptions.InternalCall)]
854 get;
857 // private methods
859 internal static bool IsRunningOnWindows {
860 get { return ((int) Platform < 4); }
862 #if !NET_2_1
864 // Used by gacutil.exe
866 #pragma warning disable 169
867 private static string GacPath {
868 get {
869 if (Environment.IsRunningOnWindows) {
870 /* On windows, we don't know the path where mscorlib.dll will be installed */
871 string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
872 return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
875 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
878 #pragma warning restore 169
879 [MethodImplAttribute (MethodImplOptions.InternalCall)]
880 internal extern static string internalGetGacPath ();
881 #endif
882 [MethodImplAttribute (MethodImplOptions.InternalCall)]
883 private extern static string [] GetLogicalDrivesInternal ();
885 [MethodImplAttribute (MethodImplOptions.InternalCall)]
886 private extern static string [] GetEnvironmentVariableNames ();
888 [MethodImplAttribute (MethodImplOptions.InternalCall)]
889 internal extern static string GetMachineConfigPath ();
891 [MethodImplAttribute (MethodImplOptions.InternalCall)]
892 internal extern static string internalGetHome ();
894 [MethodImplAttribute (MethodImplOptions.InternalCall)]
895 internal extern static int GetPageSize ();
897 static internal bool IsUnix {
898 get {
899 int platform = (int) Environment.Platform;
901 return (platform == 4 || platform == 128 || platform == 6);
904 static internal bool IsMacOS {
905 get {
906 return Environment.Platform == PlatformID.MacOSX;