Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[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 using System.Threading;
43
44 namespace System {
45
46         [ComVisible (true)]
47         public static partial class Environment {
48
49                 /*
50                  * This is the version number of the corlib-runtime interface. When
51                  * making changes to this interface (by changing the layout
52                  * of classes the runtime knows about, changing icall signature or
53                  * semantics etc), increment this variable. Also increment the
54                  * pair of this variable in the runtime in metadata/appdomain.c.
55                  * Changes which are already detected at runtime, like the addition
56                  * of icalls, do not require an increment.
57                  */
58 #pragma warning disable 169
59                 private const int mono_corlib_version = 111;
60 #pragma warning restore 169
61
62                 [ComVisible (true)]
63                 public enum SpecialFolder
64                 {       
65                         MyDocuments = 0x05,
66                         Desktop = 0x00,
67                         MyComputer = 0x11,
68                         Programs = 0x02,
69                         Personal = 0x05,
70                         Favorites = 0x06,
71                         Startup = 0x07,
72                         Recent = 0x08,
73                         SendTo = 0x09,
74                         StartMenu = 0x0b,
75                         MyMusic = 0x0d,
76                         DesktopDirectory = 0x10,
77                         Templates = 0x15,
78                         ApplicationData = 0x1a,
79                         LocalApplicationData = 0x1c,
80                         InternetCache = 0x20,
81                         Cookies = 0x21,
82                         History = 0x22,
83                         CommonApplicationData   = 0x23,
84                         System = 0x25,
85                         ProgramFiles = 0x26,
86                         MyPictures = 0x27,
87                         CommonProgramFiles = 0x2b,
88 #if NET_4_0
89                         MyVideos = 0x0e,
90 #endif
91 #if NET_4_0
92                         NetworkShortcuts = 0x13,
93                         Fonts = 0x14,
94                         CommonStartMenu = 0x16,
95                         CommonPrograms = 0x17,
96                         CommonStartup = 0x18,
97                         CommonDesktopDirectory = 0x19,
98                         PrinterShortcuts = 0x1b,
99                         Windows = 0x24,
100                         UserProfile = 0x28,
101                         SystemX86 = 0x29,
102                         ProgramFilesX86 = 0x2a,
103                         CommonProgramFilesX86 = 0x2c,
104                         CommonTemplates = 0x2d,
105                         CommonDocuments = 0x2e,
106                         CommonAdminTools = 0x2f,
107                         AdminTools = 0x30,
108                         CommonMusic = 0x35,
109                         CommonPictures = 0x36,
110                         CommonVideos = 0x37,
111                         Resources = 0x38,
112                         LocalizedResources = 0x39,
113                         CommonOemLinks = 0x3a,
114                         CDBurning = 0x3b,
115 #endif
116                 }
117
118 #if NET_4_0
119                 public
120 #else
121                 internal
122 #endif
123                 enum SpecialFolderOption {
124                         None = 0,
125                         DoNotVerify = 0x4000,
126                         Create = 0x8000
127                 }
128
129                 /// <summary>
130                 /// Gets the command line for this process
131                 /// </summary>
132                 public static string CommandLine {
133                         // note: security demand inherited from calling GetCommandLineArgs
134                         get {
135                                 StringBuilder sb = new StringBuilder ();
136                                 foreach (string str in GetCommandLineArgs ()) {
137                                         bool escape = false;
138                                         string quote = "";
139                                         string s = str;
140                                         for (int i = 0; i < s.Length; i++) {
141                                                 if (quote.Length == 0 && Char.IsWhiteSpace (s [i])) {
142                                                         quote = "\"";
143                                                 } else if (s [i] == '"') {
144                                                         escape = true;
145                                                 }
146                                         }
147                                         if (escape && quote.Length != 0) {
148                                                 s = s.Replace ("\"", "\\\"");
149                                         }
150                                         sb.AppendFormat ("{0}{1}{0} ", quote, s);
151                                 }
152                                 if (sb.Length > 0)
153                                         sb.Length--;
154                                 return sb.ToString ();
155                         }
156                 }
157
158                 /// <summary>
159                 /// Gets or sets the current directory. Actually this is supposed to get
160                 /// and/or set the process start directory acording to the documentation
161                 /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
162                 /// </summary>
163                 public static string CurrentDirectory
164                 {
165                         get {
166                                 return Directory.GetCurrentDirectory ();
167                         }
168                         set {
169                                 Directory.SetCurrentDirectory (value);
170                         }
171                 }
172                 
173 #if NET_4_5
174                 public static int CurrentManagedThreadId {
175                         get {
176                                 return Thread.CurrentThread.ManagedThreadId;
177                         }
178                 }
179 #endif
180
181                 /// <summary>
182                 /// Gets or sets the exit code of this process
183                 /// </summary>
184                 public extern static int ExitCode
185                 {       
186                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
187                         get;
188                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
189                         set;
190                 }
191
192                 static public extern bool HasShutdownStarted
193                 {
194                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
195                         get;
196                 }
197                 
198
199                 /// <summary>
200                 /// Gets the name of the local computer
201                 /// </summary>
202                 public extern static string MachineName {
203                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
204                         [EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
205                         [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
206                         get;
207                 }
208
209                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
210                 extern static string GetNewLine ();
211
212                 static string nl;
213                 /// <summary>
214                 /// Gets the standard new line value
215                 /// </summary>
216                 public static string NewLine {
217                         get {
218                                 if (nl != null)
219                                         return nl;
220
221                                 nl = GetNewLine ();
222                                 return nl;
223                         }
224                 }
225
226                 //
227                 // Support methods and fields for OSVersion property
228                 //
229                 static OperatingSystem os;
230
231                 static extern PlatformID Platform {
232                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
233                         get;
234                 }
235
236                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
237                 internal static extern string GetOSVersionString ();
238
239                 /// <summary>
240                 /// Gets the current OS version information
241                 /// </summary>
242                 public static OperatingSystem OSVersion {
243                         get {
244                                 if (os == null) {
245                                         Version v = Version.CreateFromString (GetOSVersionString ());
246                                         PlatformID p = Platform;
247                                         if (p == PlatformID.MacOSX)
248                                                 p = PlatformID.Unix;
249                                         os = new OperatingSystem (p, v);
250                                 }
251                                 return os;
252                         }
253                 }
254
255                 /// <summary>
256                 /// Get StackTrace
257                 /// </summary>
258                 public static string StackTrace {
259                         [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
260                         get {
261                                 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (0, true);
262                                 return trace.ToString ();
263                         }
264                 }
265 #if !NET_2_1
266                 /// <summary>
267                 /// Get a fully qualified path to the system directory
268                 /// </summary>
269                 public static string SystemDirectory {
270                         get {
271                                 return GetFolderPath (SpecialFolder.System);
272                         }
273                 }
274 #endif
275                 /// <summary>
276                 /// Get the number of milliseconds that have elapsed since the system was booted
277                 /// </summary>
278                 public extern static int TickCount {
279                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
280                         get;
281                 }
282
283                 /// <summary>
284                 /// Get UserDomainName
285                 /// </summary>
286                 public static string UserDomainName {
287                         // FIXME: this variable doesn't exist (at least not on WinXP) - reported to MS as FDBK20562
288                         [EnvironmentPermission (SecurityAction.Demand, Read="USERDOMAINNAME")]
289                         get {
290                                 return MachineName;
291                         }
292                 }
293
294                 /// <summary>
295                 /// Gets a flag indicating whether the process is in interactive mode
296                 /// </summary>
297                 [MonoTODO ("Currently always returns false, regardless of interactive state")]
298                 public static bool UserInteractive {
299                         get {
300                                 return false;
301                         }
302                 }
303
304                 /// <summary>
305                 /// Get the user name of current process is running under
306                 /// </summary>
307                 public extern static string UserName {
308                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
309                         [EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
310                         get;
311                 }
312
313                 /// <summary>
314                 /// Get the version of the common language runtime 
315                 /// </summary>
316                 public static Version Version {
317                         get {
318                                 return new Version (Consts.FxFileVersion);
319                         }
320                 }
321
322                 /// <summary>
323                 /// Get the amount of physical memory mapped to process
324                 /// </summary>
325                 [MonoTODO ("Currently always returns zero")]
326                 public static long WorkingSet {
327                         [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
328                         get { return 0; }
329                 }
330
331                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
332                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
333                 public extern static void Exit (int exitCode);
334
335                 /// <summary>
336                 /// Substitute environment variables in the argument "name"
337                 /// </summary>
338                 public static string ExpandEnvironmentVariables (string name)
339                 {
340                         if (name == null)
341                                 throw new ArgumentNullException ("name");
342
343                         int off1 = name.IndexOf ('%');
344                         if (off1 == -1)
345                                 return name;
346
347                         int len = name.Length;
348                         int off2 = 0;
349                         if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
350                                 return name;
351
352                         StringBuilder result = new StringBuilder ();
353                         result.Append (name, 0, off1);
354                         Hashtable tbl = null;
355                         do {
356                                 string var = name.Substring (off1 + 1, off2 - off1 - 1);
357                                 string value = GetEnvironmentVariable (var);
358                                 if (value == null && Environment.IsRunningOnWindows) {
359                                         // On windows, env. vars. are case insensitive
360                                         if (tbl == null)
361                                                 tbl = GetEnvironmentVariablesNoCase ();
362
363                                         value = tbl [var] as string;
364                                 }
365                                 
366                                 // If value not found, add %FOO to stream,
367                                 //  and use the closing % for the next iteration.
368                                 // If value found, expand it in place of %FOO%
369                                 int realOldOff2 = off2;
370                                 if (value == null) {
371                                         result.Append ('%');
372                                         result.Append (var);
373                                         off2--;
374                                 } else {
375                                         result.Append (value);
376                                 }
377                                 int oldOff2 = off2;
378                                 off1 = name.IndexOf ('%', off2 + 1);
379                                 // If no % found for off1, don't look for one for off2
380                                 off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
381                                 // textLen is the length of text between the closing % of current iteration
382                                 //  and the starting % of the next iteration if any. This text is added to output
383                                 int textLen;
384                                 // If no new % found, use all the remaining text
385                                 if (off1 == -1 || off2 == -1)
386                                         textLen = len - oldOff2 - 1;
387                                 // If value found in current iteration, use text after current closing % and next %
388                                 else if(value != null)
389                                         textLen = off1 - oldOff2 - 1;
390                                 // If value not found in current iteration, but a % was found for next iteration,
391                                 //  use text from current closing % to the next %.
392                                 else
393                                         textLen = off1 - realOldOff2;
394                                 if(off1 >= oldOff2 || off1 == -1)
395                                         result.Append (name, oldOff2+1, textLen);
396                         } while (off2 > -1 && off2 < len);
397                                 
398                         return result.ToString ();
399
400                 }
401
402                 /// <summary>
403                 /// Return an array of the command line arguments of the current process
404                 /// </summary>
405                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
406                 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
407                 public extern static string[] GetCommandLineArgs ();
408
409                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
410                 internal extern static string internalGetEnvironmentVariable (string variable);
411
412                 /// <summary>
413                 /// Return a string containing the value of the environment
414                 /// variable identifed by parameter "variable"
415                 /// </summary>
416                 public static string GetEnvironmentVariable (string variable)
417                 {
418 #if !NET_2_1
419                         if (SecurityManager.SecurityEnabled) {
420                                 new EnvironmentPermission (EnvironmentPermissionAccess.Read, variable).Demand ();
421                         }
422 #endif
423                         return internalGetEnvironmentVariable (variable);
424                 }
425
426                 static Hashtable GetEnvironmentVariablesNoCase ()
427                 {
428                         Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
429                                                         CaseInsensitiveComparer.Default);
430
431                         foreach (string name in GetEnvironmentVariableNames ()) {
432                                 vars [name] = internalGetEnvironmentVariable (name);
433                         }
434
435                         return vars;
436                 }
437
438                 /// <summary>
439                 /// Return a set of all environment variables and their values
440                 /// </summary>
441 #if !NET_2_1
442                 public static IDictionary GetEnvironmentVariables ()
443                 {
444                         StringBuilder sb = null;
445                         if (SecurityManager.SecurityEnabled) {
446                                 // we must have access to each variable to get the lot
447                                 sb = new StringBuilder ();
448                                 // but (performance-wise) we do not want a stack-walk
449                                 // for each of them so we concatenate them
450                         }
451
452                         Hashtable vars = new Hashtable ();
453                         foreach (string name in GetEnvironmentVariableNames ()) {
454                                 vars [name] = internalGetEnvironmentVariable (name);
455                                 if (sb != null) {
456                                         sb.Append (name);
457                                         sb.Append (";");
458                                 }
459                         }
460
461                         if (sb != null) {
462                                 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
463                         }
464                         return vars;
465                 }
466 #else
467                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
468                 public static IDictionary GetEnvironmentVariables ()
469                 {
470                         Hashtable vars = new Hashtable ();
471                         foreach (string name in GetEnvironmentVariableNames ()) {
472                                 vars [name] = internalGetEnvironmentVariable (name);
473                         }
474                         return vars;
475                 }
476 #endif
477
478                 /// <summary>
479                 /// Returns the fully qualified path of the
480                 /// folder specified by the "folder" parameter
481                 /// </summary>
482                 public static string GetFolderPath (SpecialFolder folder)
483                 {
484                         return GetFolderPath (folder, SpecialFolderOption.None);
485                 }
486
487 // for monotouch, not monotouch_runtime
488 #if !(MONOTOUCH && FULL_AOT_RUNTIME)
489                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
490                 private extern static string GetWindowsFolderPath (int folder);
491
492 #if NET_4_0
493                 public
494 #endif
495                 static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
496                 {
497                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
498
499                         string dir = null;
500
501                         if (Environment.IsRunningOnWindows)
502                                 dir = GetWindowsFolderPath ((int) folder);
503                         else
504                                 dir = UnixGetFolderPath (folder, option);
505
506 #if !NET_2_1
507                         if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
508                                 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
509                         }
510 #endif
511                         return dir;
512                 }
513
514                 private static string ReadXdgUserDir (string config_dir, string home_dir, string key, string fallback)
515                 {
516                         string env_path = internalGetEnvironmentVariable (key);
517                         if (env_path != null && env_path != String.Empty) {
518                                 return env_path;
519                         }
520
521                         string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
522
523                         if (!File.Exists (user_dirs_path)) {
524                                 return Path.Combine (home_dir, fallback);
525                         }
526
527                         try {
528                                 using(StreamReader reader = new StreamReader (user_dirs_path)) {
529                                         string line;
530                                         while ((line = reader.ReadLine ()) != null) {
531                                                 line = line.Trim ();
532                                                 int delim_index = line.IndexOf ('=');
533                                                 if(delim_index > 8 && line.Substring (0, delim_index) == key) {
534                                                         string path = line.Substring (delim_index + 1).Trim ('"');
535                                                         bool relative = false;
536                                                         
537                                                         if (path.StartsWithOrdinalUnchecked ("$HOME/")) {
538                                                                 relative = true;
539                                                                 path = path.Substring (6);
540                                                         } else if (!path.StartsWithOrdinalUnchecked ("/")) {
541                                                                 relative = true;
542                                                         }
543                                                         
544                                                         return relative ? Path.Combine (home_dir, path) : path;
545                                                 }
546                                         }
547                                 }
548                         } catch (FileNotFoundException) {
549                         }
550
551                         return Path.Combine (home_dir, fallback);
552                 }
553
554
555                 // the security runtime (and maybe other parts of corlib) needs the
556                 // information to initialize themselves before permissions can be checked
557                 internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOption option)
558                 {
559                         string home = internalGetHome ();
560
561                         // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
562
563                         // note: skip security check for environment variables
564                         string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
565                         if ((data == null) || (data == String.Empty)) {
566                                 data = Path.Combine (home, ".local");
567                                 data = Path.Combine (data, "share");
568                         }
569
570                         // note: skip security check for environment variables
571                         string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
572                         if ((config == null) || (config == String.Empty)) {
573                                 config = Path.Combine (home, ".config");
574                         }
575
576                         switch (folder) {
577                         // MyComputer is a virtual directory
578                         case SpecialFolder.MyComputer:
579                                 return String.Empty;
580
581                         // personal == ~
582                         case SpecialFolder.Personal:
583                                 return home;
584
585                         // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
586                         case SpecialFolder.ApplicationData:
587                                 return config;
588
589                         //use FDO's DATA_HOME. This is *NOT* synced
590                         case SpecialFolder.LocalApplicationData:
591                                 return data;
592
593                         case SpecialFolder.Desktop:
594                         case SpecialFolder.DesktopDirectory:
595                                 return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
596
597                         case SpecialFolder.MyMusic:
598                                 if (Platform == PlatformID.MacOSX)
599                                         return Path.Combine (home, "Music");
600                                 else
601                                         return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
602
603                         case SpecialFolder.MyPictures:
604                                 if (Platform == PlatformID.MacOSX)
605                                         return Path.Combine (home, "Pictures");
606                                 else
607                                         return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
608                         
609                         case SpecialFolder.Templates:
610                                 return ReadXdgUserDir (config, home, "XDG_TEMPLATES_DIR", "Templates");
611 #if NET_4_0
612                         case SpecialFolder.MyVideos:
613                                 return ReadXdgUserDir (config, home, "XDG_VIDEOS_DIR", "Videos");
614 #endif
615 #if NET_4_0
616                         case SpecialFolder.CommonTemplates:
617                                 return "/usr/share/templates";
618                         case SpecialFolder.Fonts:
619                                 if (Platform == PlatformID.MacOSX)
620                                         return Path.Combine (home, "Library", "Fonts");
621                                 
622                                 return Path.Combine (home, ".fonts");
623 #endif
624                         // these simply dont exist on Linux
625                         // The spec says if a folder doesnt exist, we
626                         // should return ""
627                         case SpecialFolder.Favorites:
628                                 if (Platform == PlatformID.MacOSX)
629                                         return Path.Combine (home, "Library", "Favorites");
630                                 else
631                                         return String.Empty;
632                                 
633                         case SpecialFolder.ProgramFiles:
634                                 if (Platform == PlatformID.MacOSX)
635                                         return "/Applications";
636                                 else
637                                         return String.Empty;
638
639                         case SpecialFolder.InternetCache:
640                                 if (Platform == PlatformID.MacOSX)
641                                         return Path.Combine (home, "Library", "Caches");
642                                 else
643                                         return String.Empty;
644
645 #if NET_4_0
646                                 // #2873
647                         case SpecialFolder.UserProfile:
648                                 return home;
649 #endif
650
651                         case SpecialFolder.Programs:
652                         case SpecialFolder.SendTo:
653                         case SpecialFolder.StartMenu:
654                         case SpecialFolder.Startup:
655                         case SpecialFolder.Cookies:
656                         case SpecialFolder.History:
657                         case SpecialFolder.Recent:
658                         case SpecialFolder.CommonProgramFiles:
659                         case SpecialFolder.System:
660 #if NET_4_0
661                         case SpecialFolder.NetworkShortcuts:
662                         case SpecialFolder.CommonStartMenu:
663                         case SpecialFolder.CommonPrograms:
664                         case SpecialFolder.CommonStartup:
665                         case SpecialFolder.CommonDesktopDirectory:
666                         case SpecialFolder.PrinterShortcuts:
667                         case SpecialFolder.Windows:
668                         case SpecialFolder.SystemX86:
669                         case SpecialFolder.ProgramFilesX86:
670                         case SpecialFolder.CommonProgramFilesX86:
671                         case SpecialFolder.CommonDocuments:
672                         case SpecialFolder.CommonAdminTools:
673                         case SpecialFolder.AdminTools:
674                         case SpecialFolder.CommonMusic:
675                         case SpecialFolder.CommonPictures:
676                         case SpecialFolder.CommonVideos:
677                         case SpecialFolder.Resources:
678                         case SpecialFolder.LocalizedResources:
679                         case SpecialFolder.CommonOemLinks:
680                         case SpecialFolder.CDBurning:
681 #endif
682                                 return String.Empty;
683                         // This is where data common to all users goes
684                         case SpecialFolder.CommonApplicationData:
685                                 return "/usr/share";
686                         default:
687                                 throw new ArgumentException ("Invalid SpecialFolder");
688                         }
689                 }
690 #endif
691
692                 
693                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
694                 public static string[] GetLogicalDrives ()
695                 {
696                         return GetLogicalDrivesInternal ();
697                 }
698
699 #if !MOBILE
700                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
701                 private static extern void internalBroadcastSettingChange ();
702
703                 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
704                 {
705                         switch (target) {
706                         case EnvironmentVariableTarget.Process:
707                                 return GetEnvironmentVariable (variable);
708                         case EnvironmentVariableTarget.Machine:
709                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
710                                 if (!IsRunningOnWindows)
711                                         return null;
712                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
713                                         object regvalue = env.GetValue (variable);
714                                         return (regvalue == null) ? null : regvalue.ToString ();
715                                 }
716                         case EnvironmentVariableTarget.User:
717                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
718                                 if (!IsRunningOnWindows)
719                                         return null;
720                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
721                                         object regvalue = env.GetValue (variable);
722                                         return (regvalue == null) ? null : regvalue.ToString ();
723                                 }
724                         default:
725                                 throw new ArgumentException ("target");
726                         }
727                 }
728
729                 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
730                 {
731                         IDictionary variables = (IDictionary)new Hashtable ();
732                         switch (target) {
733                         case EnvironmentVariableTarget.Process:
734                                 variables = GetEnvironmentVariables ();
735                                 break;
736                         case EnvironmentVariableTarget.Machine:
737                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
738                                 if (IsRunningOnWindows) {
739                                         using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
740                                                 string[] value_names = env.GetValueNames ();
741                                                 foreach (string value_name in value_names)
742                                                         variables.Add (value_name, env.GetValue (value_name));
743                                         }
744                                 }
745                                 break;
746                         case EnvironmentVariableTarget.User:
747                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
748                                 if (IsRunningOnWindows) {
749                                         using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
750                                                 string[] value_names = env.GetValueNames ();
751                                                 foreach (string value_name in value_names)
752                                                         variables.Add (value_name, env.GetValue (value_name));
753                                         }
754                                 }
755                                 break;
756                         default:
757                                 throw new ArgumentException ("target");
758                         }
759                         return variables;
760                 }
761
762                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
763                 public static void SetEnvironmentVariable (string variable, string value)
764                 {
765                         SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
766                 }
767
768                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
769                 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
770                 {
771                         if (variable == null)
772                                 throw new ArgumentNullException ("variable");
773                         if (variable == String.Empty)
774                                 throw new ArgumentException ("String cannot be of zero length.", "variable");
775                         if (variable.IndexOf ('=') != -1)
776                                 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
777                         if (variable[0] == '\0')
778                                 throw new ArgumentException ("The first char in the string is the null character.", "variable");
779
780                         switch (target) {
781                         case EnvironmentVariableTarget.Process:
782                                 InternalSetEnvironmentVariable (variable, value);
783                                 break;
784                         case EnvironmentVariableTarget.Machine:
785                                 if (!IsRunningOnWindows)
786                                         return;
787                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
788                                         if (String.IsNullOrEmpty (value))
789                                                 env.DeleteValue (variable, false);
790                                         else
791                                                 env.SetValue (variable, value);
792                                         internalBroadcastSettingChange ();
793                                 }
794                                 break;
795                         case EnvironmentVariableTarget.User:
796                                 if (!IsRunningOnWindows)
797                                         return;
798                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
799                                         if (String.IsNullOrEmpty (value))
800                                                 env.DeleteValue (variable, false);
801                                         else
802                                                 env.SetValue (variable, value);
803                                         internalBroadcastSettingChange ();
804                                 }
805                                 break;
806                         default:
807                                 throw new ArgumentException ("target");
808                         }
809                 }
810 #else
811                 public static void SetEnvironmentVariable (string variable, string value)
812                 {
813                         if (variable == null)
814                                 throw new ArgumentNullException ("variable");
815                         if (variable == String.Empty)
816                                 throw new ArgumentException ("String cannot be of zero length.", "variable");
817                         if (variable.IndexOf ('=') != -1)
818                                 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
819                         if (variable[0] == '\0')
820                                 throw new ArgumentException ("The first char in the string is the null character.", "variable");
821
822                         InternalSetEnvironmentVariable (variable, value);
823                 }
824 #endif
825                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
826                 internal static extern void InternalSetEnvironmentVariable (string variable, string value);
827
828                 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
829                 public static void FailFast (string message)
830                 {
831                         throw new NotImplementedException ();
832                 }
833
834 #if NET_4_0
835                 [SecurityCritical]
836                 public static void FailFast (string message, Exception exception)
837                 {
838                         throw new NotImplementedException ();
839                 }
840 #endif
841
842 #if NET_4_0
843                 public static bool Is64BitOperatingSystem {
844                         get { return IntPtr.Size == 8; } // FIXME: is this good enough?
845                 }
846
847                 public static int SystemPageSize {
848                         get { return GetPageSize (); }
849                 }
850 #endif
851
852 #if NET_4_0
853                 public
854 #else
855                 internal
856 #endif
857                 static bool Is64BitProcess {
858                         get { return IntPtr.Size == 8; }
859                 }
860                 
861                 public static extern int ProcessorCount {
862                         [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
863                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
864                         get;                    
865                 }
866
867                 // private methods
868 #if (MONOTOUCH || MONODROID || XAMMAC)
869                 internal const bool IsRunningOnWindows = false;
870 #else
871                 internal static bool IsRunningOnWindows {
872                         get { return ((int) Platform < 4); }
873                 }
874 #endif
875
876 #if !NET_2_1
877                 //
878                 // Used by gacutil.exe
879                 //
880 #pragma warning disable 169             
881                 private static string GacPath {
882                         get {
883                                 if (Environment.IsRunningOnWindows) {
884                                         /* On windows, we don't know the path where mscorlib.dll will be installed */
885                                         string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
886                                         return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
887                                 }
888
889                                 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
890                         }
891                 }
892 #pragma warning restore 169
893                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
894                 internal extern static string internalGetGacPath ();
895 #endif
896                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
897                 private extern static string [] GetLogicalDrivesInternal ();
898
899                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
900                 private extern static string [] GetEnvironmentVariableNames ();
901
902                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
903                 internal extern static string GetMachineConfigPath ();
904
905                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
906                 internal extern static string internalGetHome ();
907
908                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
909                 internal extern static int GetPageSize ();
910
911                 static internal bool IsUnix {
912                         get {
913                                 int platform = (int) Environment.Platform;
914
915                                 return (platform == 4 || platform == 128 || platform == 6);
916                         }
917                 }
918                 static internal bool IsMacOS {
919                         get {
920                                 return Environment.Platform == PlatformID.MacOSX;
921                         }
922                 }
923         }
924 }
925