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 = 111;
60 #pragma warning restore 169
63 public enum SpecialFolder
76 DesktopDirectory = 0x10,
78 ApplicationData = 0x1a,
79 LocalApplicationData = 0x1c,
83 CommonApplicationData = 0x23,
87 CommonProgramFiles = 0x2b,
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%
369 int realOldOff2 = off2;
375 result.Append (value);
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
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 %.
393 textLen = off1 - realOldOff2;
394 if(off1 >= oldOff2 || off1 == -1)
395 result.Append (name, oldOff2+1, textLen);
396 } while (off2 > -1 && off2 < len);
398 return result.ToString ();
403 /// Return an array of the command line arguments of the current process
405 [MethodImplAttribute (MethodImplOptions.InternalCall)]
406 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
407 public extern static string[] GetCommandLineArgs ();
409 [MethodImplAttribute (MethodImplOptions.InternalCall)]
410 internal extern static string internalGetEnvironmentVariable (string variable);
413 /// Return a string containing the value of the environment
414 /// variable identifed by parameter "variable"
416 public static string GetEnvironmentVariable (string variable)
419 if (SecurityManager.SecurityEnabled) {
420 new EnvironmentPermission (EnvironmentPermissionAccess.Read, variable).Demand ();
423 return internalGetEnvironmentVariable (variable);
426 static Hashtable GetEnvironmentVariablesNoCase ()
428 Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
429 CaseInsensitiveComparer.Default);
431 foreach (string name in GetEnvironmentVariableNames ()) {
432 vars [name] = internalGetEnvironmentVariable (name);
439 /// Return a set of all environment variables and their values
442 public static IDictionary GetEnvironmentVariables ()
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
452 Hashtable vars = new Hashtable ();
453 foreach (string name in GetEnvironmentVariableNames ()) {
454 vars [name] = internalGetEnvironmentVariable (name);
462 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
467 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
468 public static IDictionary GetEnvironmentVariables ()
470 Hashtable vars = new Hashtable ();
471 foreach (string name in GetEnvironmentVariableNames ()) {
472 vars [name] = internalGetEnvironmentVariable (name);
478 [MethodImplAttribute (MethodImplOptions.InternalCall)]
479 private extern static string GetWindowsFolderPath (int folder);
482 /// Returns the fully qualified path of the
483 /// folder specified by the "folder" parameter
485 public static string GetFolderPath (SpecialFolder folder)
487 return GetFolderPath (folder, SpecialFolderOption.None);
492 static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
494 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
498 if (Environment.IsRunningOnWindows)
499 dir = GetWindowsFolderPath ((int) folder);
501 dir = UnixGetFolderPath (folder, option);
504 if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
505 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
511 private static string ReadXdgUserDir (string config_dir, string home_dir, string key, string fallback)
513 string env_path = internalGetEnvironmentVariable (key);
514 if (env_path != null && env_path != String.Empty) {
518 string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
520 if (!File.Exists (user_dirs_path)) {
521 return Path.Combine (home_dir, fallback);
525 using(StreamReader reader = new StreamReader (user_dirs_path)) {
527 while ((line = reader.ReadLine ()) != null) {
529 int delim_index = line.IndexOf ('=');
530 if(delim_index > 8 && line.Substring (0, delim_index) == key) {
531 string path = line.Substring (delim_index + 1).Trim ('"');
532 bool relative = false;
534 if (path.StartsWithOrdinalUnchecked ("$HOME/")) {
536 path = path.Substring (6);
537 } else if (!path.StartsWithOrdinalUnchecked ("/")) {
541 return relative ? Path.Combine (home_dir, path) : path;
545 } catch (FileNotFoundException) {
548 return Path.Combine (home_dir, fallback);
552 // the security runtime (and maybe other parts of corlib) needs the
553 // information to initialize themselves before permissions can be checked
554 internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOption option)
556 string home = internalGetHome ();
558 // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
560 // note: skip security check for environment variables
561 string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
562 if ((data == null) || (data == String.Empty)) {
563 data = Path.Combine (home, ".local");
564 data = Path.Combine (data, "share");
567 // note: skip security check for environment variables
568 string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
569 if ((config == null) || (config == String.Empty)) {
570 config = Path.Combine (home, ".config");
574 // MyComputer is a virtual directory
575 case SpecialFolder.MyComputer:
579 case SpecialFolder.Personal:
581 return Path.Combine (home, "Documents");
585 // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
586 case SpecialFolder.ApplicationData:
589 string dir = Path.Combine (Path.Combine (home, "Documents"), ".config");
590 if (option == SpecialFolderOption.Create){
591 if (!Directory.Exists (dir))
592 Directory.CreateDirectory (dir);
599 //use FDO's DATA_HOME. This is *NOT* synced
600 case SpecialFolder.LocalApplicationData:
603 string dir = Path.Combine (home, "Documents");
604 if (!Directory.Exists (dir))
605 Directory.CreateDirectory (dir);
613 case SpecialFolder.Desktop:
614 case SpecialFolder.DesktopDirectory:
615 return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
617 case SpecialFolder.MyMusic:
618 if (Platform == PlatformID.MacOSX)
619 return Path.Combine (home, "Music");
621 return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
623 case SpecialFolder.MyPictures:
624 if (Platform == PlatformID.MacOSX)
625 return Path.Combine (home, "Pictures");
627 return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
629 case SpecialFolder.Templates:
630 return ReadXdgUserDir (config, home, "XDG_TEMPLATES_DIR", "Templates");
632 case SpecialFolder.MyVideos:
633 return ReadXdgUserDir (config, home, "XDG_VIDEOS_DIR", "Videos");
636 case SpecialFolder.CommonTemplates:
637 return "/usr/share/templates";
638 case SpecialFolder.Fonts:
639 if (Platform == PlatformID.MacOSX)
640 return Path.Combine (home, "Library", "Fonts");
642 return Path.Combine (home, ".fonts");
644 // these simply dont exist on Linux
645 // The spec says if a folder doesnt exist, we
647 case SpecialFolder.Favorites:
648 if (Platform == PlatformID.MacOSX)
649 return Path.Combine (home, "Library", "Favorites");
653 case SpecialFolder.ProgramFiles:
654 if (Platform == PlatformID.MacOSX)
655 return "/Applications";
659 case SpecialFolder.InternetCache:
660 if (Platform == PlatformID.MacOSX)
661 return Path.Combine (home, "Library", "Caches");
667 case SpecialFolder.UserProfile:
671 case SpecialFolder.Programs:
672 case SpecialFolder.SendTo:
673 case SpecialFolder.StartMenu:
674 case SpecialFolder.Startup:
675 case SpecialFolder.Cookies:
676 case SpecialFolder.History:
677 case SpecialFolder.Recent:
678 case SpecialFolder.CommonProgramFiles:
679 case SpecialFolder.System:
681 case SpecialFolder.NetworkShortcuts:
682 case SpecialFolder.CommonStartMenu:
683 case SpecialFolder.CommonPrograms:
684 case SpecialFolder.CommonStartup:
685 case SpecialFolder.CommonDesktopDirectory:
686 case SpecialFolder.PrinterShortcuts:
687 case SpecialFolder.Windows:
688 case SpecialFolder.SystemX86:
689 case SpecialFolder.ProgramFilesX86:
690 case SpecialFolder.CommonProgramFilesX86:
691 case SpecialFolder.CommonDocuments:
692 case SpecialFolder.CommonAdminTools:
693 case SpecialFolder.AdminTools:
694 case SpecialFolder.CommonMusic:
695 case SpecialFolder.CommonPictures:
696 case SpecialFolder.CommonVideos:
697 case SpecialFolder.Resources:
698 case SpecialFolder.LocalizedResources:
699 case SpecialFolder.CommonOemLinks:
700 case SpecialFolder.CDBurning:
703 // This is where data common to all users goes
704 case SpecialFolder.CommonApplicationData:
707 throw new ArgumentException ("Invalid SpecialFolder");
712 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
713 public static string[] GetLogicalDrives ()
715 return GetLogicalDrivesInternal ();
719 [MethodImplAttribute (MethodImplOptions.InternalCall)]
720 private static extern void internalBroadcastSettingChange ();
722 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
725 case EnvironmentVariableTarget.Process:
726 return GetEnvironmentVariable (variable);
727 case EnvironmentVariableTarget.Machine:
728 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
729 if (!IsRunningOnWindows)
731 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
732 object regvalue = env.GetValue (variable);
733 return (regvalue == null) ? null : regvalue.ToString ();
735 case EnvironmentVariableTarget.User:
736 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
737 if (!IsRunningOnWindows)
739 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
740 object regvalue = env.GetValue (variable);
741 return (regvalue == null) ? null : regvalue.ToString ();
744 throw new ArgumentException ("target");
748 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
750 IDictionary variables = (IDictionary)new Hashtable ();
752 case EnvironmentVariableTarget.Process:
753 variables = GetEnvironmentVariables ();
755 case EnvironmentVariableTarget.Machine:
756 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
757 if (IsRunningOnWindows) {
758 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
759 string[] value_names = env.GetValueNames ();
760 foreach (string value_name in value_names)
761 variables.Add (value_name, env.GetValue (value_name));
765 case EnvironmentVariableTarget.User:
766 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
767 if (IsRunningOnWindows) {
768 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
769 string[] value_names = env.GetValueNames ();
770 foreach (string value_name in value_names)
771 variables.Add (value_name, env.GetValue (value_name));
776 throw new ArgumentException ("target");
781 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
782 public static void SetEnvironmentVariable (string variable, string value)
784 SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
787 [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
788 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
790 if (variable == null)
791 throw new ArgumentNullException ("variable");
792 if (variable == String.Empty)
793 throw new ArgumentException ("String cannot be of zero length.", "variable");
794 if (variable.IndexOf ('=') != -1)
795 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
796 if (variable[0] == '\0')
797 throw new ArgumentException ("The first char in the string is the null character.", "variable");
800 case EnvironmentVariableTarget.Process:
801 InternalSetEnvironmentVariable (variable, value);
803 case EnvironmentVariableTarget.Machine:
804 if (!IsRunningOnWindows)
806 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
807 if (String.IsNullOrEmpty (value))
808 env.DeleteValue (variable, false);
810 env.SetValue (variable, value);
811 internalBroadcastSettingChange ();
814 case EnvironmentVariableTarget.User:
815 if (!IsRunningOnWindows)
817 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
818 if (String.IsNullOrEmpty (value))
819 env.DeleteValue (variable, false);
821 env.SetValue (variable, value);
822 internalBroadcastSettingChange ();
826 throw new ArgumentException ("target");
830 [MethodImplAttribute (MethodImplOptions.InternalCall)]
831 internal static extern void InternalSetEnvironmentVariable (string variable, string value);
833 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
834 public static void FailFast (string message)
836 throw new NotImplementedException ();
841 public static void FailFast (string message, Exception exception)
843 throw new NotImplementedException ();
848 public static bool Is64BitOperatingSystem {
849 get { return IntPtr.Size == 8; } // FIXME: is this good enough?
852 public static int SystemPageSize {
853 get { return GetPageSize (); }
862 static bool Is64BitProcess {
863 get { return IntPtr.Size == 8; }
866 public static extern int ProcessorCount {
867 [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
868 [MethodImplAttribute (MethodImplOptions.InternalCall)]
874 internal const bool IsRunningOnWindows = false;
876 internal static bool IsRunningOnWindows {
877 get { return ((int) Platform < 4); }
883 // Used by gacutil.exe
885 #pragma warning disable 169
886 private static string GacPath {
888 if (Environment.IsRunningOnWindows) {
889 /* On windows, we don't know the path where mscorlib.dll will be installed */
890 string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
891 return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
894 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
897 #pragma warning restore 169
898 [MethodImplAttribute (MethodImplOptions.InternalCall)]
899 internal extern static string internalGetGacPath ();
901 [MethodImplAttribute (MethodImplOptions.InternalCall)]
902 private extern static string [] GetLogicalDrivesInternal ();
904 [MethodImplAttribute (MethodImplOptions.InternalCall)]
905 private extern static string [] GetEnvironmentVariableNames ();
907 [MethodImplAttribute (MethodImplOptions.InternalCall)]
908 internal extern static string GetMachineConfigPath ();
910 [MethodImplAttribute (MethodImplOptions.InternalCall)]
911 internal extern static string internalGetHome ();
913 [MethodImplAttribute (MethodImplOptions.InternalCall)]
914 internal extern static int GetPageSize ();
916 static internal bool IsUnix {
918 int platform = (int) Environment.Platform;
920 return (platform == 4 || platform == 128 || platform == 6);
923 static internal bool IsMacOS {
925 return Environment.Platform == PlatformID.MacOSX;