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;
46 public static class Environment {
49 * This is the version number of the corlib-runtime interface. When
50 * making changes to this interface (by changing the layout
51 * of classes the runtime knows about, changing icall signature or
52 * semantics etc), increment this variable. Also increment the
53 * pair of this variable in the runtime in metadata/appdomain.c.
54 * Changes which are already detected at runtime, like the addition
55 * of icalls, do not require an increment.
57 #pragma warning disable 169
58 private const int mono_corlib_version = 98;
59 #pragma warning restore 169
62 public enum SpecialFolder
75 DesktopDirectory = 0x10,
77 ApplicationData = 0x1a,
78 LocalApplicationData = 0x1c,
82 CommonApplicationData = 0x23,
86 CommonProgramFiles = 0x2b,
87 #if NET_4_0 || MOONLIGHT || MOBILE
91 NetworkShortcuts = 0x13,
93 CommonStartMenu = 0x16,
94 CommonPrograms = 0x17,
96 CommonDesktopDirectory = 0x19,
97 PrinterShortcuts = 0x1b,
101 ProgramFilesX86 = 0x2a,
102 CommonProgramFilesX86 = 0x2c,
103 CommonTemplates = 0x2d,
104 CommonDocuments = 0x2e,
105 CommonAdminTools = 0x2f,
108 CommonPictures = 0x36,
111 LocalizedResources = 0x39,
112 CommonOemLinks = 0x3a,
122 enum SpecialFolderOption {
124 DoNotVerify = 0x4000,
129 /// Gets the command line for this process
131 public static string CommandLine {
132 // note: security demand inherited from calling GetCommandLineArgs
134 StringBuilder sb = new StringBuilder ();
135 foreach (string str in GetCommandLineArgs ()) {
139 for (int i = 0; i < s.Length; i++) {
140 if (quote.Length == 0 && Char.IsWhiteSpace (s [i])) {
142 } else if (s [i] == '"') {
146 if (escape && quote.Length != 0) {
147 s = s.Replace ("\"", "\\\"");
149 sb.AppendFormat ("{0}{1}{0} ", quote, s);
153 return sb.ToString ();
158 /// Gets or sets the current directory. Actually this is supposed to get
159 /// and/or set the process start directory acording to the documentation
160 /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
162 public static string CurrentDirectory
165 return Directory.GetCurrentDirectory ();
168 Directory.SetCurrentDirectory (value);
173 /// Gets or sets the exit code of this process
175 public extern static int ExitCode
177 [MethodImplAttribute (MethodImplOptions.InternalCall)]
179 [MethodImplAttribute (MethodImplOptions.InternalCall)]
183 static public extern bool HasShutdownStarted
185 [MethodImplAttribute (MethodImplOptions.InternalCall)]
191 /// Gets the name of the local computer
193 public extern static string MachineName {
194 [MethodImplAttribute (MethodImplOptions.InternalCall)]
195 [EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
196 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
200 [MethodImplAttribute (MethodImplOptions.InternalCall)]
201 extern static string GetNewLine ();
205 /// Gets the standard new line value
207 public static string NewLine {
218 // Support methods and fields for OSVersion property
220 static OperatingSystem os;
222 static extern PlatformID Platform {
223 [MethodImplAttribute (MethodImplOptions.InternalCall)]
227 [MethodImplAttribute (MethodImplOptions.InternalCall)]
228 internal static extern string GetOSVersionString ();
231 /// Gets the current OS version information
233 public static OperatingSystem OSVersion {
236 Version v = Version.CreateFromString (GetOSVersionString ());
237 PlatformID p = Platform;
238 if (p == PlatformID.MacOSX)
240 os = new OperatingSystem (p, v);
249 public static string StackTrace {
250 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
252 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (0, true);
253 return trace.ToString ();
258 /// Get a fully qualified path to the system directory
260 public static string SystemDirectory {
262 return GetFolderPath (SpecialFolder.System);
267 /// Get the number of milliseconds that have elapsed since the system was booted
269 public extern static int TickCount {
270 [MethodImplAttribute (MethodImplOptions.InternalCall)]
275 /// Get UserDomainName
277 public static string UserDomainName {
278 // FIXME: this variable doesn't exist (at least not on WinXP) - reported to MS as FDBK20562
279 [EnvironmentPermission (SecurityAction.Demand, Read="USERDOMAINNAME")]
286 /// Gets a flag indicating whether the process is in interactive mode
288 [MonoTODO ("Currently always returns false, regardless of interactive state")]
289 public static bool UserInteractive {
296 /// Get the user name of current process is running under
298 public extern static string UserName {
299 [MethodImplAttribute (MethodImplOptions.InternalCall)]
300 [EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
305 /// Get the version of the common language runtime
307 public static Version Version {
309 return new Version (Consts.FxFileVersion);
314 /// Get the amount of physical memory mapped to process
316 [MonoTODO ("Currently always returns zero")]
317 public static long WorkingSet {
318 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
322 [MethodImplAttribute (MethodImplOptions.InternalCall)]
323 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
324 public extern static void Exit (int exitCode);
327 /// Substitute environment variables in the argument "name"
329 public static string ExpandEnvironmentVariables (string name)
332 throw new ArgumentNullException ("name");
334 int off1 = name.IndexOf ('%');
338 int len = name.Length;
340 if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
343 StringBuilder result = new StringBuilder ();
344 result.Append (name, 0, off1);
345 Hashtable tbl = null;
347 string var = name.Substring (off1 + 1, off2 - off1 - 1);
348 string value = GetEnvironmentVariable (var);
349 if (value == null && Environment.IsRunningOnWindows) {
350 // On windows, env. vars. are case insensitive
352 tbl = GetEnvironmentVariablesNoCase ();
354 value = tbl [var] as string;
357 // If value not found, add %FOO to stream,
358 // and use the closing % for the next iteration.
359 // If value found, expand it in place of %FOO%
365 result.Append (value);
368 off1 = name.IndexOf ('%', off2 + 1);
369 // If no % found for off1, don't look for one for off2
370 off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
371 // textLen is the length of text between the closing % of current iteration
372 // and the starting % of the next iteration if any. This text is added to output
374 // If no new % found, use all the remaining text
375 if (off1 == -1 || off2 == -1)
376 textLen = len - oldOff2 - 1;
377 // If value found in current iteration, use text after current closing % and next %
378 else if(value != null)
379 textLen = off1 - oldOff2 - 1;
380 // If value not found in current iteration, but a % was found for next iteration,
381 // use text from current closing % to the next %.
383 textLen = off1 - oldOff2;
384 if(off1 >= oldOff2 || off1 == -1)
385 result.Append (name, oldOff2+1, textLen);
386 } while (off2 > -1 && off2 < len);
388 return result.ToString ();
393 /// Return an array of the command line arguments of the current process
395 [MethodImplAttribute (MethodImplOptions.InternalCall)]
396 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
397 public extern static string[] GetCommandLineArgs ();
399 [MethodImplAttribute (MethodImplOptions.InternalCall)]
400 internal extern static string internalGetEnvironmentVariable (string variable);
403 /// Return a string containing the value of the environment
404 /// variable identifed by parameter "variable"
406 public static string GetEnvironmentVariable (string variable)
409 if (SecurityManager.SecurityEnabled) {
410 new EnvironmentPermission (EnvironmentPermissionAccess.Read, variable).Demand ();
413 return internalGetEnvironmentVariable (variable);
416 static Hashtable GetEnvironmentVariablesNoCase ()
418 Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
419 CaseInsensitiveComparer.Default);
421 foreach (string name in GetEnvironmentVariableNames ()) {
422 vars [name] = internalGetEnvironmentVariable (name);
429 /// Return a set of all environment variables and their values
432 public static IDictionary GetEnvironmentVariables ()
434 StringBuilder sb = null;
435 if (SecurityManager.SecurityEnabled) {
436 // we must have access to each variable to get the lot
437 sb = new StringBuilder ();
438 // but (performance-wise) we do not want a stack-walk
439 // for each of them so we concatenate them
442 Hashtable vars = new Hashtable ();
443 foreach (string name in GetEnvironmentVariableNames ()) {
444 vars [name] = internalGetEnvironmentVariable (name);
452 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
457 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
458 public static IDictionary GetEnvironmentVariables ()
460 Hashtable vars = new Hashtable ();
461 foreach (string name in GetEnvironmentVariableNames ()) {
462 vars [name] = internalGetEnvironmentVariable (name);
468 [MethodImplAttribute (MethodImplOptions.InternalCall)]
469 private extern static string GetWindowsFolderPath (int folder);
472 /// Returns the fully qualified path of the
473 /// folder specified by the "folder" parameter
475 public static string GetFolderPath (SpecialFolder folder)
477 return GetFolderPath (folder, SpecialFolderOption.None);
482 static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
484 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
488 if (Environment.IsRunningOnWindows)
489 dir = GetWindowsFolderPath ((int) folder);
491 dir = UnixGetFolderPath (folder, option);
494 if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
495 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
501 private static string ReadXdgUserDir (string config_dir, string home_dir, string key, string fallback)
503 string env_path = internalGetEnvironmentVariable (key);
504 if (env_path != null && env_path != String.Empty) {
508 string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
510 if (!File.Exists (user_dirs_path)) {
511 return Path.Combine (home_dir, fallback);
515 using(StreamReader reader = new StreamReader (user_dirs_path)) {
517 while ((line = reader.ReadLine ()) != null) {
519 int delim_index = line.IndexOf ('=');
520 if(delim_index > 8 && line.Substring (0, delim_index) == key) {
521 string path = line.Substring (delim_index + 1).Trim ('"');
522 bool relative = false;
524 if (path.StartsWith ("$HOME/")) {
526 path = path.Substring (6);
527 } else if (!path.StartsWith ("/")) {
531 return relative ? Path.Combine (home_dir, path) : path;
535 } catch (FileNotFoundException) {
538 return Path.Combine (home_dir, fallback);
542 // the security runtime (and maybe other parts of corlib) needs the
543 // information to initialize themselves before permissions can be checked
544 internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOption option)
546 string home = internalGetHome ();
548 // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
550 // note: skip security check for environment variables
551 string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
552 if ((data == null) || (data == String.Empty)) {
553 data = Path.Combine (home, ".local");
554 data = Path.Combine (data, "share");
557 // note: skip security check for environment variables
558 string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
559 if ((config == null) || (config == String.Empty)) {
560 config = Path.Combine (home, ".config");
564 // MyComputer is a virtual directory
565 case SpecialFolder.MyComputer:
569 case SpecialFolder.Personal:
571 return Path.Combine (home, "Documents");
575 // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
576 case SpecialFolder.ApplicationData:
579 string dir = Path.Combine (Path.Combine (home, "Documents"), ".config");
580 if (option == SpecialFolderOption.Create){
581 if (!Directory.Exists (dir))
582 Directory.CreateDirectory (dir);
589 //use FDO's DATA_HOME. This is *NOT* synced
590 case SpecialFolder.LocalApplicationData:
593 string dir = Path.Combine (home, "Documents");
594 if (!Directory.Exists (dir))
595 Directory.CreateDirectory (dir);
603 case SpecialFolder.Desktop:
604 case SpecialFolder.DesktopDirectory:
605 return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
607 case SpecialFolder.MyMusic:
608 if (Platform == PlatformID.MacOSX)
609 return Path.Combine (home, "Music");
611 return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
613 case SpecialFolder.MyPictures:
614 if (Platform == PlatformID.MacOSX)
615 return Path.Combine (home, "Pictures");
617 return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
619 case SpecialFolder.Templates:
620 return ReadXdgUserDir (config, home, "XDG_TEMPLATES_DIR", "Templates");
621 #if NET_4_0 || MOONLIGHT || MOBILE
622 case SpecialFolder.MyVideos:
623 return ReadXdgUserDir (config, home, "XDG_VIDEOS_DIR", "Videos");
626 case SpecialFolder.CommonTemplates:
627 return "/usr/share/templates";
628 case SpecialFolder.Fonts:
629 if (Platform == PlatformID.MacOSX)
630 return Path.Combine (home, "Library", "Fonts");
632 return Path.Combine (home, ".fonts");
634 // these simply dont exist on Linux
635 // The spec says if a folder doesnt exist, we
637 case SpecialFolder.Favorites:
638 if (Platform == PlatformID.MacOSX)
639 return Path.Combine (home, "Library", "Favorites");
643 case SpecialFolder.ProgramFiles:
644 if (Platform == PlatformID.MacOSX)
645 return "/Applications";
649 case SpecialFolder.InternetCache:
650 if (Platform == PlatformID.MacOSX)
651 return Path.Combine (home, "Library", "Caches");
655 case SpecialFolder.Programs:
656 case SpecialFolder.SendTo:
657 case SpecialFolder.StartMenu:
658 case SpecialFolder.Startup:
659 case SpecialFolder.Cookies:
660 case SpecialFolder.History:
661 case SpecialFolder.Recent:
662 case SpecialFolder.CommonProgramFiles:
663 case SpecialFolder.System:
665 case SpecialFolder.NetworkShortcuts:
666 case SpecialFolder.CommonStartMenu:
667 case SpecialFolder.CommonPrograms:
668 case SpecialFolder.CommonStartup:
669 case SpecialFolder.CommonDesktopDirectory:
670 case SpecialFolder.PrinterShortcuts:
671 case SpecialFolder.Windows:
672 case SpecialFolder.UserProfile:
673 case SpecialFolder.SystemX86:
674 case SpecialFolder.ProgramFilesX86:
675 case SpecialFolder.CommonProgramFilesX86:
676 case SpecialFolder.CommonDocuments:
677 case SpecialFolder.CommonAdminTools:
678 case SpecialFolder.AdminTools:
679 case SpecialFolder.CommonMusic:
680 case SpecialFolder.CommonPictures:
681 case SpecialFolder.CommonVideos:
682 case SpecialFolder.Resources:
683 case SpecialFolder.LocalizedResources:
684 case SpecialFolder.CommonOemLinks:
685 case SpecialFolder.CDBurning:
688 // This is where data common to all users goes
689 case SpecialFolder.CommonApplicationData:
692 throw new ArgumentException ("Invalid SpecialFolder");
697 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
698 public static string[] GetLogicalDrives ()
700 return GetLogicalDrivesInternal ();
704 [MethodImplAttribute (MethodImplOptions.InternalCall)]
705 private static extern void internalBroadcastSettingChange ();
707 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
710 case EnvironmentVariableTarget.Process:
711 return GetEnvironmentVariable (variable);
712 case EnvironmentVariableTarget.Machine:
713 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
714 if (!IsRunningOnWindows)
716 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
717 object regvalue = env.GetValue (variable);
718 return (regvalue == null) ? null : regvalue.ToString ();
720 case EnvironmentVariableTarget.User:
721 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
722 if (!IsRunningOnWindows)
724 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
725 object regvalue = env.GetValue (variable);
726 return (regvalue == null) ? null : regvalue.ToString ();
729 throw new ArgumentException ("target");
733 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
735 IDictionary variables = (IDictionary)new Hashtable ();
737 case EnvironmentVariableTarget.Process:
738 variables = GetEnvironmentVariables ();
740 case EnvironmentVariableTarget.Machine:
741 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
742 if (IsRunningOnWindows) {
743 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
744 string[] value_names = env.GetValueNames ();
745 foreach (string value_name in value_names)
746 variables.Add (value_name, env.GetValue (value_name));
750 case EnvironmentVariableTarget.User:
751 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
752 if (IsRunningOnWindows) {
753 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
754 string[] value_names = env.GetValueNames ();
755 foreach (string value_name in value_names)
756 variables.Add (value_name, env.GetValue (value_name));
761 throw new ArgumentException ("target");
766 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
767 public static void SetEnvironmentVariable (string variable, string value)
769 SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
772 [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
773 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
775 if (variable == null)
776 throw new ArgumentNullException ("variable");
777 if (variable == String.Empty)
778 throw new ArgumentException ("String cannot be of zero length.", "variable");
779 if (variable.IndexOf ('=') != -1)
780 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
781 if (variable[0] == '\0')
782 throw new ArgumentException ("The first char in the string is the null character.", "variable");
785 case EnvironmentVariableTarget.Process:
786 InternalSetEnvironmentVariable (variable, value);
788 case EnvironmentVariableTarget.Machine:
789 if (!IsRunningOnWindows)
791 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
792 if (String.IsNullOrEmpty (value))
793 env.DeleteValue (variable, false);
795 env.SetValue (variable, value);
796 internalBroadcastSettingChange ();
799 case EnvironmentVariableTarget.User:
800 if (!IsRunningOnWindows)
802 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
803 if (String.IsNullOrEmpty (value))
804 env.DeleteValue (variable, false);
806 env.SetValue (variable, value);
807 internalBroadcastSettingChange ();
811 throw new ArgumentException ("target");
815 [MethodImplAttribute (MethodImplOptions.InternalCall)]
816 internal static extern void InternalSetEnvironmentVariable (string variable, string value);
818 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
819 public static void FailFast (string message)
821 throw new NotImplementedException ();
824 #if NET_4_0 || MOONLIGHT || MOBILE
826 public static void FailFast (string message, Exception exception)
828 throw new NotImplementedException ();
833 public static bool Is64BitOperatingSystem {
834 get { return IntPtr.Size == 8; } // FIXME: is this good enough?
837 public static bool Is64BitProcess {
838 get { return Is64BitOperatingSystem; }
841 public static int SystemPageSize {
842 get { return GetPageSize (); }
846 public static extern int ProcessorCount {
847 [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
848 [MethodImplAttribute (MethodImplOptions.InternalCall)]
854 internal static bool IsRunningOnWindows {
855 get { return ((int) Platform < 4); }
859 // Used by gacutil.exe
861 #pragma warning disable 169
862 private static string GacPath {
864 if (Environment.IsRunningOnWindows) {
865 /* On windows, we don't know the path where mscorlib.dll will be installed */
866 string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
867 return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
870 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
873 #pragma warning restore 169
874 [MethodImplAttribute (MethodImplOptions.InternalCall)]
875 internal extern static string internalGetGacPath ();
877 [MethodImplAttribute (MethodImplOptions.InternalCall)]
878 private extern static string [] GetLogicalDrivesInternal ();
880 [MethodImplAttribute (MethodImplOptions.InternalCall)]
881 private extern static string [] GetEnvironmentVariableNames ();
883 [MethodImplAttribute (MethodImplOptions.InternalCall)]
884 internal extern static string GetMachineConfigPath ();
886 [MethodImplAttribute (MethodImplOptions.InternalCall)]
887 internal extern static string internalGetHome ();
889 [MethodImplAttribute (MethodImplOptions.InternalCall)]
890 internal extern static int GetPageSize ();
892 static internal bool IsUnix {
894 int platform = (int) Environment.Platform;
896 return (platform == 4 || platform == 128 || platform == 6);
899 static internal bool IsMacOS {
901 return Environment.Platform == PlatformID.MacOSX;