2009-09-20 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / corlib / System / Environment.cs
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 
10 //
11 //------------------------------------------------------------------------------
12 //
13 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
14 //
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.
33 //
34
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;
42
43 namespace System {
44
45 #if NET_2_0
46         [ComVisible (true)]
47 #endif
48 #if NET_2_0
49         public static class Environment {
50 #else
51         public sealed class Environment {
52
53                 private Environment ()
54                 {
55                 }
56 #endif
57                 /*
58                  * This is the version number of the corlib-runtime interface. When
59                  * making changes to this interface (by changing the layout
60                  * of classes the runtime knows about, changing icall signature or
61                  * semantics etc), increment this variable. Also increment the
62                  * pair of this variable in the runtime in metadata/appdomain.c.
63                  * Changes which are already detected at runtime, like the addition
64                  * of icalls, do not require an increment.
65                  */
66                 private const int mono_corlib_version = 82;
67
68 #if NET_2_0
69                 [ComVisible (true)]
70 #endif
71                 public enum SpecialFolder
72                 {       // TODO: Determine if these windoze style folder identifiers 
73                         //       have unix/linux counterparts
74 #if NET_2_0
75                         MyDocuments = 0x05,
76 #endif
77 #if NET_1_1
78                         Desktop = 0x00,
79                         MyComputer = 0x11,
80 #endif
81                         Programs = 0x02,
82                         Personal = 0x05,
83                         Favorites = 0x06,
84                         Startup = 0x07,
85                         Recent = 0x08,
86                         SendTo = 0x09,
87                         StartMenu = 0x0b,
88                         MyMusic = 0x0d,
89                         DesktopDirectory = 0x10,
90                         Templates = 0x15,
91                         ApplicationData = 0x1a,
92                         LocalApplicationData = 0x1c,
93                         InternetCache = 0x20,
94                         Cookies = 0x21,
95                         History = 0x22,
96                         CommonApplicationData   = 0x23,
97                         System = 0x25,
98                         ProgramFiles = 0x26,
99                         MyPictures = 0x27,
100                         CommonProgramFiles = 0x2b,
101                 }
102
103                 /// <summary>
104                 /// Gets the command line for this process
105                 /// </summary>
106                 public static string CommandLine {
107                         // note: security demand inherited from calling GetCommandLineArgs
108                         get {
109                                 // FIXME: we may need to quote, but any sane person
110                                 // should use GetCommandLineArgs () instead.
111                                 return String.Join (" ", GetCommandLineArgs ());
112                         }
113                 }
114
115                 /// <summary>
116                 /// Gets or sets the current directory. Actually this is supposed to get
117                 /// and/or set the process start directory acording to the documentation
118                 /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
119                 /// </summary>
120                 public static string CurrentDirectory
121                 {
122                         get {
123                                 return Directory.GetCurrentDirectory ();
124                         }
125                         set {
126                                 Directory.SetCurrentDirectory (value);
127                         }
128                 }
129
130                 /// <summary>
131                 /// Gets or sets the exit code of this process
132                 /// </summary>
133                 public extern static int ExitCode
134                 {       
135                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
136                         get;
137                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
138                         set;
139                 }
140
141 #if NET_1_1
142                 static
143 #endif
144                 public extern bool HasShutdownStarted
145                 {
146                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
147                         get;
148                 }
149                 
150
151                 /// <summary>
152                 /// Gets the name of the local computer
153                 /// </summary>
154                 public extern static string MachineName {
155                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
156                         [EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
157                         [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
158                         get;
159                 }
160
161                 /// <summary>
162                 /// Gets the standard new line value
163                 /// </summary>
164                 public extern static string NewLine {
165                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
166                         get;
167                 }
168
169                 //
170                 // Support methods and fields for OSVersion property
171                 //
172                 static OperatingSystem os;
173
174                 internal static extern PlatformID Platform {
175                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
176                         get;
177                 }
178
179                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
180                 internal static extern string GetOSVersionString ();
181
182                 /// <summary>
183                 /// Gets the current OS version information
184                 /// </summary>
185                 public static OperatingSystem OSVersion {
186                         get {
187                                 if (os == null) {
188                                         Version v = Version.CreateFromString (GetOSVersionString ());
189                                         PlatformID p = Platform;
190                                         os = new OperatingSystem (p, v);
191                                 }
192                                 return os;
193                         }
194                 }
195
196                 /// <summary>
197                 /// Get StackTrace
198                 /// </summary>
199                 public static string StackTrace {
200                         [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
201                         get {
202                                 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (0, true);
203                                 return trace.ToString ();
204                         }
205                 }
206 #if !NET_2_1
207                 /// <summary>
208                 /// Get a fully qualified path to the system directory
209                 /// </summary>
210                 public static string SystemDirectory {
211                         get {
212                                 return GetFolderPath (SpecialFolder.System);
213                         }
214                 }
215 #endif
216                 /// <summary>
217                 /// Get the number of milliseconds that have elapsed since the system was booted
218                 /// </summary>
219                 public extern static int TickCount {
220                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
221                         get;
222                 }
223
224                 /// <summary>
225                 /// Get UserDomainName
226                 /// </summary>
227                 public static string UserDomainName {
228                         // FIXME: this variable doesn't exist (at least not on WinXP) - reported to MS as FDBK20562
229                         [EnvironmentPermission (SecurityAction.Demand, Read="USERDOMAINNAME")]
230                         get {
231                                 return MachineName;
232                         }
233                 }
234
235                 /// <summary>
236                 /// Gets a flag indicating whether the process is in interactive mode
237                 /// </summary>
238                 [MonoTODO ("Currently always returns false, regardless of interactive state")]
239                 public static bool UserInteractive {
240                         get {
241                                 return false;
242                         }
243                 }
244
245                 /// <summary>
246                 /// Get the user name of current process is running under
247                 /// </summary>
248                 public extern static string UserName {
249                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
250                         [EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
251                         get;
252                 }
253
254                 /// <summary>
255                 /// Get the version of the common language runtime 
256                 /// </summary>
257                 public static Version Version {
258                         get {
259                                 return new Version (Consts.FxFileVersion);
260                         }
261                 }
262
263                 /// <summary>
264                 /// Get the amount of physical memory mapped to process
265                 /// </summary>
266                 [MonoTODO ("Currently always returns zero")]
267                 public static long WorkingSet {
268                         [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
269                         get { return 0; }
270                 }
271
272                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
273                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
274                 public extern static void Exit (int exitCode);
275
276                 /// <summary>
277                 /// Substitute environment variables in the argument "name"
278                 /// </summary>
279                 public static string ExpandEnvironmentVariables (string name)
280                 {
281                         if (name == null)
282                                 throw new ArgumentNullException ("name");
283
284                         int off1 = name.IndexOf ('%');
285                         if (off1 == -1)
286                                 return name;
287
288                         int len = name.Length;
289                         int off2 = 0;
290                         if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
291                                 return name;
292
293                         StringBuilder result = new StringBuilder ();
294                         result.Append (name, 0, off1);
295                         Hashtable tbl = null;
296                         do {
297                                 string var = name.Substring (off1 + 1, off2 - off1 - 1);
298                                 string value = GetEnvironmentVariable (var);
299                                 if (value == null && Environment.IsRunningOnWindows) {
300                                         // On windows, env. vars. are case insensitive
301                                         if (tbl == null)
302                                                 tbl = GetEnvironmentVariablesNoCase ();
303
304                                         value = tbl [var] as string;
305                                 }
306                                 
307                                 // If value not found, add %FOO to stream,
308                                 //  and use the closing % for the next iteration.
309                                 // If value found, expand it in place of %FOO%
310                                 if (value == null) {
311                                         result.Append ('%');
312                                         result.Append (var);
313                                         off2--;
314                                 } else {
315                                         result.Append (value);
316                                 }
317                                 int oldOff2 = off2;
318                                 off1 = name.IndexOf ('%', off2 + 1);
319                                 // If no % found for off1, don't look for one for off2
320                                 off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
321                                 // textLen is the length of text between the closing % of current iteration
322                                 //  and the starting % of the next iteration if any. This text is added to output
323                                 int textLen;
324                                 // If no new % found, use all the remaining text
325                                 if (off1 == -1 || off2 == -1)
326                                         textLen = len - oldOff2 - 1;
327                                 // If value found in current iteration, use text after current closing % and next %
328                                 else if(value != null)
329                                         textLen = off1 - oldOff2 - 1;
330                                 // If value not found in current iteration, but a % was found for next iteration,
331                                 //  use text from current closing % to the next %.
332                                 else
333                                         textLen = off1 - oldOff2;
334                                 if(off1 >= oldOff2 || off1 == -1)
335                                         result.Append (name, oldOff2+1, textLen);
336                         } while (off2 > -1 && off2 < len);
337                                 
338                         return result.ToString ();
339
340                 }
341
342                 /// <summary>
343                 /// Return an array of the command line arguments of the current process
344                 /// </summary>
345                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
346                 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
347                 public extern static string[] GetCommandLineArgs ();
348
349                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
350                 internal extern static string internalGetEnvironmentVariable (string variable);
351
352                 /// <summary>
353                 /// Return a string containing the value of the environment
354                 /// variable identifed by parameter "variable"
355                 /// </summary>
356                 public static string GetEnvironmentVariable (string variable)
357                 {
358                         if (SecurityManager.SecurityEnabled) {
359                                 new EnvironmentPermission (EnvironmentPermissionAccess.Read, variable).Demand ();
360                         }
361                         return internalGetEnvironmentVariable (variable);
362                 }
363
364                 static Hashtable GetEnvironmentVariablesNoCase ()
365                 {
366                         Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
367                                                         CaseInsensitiveComparer.Default);
368
369                         foreach (string name in GetEnvironmentVariableNames ()) {
370                                 vars [name] = internalGetEnvironmentVariable (name);
371                         }
372
373                         return vars;
374                 }
375
376                 /// <summary>
377                 /// Return a set of all environment variables and their values
378                 /// </summary>
379 #if NET_2_0
380                 public static IDictionary GetEnvironmentVariables ()
381                 {
382                         StringBuilder sb = null;
383                         if (SecurityManager.SecurityEnabled) {
384                                 // we must have access to each variable to get the lot
385                                 sb = new StringBuilder ();
386                                 // but (performance-wise) we do not want a stack-walk
387                                 // for each of them so we concatenate them
388                         }
389
390                         Hashtable vars = new Hashtable ();
391                         foreach (string name in GetEnvironmentVariableNames ()) {
392                                 vars [name] = internalGetEnvironmentVariable (name);
393                                 if (sb != null) {
394                                         sb.Append (name);
395                                         sb.Append (";");
396                                 }
397                         }
398
399                         if (sb != null) {
400                                 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
401                         }
402                         return vars;
403                 }
404 #else
405                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
406                 public static IDictionary GetEnvironmentVariables ()
407                 {
408                         Hashtable vars = new Hashtable ();
409                         foreach (string name in GetEnvironmentVariableNames ()) {
410                                 vars [name] = internalGetEnvironmentVariable (name);
411                         }
412                         return vars;
413                 }
414 #endif
415
416                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
417                 private extern static string GetWindowsFolderPath (int folder);
418
419                 /// <summary>
420                 /// Returns the fully qualified path of the
421                 /// folder specified by the "folder" parameter
422                 /// </summary>
423                 public static string GetFolderPath (SpecialFolder folder)
424                 {
425                         string dir = null;
426
427                         if (Environment.IsRunningOnWindows) {
428                                 dir = GetWindowsFolderPath ((int) folder);
429                         } else {
430                                 dir = InternalGetFolderPath (folder);
431                         }
432 #if !NET_2_1
433                         if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
434                                 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
435                         }
436 #endif
437                         return dir;
438                 }
439
440                 private static string ReadXdgUserDir (string config_dir, string home_dir, 
441                         string key, string fallback)
442                 {
443                         string env_path = internalGetEnvironmentVariable (key);
444                         if (env_path != null && env_path != String.Empty) {
445                                 return env_path;
446                         }
447
448                         string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
449
450                         if (!File.Exists (user_dirs_path)) {
451                                 return Path.Combine (home_dir, fallback);
452                         }
453
454                         try {
455                                 using(StreamReader reader = new StreamReader (user_dirs_path)) {
456                                         string line;
457                                         while ((line = reader.ReadLine ()) != null) {
458                                                 line = line.Trim ();
459                                                 int delim_index = line.IndexOf ('=');
460                         if(delim_index > 8 && line.Substring (0, delim_index) == key) {
461                             string path = line.Substring (delim_index + 1).Trim ('"');
462                             bool relative = false;
463
464                             if (path.StartsWith ("$HOME/")) {
465                                 relative = true;
466                                 path = path.Substring (6);
467                             } else if (!path.StartsWith ("/")) {
468                                 relative = true;
469                             }
470
471                             return relative ? Path.Combine (home_dir, path) : path;
472                         }
473                                         }
474                                 }
475                         } catch (FileNotFoundException) {
476                         }
477
478                         return Path.Combine (home_dir, fallback);
479                 }
480
481
482                 // the security runtime (and maybe other parts of corlib) needs the
483                 // information to initialize themselves before permissions can be checked
484                 internal static string InternalGetFolderPath (SpecialFolder folder)
485                 {
486                         string home = internalGetHome ();
487
488                         // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
489
490                         // note: skip security check for environment variables
491                         string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
492                         if ((data == null) || (data == String.Empty)) {
493                                 data = Path.Combine (home, ".local");
494                                 data = Path.Combine (data, "share");
495                         }
496
497                         // note: skip security check for environment variables
498                         string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
499                         if ((config == null) || (config == String.Empty)) {
500                                 config = Path.Combine (home, ".config");
501                         }
502
503                         switch (folder) {
504 #if NET_1_1
505                         // MyComputer is a virtual directory
506                         case SpecialFolder.MyComputer:
507                                 return String.Empty;
508 #endif
509                         // personal == ~
510                         case SpecialFolder.Personal:
511 #if MONOTOUCH
512                                 return Path.Combine (home, "Documents");
513 #else
514                                 return home;
515 #endif
516                         // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
517                         case SpecialFolder.ApplicationData:
518                                 return config;
519                         //use FDO's DATA_HOME. This is *NOT* synced
520                         case SpecialFolder.LocalApplicationData:
521                                 return data;
522 #if NET_1_1
523                         case SpecialFolder.Desktop:
524 #endif
525                         case SpecialFolder.DesktopDirectory:
526                                 return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
527
528                         case SpecialFolder.MyMusic:
529                                 return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
530
531                         case SpecialFolder.MyPictures:
532                                 return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
533                                 
534                         // these simply dont exist on Linux
535                         // The spec says if a folder doesnt exist, we
536                         // should return ""
537                         case SpecialFolder.Favorites:
538                         case SpecialFolder.Programs:
539                         case SpecialFolder.SendTo:
540                         case SpecialFolder.StartMenu:
541                         case SpecialFolder.Startup:
542                         case SpecialFolder.Templates:
543                         case SpecialFolder.Cookies:
544                         case SpecialFolder.History:
545                         case SpecialFolder.InternetCache:
546                         case SpecialFolder.Recent:
547                         case SpecialFolder.CommonProgramFiles:
548                         case SpecialFolder.ProgramFiles:
549                         case SpecialFolder.System:
550                                 return String.Empty;
551                         // This is where data common to all users goes
552                         case SpecialFolder.CommonApplicationData:
553                                 return "/usr/share";
554                         default:
555                                 throw new ArgumentException ("Invalid SpecialFolder");
556                         }
557                 }
558
559                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
560                 public static string[] GetLogicalDrives ()
561                 {
562                         return GetLogicalDrivesInternal ();
563                 }
564
565 #if NET_2_0 && !NET_2_1
566                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
567                 private static extern void internalBroadcastSettingChange ();
568
569                 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
570                 {
571                         switch (target) {
572                         case EnvironmentVariableTarget.Process:
573                                 return GetEnvironmentVariable (variable);
574                         case EnvironmentVariableTarget.Machine:
575                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
576                                 if (!IsRunningOnWindows)
577                                         return null;
578                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
579                                         object regvalue = env.GetValue (variable);
580                                         return (regvalue == null) ? null : regvalue.ToString ();
581                                 }
582                         case EnvironmentVariableTarget.User:
583                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
584                                 if (!IsRunningOnWindows)
585                                         return null;
586                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
587                                         object regvalue = env.GetValue (variable);
588                                         return (regvalue == null) ? null : regvalue.ToString ();
589                                 }
590                         default:
591                                 throw new ArgumentException ("target");
592                         }
593                 }
594
595                 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
596                 {
597                         IDictionary variables = (IDictionary)new Hashtable ();
598                         switch (target) {
599                         case EnvironmentVariableTarget.Process:
600                                 variables = GetEnvironmentVariables ();
601                                 break;
602                         case EnvironmentVariableTarget.Machine:
603                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
604                                 if (IsRunningOnWindows) {
605                                         using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
606                                                 string[] value_names = env.GetValueNames ();
607                                                 foreach (string value_name in value_names)
608                                                         variables.Add (value_name, env.GetValue (value_name));
609                                         }
610                                 }
611                                 break;
612                         case EnvironmentVariableTarget.User:
613                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
614                                 if (IsRunningOnWindows) {
615                                         using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
616                                                 string[] value_names = env.GetValueNames ();
617                                                 foreach (string value_name in value_names)
618                                                         variables.Add (value_name, env.GetValue (value_name));
619                                         }
620                                 }
621                                 break;
622                         default:
623                                 throw new ArgumentException ("target");
624                         }
625                         return variables;
626                 }
627
628                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
629                 public static void SetEnvironmentVariable (string variable, string value)
630                 {
631                         SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
632                 }
633
634                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
635                 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
636                 {
637                         if (variable == null)
638                                 throw new ArgumentNullException ("variable");
639                         if (variable == String.Empty)
640                                 throw new ArgumentException ("String cannot be of zero length.", "variable");
641                         if (variable.IndexOf ('=') != -1)
642                                 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
643                         if (variable[0] == '\0')
644                                 throw new ArgumentException ("The first char in the string is the null character.", "variable");
645
646                         switch (target) {
647                         case EnvironmentVariableTarget.Process:
648                                 InternalSetEnvironmentVariable (variable, value);
649                                 break;
650                         case EnvironmentVariableTarget.Machine:
651                                 if (!IsRunningOnWindows)
652                                         return;
653                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
654                                         if (String.IsNullOrEmpty (value))
655                                                 env.DeleteValue (variable, false);
656                                         else
657                                                 env.SetValue (variable, value);
658                                         internalBroadcastSettingChange ();
659                                 }
660                                 break;
661                         case EnvironmentVariableTarget.User:
662                                 if (!IsRunningOnWindows)
663                                         return;
664                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
665                                         if (String.IsNullOrEmpty (value))
666                                                 env.DeleteValue (variable, false);
667                                         else
668                                                 env.SetValue (variable, value);
669                                         internalBroadcastSettingChange ();
670                                 }
671                                 break;
672                         default:
673                                 throw new ArgumentException ("target");
674                         }
675                 }
676
677                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
678                 internal static extern void InternalSetEnvironmentVariable (string variable, string value);
679
680                 [MonoTODO ("Not implemented")]
681                 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
682                 public static void FailFast (string message)
683                 {
684                         throw new NotImplementedException ();
685                 }
686 #endif
687 #if NET_2_0
688                 public static extern int ProcessorCount {
689                         [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
690                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
691                         get;                    
692                 }
693 #endif
694                 // private methods
695
696                 internal static bool IsRunningOnWindows {
697                         get { return ((int) Platform < 4); }
698                 }
699 #if !NET_2_1
700                 //
701                 // Used by gacutil.exe
702                 //
703 #pragma warning disable 169             
704                 private static string GacPath {
705                         get {
706                                 if (Environment.IsRunningOnWindows) {
707                                         /* On windows, we don't know the path where mscorlib.dll will be installed */
708                                         string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
709                                         return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
710                                 }
711
712                                 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
713                         }
714                 }
715 #pragma warning restore 169
716                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
717                 internal extern static string internalGetGacPath ();
718 #endif
719                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
720                 private extern static string [] GetLogicalDrivesInternal ();
721
722                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
723                 private extern static string [] GetEnvironmentVariableNames ();
724
725                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
726                 internal extern static string GetMachineConfigPath ();
727
728                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
729                 internal extern static string internalGetHome ();
730         }
731 }
732