1 //------------------------------------------------------------------------------
3 // System.Environment.cs
5 // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
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:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
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.
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Security;
39 using System.Security.Permissions;
41 using System.Runtime.InteropServices;
42 using System.Threading;
47 public static class Environment {
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.
58 #pragma warning disable 169
59 private const int mono_corlib_version = 101;
60 #pragma warning restore 169
63 public enum SpecialFolder
76 DesktopDirectory = 0x10,
78 ApplicationData = 0x1a,
79 LocalApplicationData = 0x1c,
83 CommonApplicationData = 0x23,
87 CommonProgramFiles = 0x2b,
88 #if NET_4_0 || MOONLIGHT || MOBILE
92 NetworkShortcuts = 0x13,
94 CommonStartMenu = 0x16,
95 CommonPrograms = 0x17,
97 CommonDesktopDirectory = 0x19,
98 PrinterShortcuts = 0x1b,
102 ProgramFilesX86 = 0x2a,
103 CommonProgramFilesX86 = 0x2c,
104 CommonTemplates = 0x2d,
105 CommonDocuments = 0x2e,
106 CommonAdminTools = 0x2f,
109 CommonPictures = 0x36,
112 LocalizedResources = 0x39,
113 CommonOemLinks = 0x3a,
123 enum SpecialFolderOption {
125 DoNotVerify = 0x4000,
130 /// Gets the command line for this process
132 public static string CommandLine {
133 // note: security demand inherited from calling GetCommandLineArgs
135 StringBuilder sb = new StringBuilder ();
136 foreach (string str in GetCommandLineArgs ()) {
140 for (int i = 0; i < s.Length; i++) {
141 if (quote.Length == 0 && Char.IsWhiteSpace (s [i])) {
143 } else if (s [i] == '"') {
147 if (escape && quote.Length != 0) {
148 s = s.Replace ("\"", "\\\"");
150 sb.AppendFormat ("{0}{1}{0} ", quote, s);
154 return sb.ToString ();
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
163 public static string CurrentDirectory
166 return Directory.GetCurrentDirectory ();
169 Directory.SetCurrentDirectory (value);
174 public static int CurrentManagedThreadId {
176 return Thread.CurrentThread.ManagedThreadId;
182 /// Gets or sets the exit code of this process
184 public extern static int ExitCode
186 [MethodImplAttribute (MethodImplOptions.InternalCall)]
188 [MethodImplAttribute (MethodImplOptions.InternalCall)]
192 static public extern bool HasShutdownStarted
194 [MethodImplAttribute (MethodImplOptions.InternalCall)]
200 /// Gets the name of the local computer
202 public extern static string MachineName {
203 [MethodImplAttribute (MethodImplOptions.InternalCall)]
204 [EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
205 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
209 [MethodImplAttribute (MethodImplOptions.InternalCall)]
210 extern static string GetNewLine ();
214 /// Gets the standard new line value
216 public static string NewLine {
227 // Support methods and fields for OSVersion property
229 static OperatingSystem os;
231 static extern PlatformID Platform {
232 [MethodImplAttribute (MethodImplOptions.InternalCall)]
236 [MethodImplAttribute (MethodImplOptions.InternalCall)]
237 internal static extern string GetOSVersionString ();
240 /// Gets the current OS version information
242 public static OperatingSystem OSVersion {
245 Version v = Version.CreateFromString (GetOSVersionString ());
246 PlatformID p = Platform;
247 if (p == PlatformID.MacOSX)
249 os = new OperatingSystem (p, v);
258 public static string StackTrace {
259 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
261 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (0, true);
262 return trace.ToString ();
267 /// Get a fully qualified path to the system directory
269 public static string SystemDirectory {
271 return GetFolderPath (SpecialFolder.System);
276 /// Get the number of milliseconds that have elapsed since the system was booted
278 public extern static int TickCount {
279 [MethodImplAttribute (MethodImplOptions.InternalCall)]
284 /// Get UserDomainName
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")]
295 /// Gets a flag indicating whether the process is in interactive mode
297 [MonoTODO ("Currently always returns false, regardless of interactive state")]
298 public static bool UserInteractive {
305 /// Get the user name of current process is running under
307 public extern static string UserName {
308 [MethodImplAttribute (MethodImplOptions.InternalCall)]
309 [EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
314 /// Get the version of the common language runtime
316 public static Version Version {
318 return new Version (Consts.FxFileVersion);
323 /// Get the amount of physical memory mapped to process
325 [MonoTODO ("Currently always returns zero")]
326 public static long WorkingSet {
327 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
331 [MethodImplAttribute (MethodImplOptions.InternalCall)]
332 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
333 public extern static void Exit (int exitCode);
336 /// Substitute environment variables in the argument "name"
338 public static string ExpandEnvironmentVariables (string name)
341 throw new ArgumentNullException ("name");
343 int off1 = name.IndexOf ('%');
347 int len = name.Length;
349 if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
352 StringBuilder result = new StringBuilder ();
353 result.Append (name, 0, off1);
354 Hashtable tbl = null;
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
361 tbl = GetEnvironmentVariablesNoCase ();
363 value = tbl [var] as string;
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%
374 result.Append (value);
377 off1 = name.IndexOf ('%', off2 + 1);
378 // If no % found for off1, don't look for one for off2
379 off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
380 // textLen is the length of text between the closing % of current iteration
381 // and the starting % of the next iteration if any. This text is added to output
383 // If no new % found, use all the remaining text
384 if (off1 == -1 || off2 == -1)
385 textLen = len - oldOff2 - 1;
386 // If value found in current iteration, use text after current closing % and next %
387 else if(value != null)
388 textLen = off1 - oldOff2 - 1;
389 // If value not found in current iteration, but a % was found for next iteration,
390 // use text from current closing % to the next %.
392 textLen = off1 - oldOff2;
393 if(off1 >= oldOff2 || off1 == -1)
394 result.Append (name, oldOff2+1, textLen);
395 } while (off2 > -1 && off2 < len);
397 return result.ToString ();
402 /// Return an array of the command line arguments of the current process
404 [MethodImplAttribute (MethodImplOptions.InternalCall)]
405 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
406 public extern static string[] GetCommandLineArgs ();
408 [MethodImplAttribute (MethodImplOptions.InternalCall)]
409 internal extern static string internalGetEnvironmentVariable (string variable);
412 /// Return a string containing the value of the environment
413 /// variable identifed by parameter "variable"
415 public static string GetEnvironmentVariable (string variable)
418 if (SecurityManager.SecurityEnabled) {
419 new EnvironmentPermission (EnvironmentPermissionAccess.Read, variable).Demand ();
422 return internalGetEnvironmentVariable (variable);
425 static Hashtable GetEnvironmentVariablesNoCase ()
427 Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
428 CaseInsensitiveComparer.Default);
430 foreach (string name in GetEnvironmentVariableNames ()) {
431 vars [name] = internalGetEnvironmentVariable (name);
438 /// Return a set of all environment variables and their values
441 public static IDictionary GetEnvironmentVariables ()
443 StringBuilder sb = null;
444 if (SecurityManager.SecurityEnabled) {
445 // we must have access to each variable to get the lot
446 sb = new StringBuilder ();
447 // but (performance-wise) we do not want a stack-walk
448 // for each of them so we concatenate them
451 Hashtable vars = new Hashtable ();
452 foreach (string name in GetEnvironmentVariableNames ()) {
453 vars [name] = internalGetEnvironmentVariable (name);
461 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
466 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
467 public static IDictionary GetEnvironmentVariables ()
469 Hashtable vars = new Hashtable ();
470 foreach (string name in GetEnvironmentVariableNames ()) {
471 vars [name] = internalGetEnvironmentVariable (name);
477 [MethodImplAttribute (MethodImplOptions.InternalCall)]
478 private extern static string GetWindowsFolderPath (int folder);
481 /// Returns the fully qualified path of the
482 /// folder specified by the "folder" parameter
484 public static string GetFolderPath (SpecialFolder folder)
486 return GetFolderPath (folder, SpecialFolderOption.None);
491 static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
493 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
497 if (Environment.IsRunningOnWindows)
498 dir = GetWindowsFolderPath ((int) folder);
500 dir = UnixGetFolderPath (folder, option);
503 if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
504 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
510 private static string ReadXdgUserDir (string config_dir, string home_dir, string key, string fallback)
512 string env_path = internalGetEnvironmentVariable (key);
513 if (env_path != null && env_path != String.Empty) {
517 string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
519 if (!File.Exists (user_dirs_path)) {
520 return Path.Combine (home_dir, fallback);
524 using(StreamReader reader = new StreamReader (user_dirs_path)) {
526 while ((line = reader.ReadLine ()) != null) {
528 int delim_index = line.IndexOf ('=');
529 if(delim_index > 8 && line.Substring (0, delim_index) == key) {
530 string path = line.Substring (delim_index + 1).Trim ('"');
531 bool relative = false;
533 if (path.StartsWith ("$HOME/")) {
535 path = path.Substring (6);
536 } else if (!path.StartsWith ("/")) {
540 return relative ? Path.Combine (home_dir, path) : path;
544 } catch (FileNotFoundException) {
547 return Path.Combine (home_dir, fallback);
551 // the security runtime (and maybe other parts of corlib) needs the
552 // information to initialize themselves before permissions can be checked
553 internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOption option)
555 string home = internalGetHome ();
557 // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
559 // note: skip security check for environment variables
560 string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
561 if ((data == null) || (data == String.Empty)) {
562 data = Path.Combine (home, ".local");
563 data = Path.Combine (data, "share");
566 // note: skip security check for environment variables
567 string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
568 if ((config == null) || (config == String.Empty)) {
569 config = Path.Combine (home, ".config");
573 // MyComputer is a virtual directory
574 case SpecialFolder.MyComputer:
578 case SpecialFolder.Personal:
580 return Path.Combine (home, "Documents");
584 // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
585 case SpecialFolder.ApplicationData:
588 string dir = Path.Combine (Path.Combine (home, "Documents"), ".config");
589 if (option == SpecialFolderOption.Create){
590 if (!Directory.Exists (dir))
591 Directory.CreateDirectory (dir);
598 //use FDO's DATA_HOME. This is *NOT* synced
599 case SpecialFolder.LocalApplicationData:
602 string dir = Path.Combine (home, "Documents");
603 if (!Directory.Exists (dir))
604 Directory.CreateDirectory (dir);
612 case SpecialFolder.Desktop:
613 case SpecialFolder.DesktopDirectory:
614 return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
616 case SpecialFolder.MyMusic:
617 if (Platform == PlatformID.MacOSX)
618 return Path.Combine (home, "Music");
620 return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
622 case SpecialFolder.MyPictures:
623 if (Platform == PlatformID.MacOSX)
624 return Path.Combine (home, "Pictures");
626 return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
628 case SpecialFolder.Templates:
629 return ReadXdgUserDir (config, home, "XDG_TEMPLATES_DIR", "Templates");
630 #if NET_4_0 || MOONLIGHT || MOBILE
631 case SpecialFolder.MyVideos:
632 return ReadXdgUserDir (config, home, "XDG_VIDEOS_DIR", "Videos");
635 case SpecialFolder.CommonTemplates:
636 return "/usr/share/templates";
637 case SpecialFolder.Fonts:
638 if (Platform == PlatformID.MacOSX)
639 return Path.Combine (home, "Library", "Fonts");
641 return Path.Combine (home, ".fonts");
643 // these simply dont exist on Linux
644 // The spec says if a folder doesnt exist, we
646 case SpecialFolder.Favorites:
647 if (Platform == PlatformID.MacOSX)
648 return Path.Combine (home, "Library", "Favorites");
652 case SpecialFolder.ProgramFiles:
653 if (Platform == PlatformID.MacOSX)
654 return "/Applications";
658 case SpecialFolder.InternetCache:
659 if (Platform == PlatformID.MacOSX)
660 return Path.Combine (home, "Library", "Caches");
666 case SpecialFolder.UserProfile:
670 case SpecialFolder.Programs:
671 case SpecialFolder.SendTo:
672 case SpecialFolder.StartMenu:
673 case SpecialFolder.Startup:
674 case SpecialFolder.Cookies:
675 case SpecialFolder.History:
676 case SpecialFolder.Recent:
677 case SpecialFolder.CommonProgramFiles:
678 case SpecialFolder.System:
680 case SpecialFolder.NetworkShortcuts:
681 case SpecialFolder.CommonStartMenu:
682 case SpecialFolder.CommonPrograms:
683 case SpecialFolder.CommonStartup:
684 case SpecialFolder.CommonDesktopDirectory:
685 case SpecialFolder.PrinterShortcuts:
686 case SpecialFolder.Windows:
687 case SpecialFolder.SystemX86:
688 case SpecialFolder.ProgramFilesX86:
689 case SpecialFolder.CommonProgramFilesX86:
690 case SpecialFolder.CommonDocuments:
691 case SpecialFolder.CommonAdminTools:
692 case SpecialFolder.AdminTools:
693 case SpecialFolder.CommonMusic:
694 case SpecialFolder.CommonPictures:
695 case SpecialFolder.CommonVideos:
696 case SpecialFolder.Resources:
697 case SpecialFolder.LocalizedResources:
698 case SpecialFolder.CommonOemLinks:
699 case SpecialFolder.CDBurning:
702 // This is where data common to all users goes
703 case SpecialFolder.CommonApplicationData:
706 throw new ArgumentException ("Invalid SpecialFolder");
711 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
712 public static string[] GetLogicalDrives ()
714 return GetLogicalDrivesInternal ();
718 [MethodImplAttribute (MethodImplOptions.InternalCall)]
719 private static extern void internalBroadcastSettingChange ();
721 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
724 case EnvironmentVariableTarget.Process:
725 return GetEnvironmentVariable (variable);
726 case EnvironmentVariableTarget.Machine:
727 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
728 if (!IsRunningOnWindows)
730 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
731 object regvalue = env.GetValue (variable);
732 return (regvalue == null) ? null : regvalue.ToString ();
734 case EnvironmentVariableTarget.User:
735 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
736 if (!IsRunningOnWindows)
738 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
739 object regvalue = env.GetValue (variable);
740 return (regvalue == null) ? null : regvalue.ToString ();
743 throw new ArgumentException ("target");
747 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
749 IDictionary variables = (IDictionary)new Hashtable ();
751 case EnvironmentVariableTarget.Process:
752 variables = GetEnvironmentVariables ();
754 case EnvironmentVariableTarget.Machine:
755 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
756 if (IsRunningOnWindows) {
757 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
758 string[] value_names = env.GetValueNames ();
759 foreach (string value_name in value_names)
760 variables.Add (value_name, env.GetValue (value_name));
764 case EnvironmentVariableTarget.User:
765 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
766 if (IsRunningOnWindows) {
767 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
768 string[] value_names = env.GetValueNames ();
769 foreach (string value_name in value_names)
770 variables.Add (value_name, env.GetValue (value_name));
775 throw new ArgumentException ("target");
780 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
781 public static void SetEnvironmentVariable (string variable, string value)
783 SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
786 [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
787 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
789 if (variable == null)
790 throw new ArgumentNullException ("variable");
791 if (variable == String.Empty)
792 throw new ArgumentException ("String cannot be of zero length.", "variable");
793 if (variable.IndexOf ('=') != -1)
794 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
795 if (variable[0] == '\0')
796 throw new ArgumentException ("The first char in the string is the null character.", "variable");
799 case EnvironmentVariableTarget.Process:
800 InternalSetEnvironmentVariable (variable, value);
802 case EnvironmentVariableTarget.Machine:
803 if (!IsRunningOnWindows)
805 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
806 if (String.IsNullOrEmpty (value))
807 env.DeleteValue (variable, false);
809 env.SetValue (variable, value);
810 internalBroadcastSettingChange ();
813 case EnvironmentVariableTarget.User:
814 if (!IsRunningOnWindows)
816 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
817 if (String.IsNullOrEmpty (value))
818 env.DeleteValue (variable, false);
820 env.SetValue (variable, value);
821 internalBroadcastSettingChange ();
825 throw new ArgumentException ("target");
829 [MethodImplAttribute (MethodImplOptions.InternalCall)]
830 internal static extern void InternalSetEnvironmentVariable (string variable, string value);
832 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
833 public static void FailFast (string message)
835 throw new NotImplementedException ();
838 #if NET_4_0 || MOONLIGHT || MOBILE
840 public static void FailFast (string message, Exception exception)
842 throw new NotImplementedException ();
847 public static bool Is64BitOperatingSystem {
848 get { return IntPtr.Size == 8; } // FIXME: is this good enough?
851 public static bool Is64BitProcess {
852 get { return Is64BitOperatingSystem; }
855 public static int SystemPageSize {
856 get { return GetPageSize (); }
860 public static extern int ProcessorCount {
861 [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
862 [MethodImplAttribute (MethodImplOptions.InternalCall)]
868 internal static bool IsRunningOnWindows {
869 get { return ((int) Platform < 4); }
873 // Used by gacutil.exe
875 #pragma warning disable 169
876 private static string GacPath {
878 if (Environment.IsRunningOnWindows) {
879 /* On windows, we don't know the path where mscorlib.dll will be installed */
880 string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
881 return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
884 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
887 #pragma warning restore 169
888 [MethodImplAttribute (MethodImplOptions.InternalCall)]
889 internal extern static string internalGetGacPath ();
891 [MethodImplAttribute (MethodImplOptions.InternalCall)]
892 private extern static string [] GetLogicalDrivesInternal ();
894 [MethodImplAttribute (MethodImplOptions.InternalCall)]
895 private extern static string [] GetEnvironmentVariableNames ();
897 [MethodImplAttribute (MethodImplOptions.InternalCall)]
898 internal extern static string GetMachineConfigPath ();
900 [MethodImplAttribute (MethodImplOptions.InternalCall)]
901 internal extern static string internalGetHome ();
903 [MethodImplAttribute (MethodImplOptions.InternalCall)]
904 internal extern static int GetPageSize ();
906 static internal bool IsUnix {
908 int platform = (int) Environment.Platform;
910 return (platform == 4 || platform == 128 || platform == 6);
913 static internal bool IsMacOS {
915 return Environment.Platform == PlatformID.MacOSX;