//****************************************************************************************************** // Common.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 04/03/2006 - J. Ritchie Carroll // Generated original version of source code. // 12/13/2007 - Darrell Zuercher // Edited code comments. // 09/08/2008 - J. Ritchie Carroll // Converted to C#. // 02/13/2009 - Josh L. Patterson // Edited Code Comments. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 09/17/2009 - Pinal C. Patel // Modified GetApplicationType() to remove dependency on HttpContext.Current. // 09/28/2010 - Pinal C. Patel // Cached the current ApplicationType returned by GetApplicationType() for better performance. // 12/05/2010 - Pinal C. Patel // Added an overload for TypeConvertToString() that takes CultureInfo as a parameter. // 12/07/2010 - Pinal C. Patel // Updated TypeConvertToString() to return an empty string if the passed in value is null. // 03/09/2011 - Pinal C. Patel // Moved UpdateType enumeration from GSF.Services.ServiceProcess namespace for broader usage. // 04/07/2011 - J. Ritchie Carroll // Added ToNonNullNorEmptyString() and ToNonNullNorWhiteSpace() extensions. // 12/14/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Web.Hosting; using GSF.Collections; using GSF.Console; using GSF.IO; using GSF.Reflection; using Microsoft.Win32; namespace GSF { #region [ Enumerations ] /// /// Specifies the type of the application. /// public enum ApplicationType { /// /// Application is of unknown type. /// Unknown = 0, /// /// Application doesn't require a subsystem. /// Native = 1, /// /// Application runs in the Windows GUI subsystem. /// WindowsGui = 2, /// /// Application runs in the Windows character subsystem. /// WindowsCui = 3, /// /// Application runs in the OS/2 character subsystem. /// OS2Cui = 5, /// /// Application runs in the POSIX character subsystem. /// PosixCui = 7, /// /// Application is a native Win9x driver. /// NativeWindows = 8, /// /// Application runs in the Windows CE subsystem. /// WindowsCEGui = 9, /// /// The application is a web site or web application. /// Web = 100 } /// /// Indicates the type of update. /// public enum UpdateType { /// /// Update is informational. /// Information, /// /// Update is a warning. /// Warning, /// /// Update is an alarm. /// Alarm } #endregion // This is the location for handy miscellaneous functions that are difficult to categorize elsewhere. For the most // part these functions may have the most value in a Visual Basic application which supports importing functions // down to a class level, e.g.: Imports GSF.Common /// /// Defines common global functions. /// public static class Common { private static ApplicationType? s_applicationType; private static string s_osPlatformName; private static PlatformID s_osPlatformID = PlatformID.Win32S; /// /// Determines if the current system is a POSIX style environment. /// /// /// /// Since a .NET application compiled under Mono can run under both Windows and Unix style platforms, /// you can use this property to easily determine the current operating environment. /// /// /// This property will return true for both MacOSX and Unix environments. Use the Platform property /// of the to determine more specific platform type, e.g., /// MacOSX or Unix. Note that all flavors of Linux will show up as . /// /// public static readonly bool IsPosixEnvironment = (Path.DirectorySeparatorChar == '/'); // This is how Mono source often checks this /// /// Determines if the code base is currently running under Mono. /// /// /// This property can be used to make a run-time determination if Windows or Mono based .NET is being used. However, it is /// highly recommended to use the MONO compiler directive wherever possible instead of determining this at run-time. /// public static bool IsMono = ((object)Type.GetType("Mono.Runtime") != null); /// Returns one of two strongly-typed objects. /// One of two objects, depending on the evaluation of given expression. /// The expression you want to evaluate. /// Returned if expression evaluates to True. /// Returned if expression evaluates to False. /// Return type used for immediate expression /// /// This function acts as a strongly-typed immediate if (a.k.a. inline if). /// /// It is expected that this function will only be used in languages that do not support ?: conditional operations, e.g., Visual Basic.NET. /// In Visual Basic this function can be used as a strongly-typed IIf replacement by specifying "Imports GSF.Common". /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T IIf(bool expression, T truePart, T falsePart) { return (expression ? truePart : falsePart); } /// Creates a strongly-typed Array. /// New array of specified type. /// Desired length of new array. /// Return type for new array. /// /// It is expected that this function will only be used in Visual Basic.NET. /// /// The Array.CreateInstance provides better performance and more direct CLR access for array creation (not to /// mention less confusion on the matter of array lengths) in VB.NET, however the returned System.Array is not /// typed properly. This function properly casts the return array based on the type specification helping /// when Option Strict is enabled. /// /// /// /// /// Dim buffer As Byte() = CreateArray(Of Byte)(12) /// Dim matrix As Integer()() = CreateArray(Of Integer())(10) /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] CreateArray(int length) { // The following provides better performance than "Return New T(length) {}". // ReSharper disable once UseArrayCreationExpression.1 return (T[])Array.CreateInstance(typeof(T), length); } /// Creates a strongly-typed Array with an initial value parameter. /// New array of specified type. /// Desired length of new array. /// Value used to initialize all array elements. /// Return type for new array. /// /// It is expected that this function will only be used in Visual Basic.NET. /// /// /// /// Dim elements As Integer() = CreateArray(12, -1) /// Dim names As String() = CreateArray(100, "undefined") /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] CreateArray(int length, T initialValue) { T[] typedArray = CreateArray(length); // Initializes all elements with the default value. for (int x = 0; x < typedArray.Length; x++) { typedArray[x] = initialValue; } return typedArray; } /// /// Gets the type of the currently executing application. /// /// One of the values. public static ApplicationType GetApplicationType() { if (s_applicationType.HasValue) return s_applicationType.Value; if (HostingEnvironment.IsHosted) { s_applicationType = ApplicationType.Web; } else { try { // References: // - http://support.microsoft.com/kb/65122 // - http://support.microsoft.com/kb/90493/en-us // - http://www.codeguru.com/cpp/w-p/system/misc/article.php/c2897/ // We will always have an entry assembly for windows application. FileStream exe = new FileStream(AssemblyInfo.EntryAssembly.Location, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); byte[] dosHeader = new byte[64]; byte[] exeHeader = new byte[248]; byte[] subSystem = new byte[2]; exe.Read(dosHeader, 0, dosHeader.Length); exe.Seek(BitConverter.ToInt16(dosHeader, 60), SeekOrigin.Begin); exe.Read(exeHeader, 0, exeHeader.Length); exe.Close(); Buffer.BlockCopy(exeHeader, 92, subSystem, 0, 2); s_applicationType = ((ApplicationType)(LittleEndian.ToInt16(subSystem, 0))); } catch { // We are unable to determine the application type. s_applicationType = ApplicationType.Unknown; } } return s_applicationType.Value; } /// /// Gets the operating system /// /// The operating system . /// /// This function will properly detect the platform ID, even if running on Mac. /// public static PlatformID GetOSPlatformID() { if (s_osPlatformID != PlatformID.Win32S) return s_osPlatformID; s_osPlatformID = Environment.OSVersion.Platform; if (s_osPlatformID == PlatformID.Unix) { // Environment.OSVersion.Platform can report Unix when running on Mac OS X try { s_osPlatformID = Command.Execute("uname").StandardOutput.StartsWith("Darwin", StringComparison.OrdinalIgnoreCase) ? PlatformID.MacOSX : PlatformID.Unix; } catch { // Fall back on looking for Mac specific root folders: if (Directory.Exists("/Applications") && Directory.Exists("/System") && Directory.Exists("/Users") && Directory.Exists("/Volumes")) s_osPlatformID = PlatformID.MacOSX; } } return s_osPlatformID; } /// /// Gets the operating system product name. /// /// Operating system product name. public static string GetOSProductName() { if ((object)s_osPlatformName != null) return s_osPlatformName; switch (GetOSPlatformID()) { case PlatformID.Unix: case PlatformID.MacOSX: // Call sw_vers on Mac to get product name and version information, Linux could have this try { string output = Command.Execute("sw_vers").StandardOutput; Dictionary kvps = output.ParseKeyValuePairs('\n', ':'); if (kvps.Count > 0) s_osPlatformName = kvps.Values.Select(val => val.Trim()).ToDelimitedString(" "); } catch { s_osPlatformName = null; } if (string.IsNullOrEmpty(s_osPlatformName)) { // Try some common ways to get product name on Linux, some might work on Mac try { foreach (string fileName in FilePath.GetFileList("/etc/*release*")) { using (StreamReader reader = new StreamReader(fileName)) { string line = reader.ReadLine(); while ((object)line != null) { if (line.StartsWith("PRETTY_NAME", StringComparison.OrdinalIgnoreCase) && !line.Contains('#')) { string[] parts = line.Split('='); if (parts.Length == 2) { s_osPlatformName = parts[1].Replace("\"", ""); break; } } line = reader.ReadLine(); } } if (!string.IsNullOrEmpty(s_osPlatformName)) break; } } catch { try { string output = Command.Execute("lsb_release", "-a").StandardOutput; Dictionary kvps = output.ParseKeyValuePairs('\n', ':'); if (kvps.TryGetValue("Description", out s_osPlatformName) && !string.IsNullOrEmpty(s_osPlatformName)) s_osPlatformName = s_osPlatformName.Trim(); } catch { s_osPlatformName = null; } } } break; default: // Get Windows product name try { s_osPlatformName = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductName", null).ToString(); } catch { s_osPlatformName = null; } break; } if (string.IsNullOrWhiteSpace(s_osPlatformName)) s_osPlatformName = GetOSPlatformID().ToString(); if (IsMono) s_osPlatformName += " using Mono"; return s_osPlatformName; } /// /// Gets the memory usage by the current process. /// /// Memory usage by the current process. public static long GetProcessMemory() { long processMemory = Environment.WorkingSet; if (processMemory == 0 && IsPosixEnvironment) { try { double percentOfTotal; long totalMemory; // Get total system memory using (PerformanceCounter counter = new PerformanceCounter("Mono Memory", "Total Physical Memory")) totalMemory = counter.RawValue; // Get percent of total memory used by current process string output = Command.Execute("ps", string.Format("-p {0} -o %mem", Process.GetCurrentProcess().Id)).StandardOutput; string[] lines = output.Split('\n'); if (lines.Length > 1 && double.TryParse(lines[1].Trim(), out percentOfTotal)) processMemory = (long)Math.Round(percentOfTotal / 100.0D * totalMemory); } catch { processMemory = -1; } } return processMemory; } // The following "ToNonNullString" methods extend all class based objects. Note that these extension methods can be // called even if the base object is null, hence the value of these methods. Our philosophy for this project has been // "not" to apply extensions to all objects (this to avoid general namespace pollution) and make sure extensions are // grouped together in their own source file (e.g., StringExtensions.cs); however these items do apply to all items // and are essentially type-less hence their location in the "Common" class. These extension methods are at least // limited to classes and won't show up on native types and custom structures. /// /// Converts value to string; null objects (or DBNull objects) will return an empty string (""). /// /// of to convert to string. /// Value to convert to string. /// as a string; if is null, empty string ("") will be returned. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToNonNullString(this T value) where T : class { return ((object)value == null || value is DBNull ? "" : value.ToString()); } /// /// Converts value to string; null objects (or DBNull objects) will return specified . /// /// of to convert to string. /// Value to convert to string. /// to return if is null. /// as a string; if is null, will be returned. /// cannot be null. public static string ToNonNullString(this T value, string nonNullValue) where T : class { if ((object)nonNullValue == null) throw new ArgumentNullException("nonNullValue"); return ((object)value == null || value is DBNull ? nonNullValue : value.ToString()); } // We handle strings as a special version of the ToNullNullString extension to handle documentation a little differently /// /// Makes sure returned string value is not null; if this string is null, empty string ("") will be returned. /// /// to verify is not null. /// value; if is null, empty string ("") will be returned. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToNonNullString(this string value) { return ((object)value == null ? "" : value); } /// /// Converts value to string; null objects, DBNull objects or empty strings will return specified . /// /// of to convert to string. /// Value to convert to string. /// to return if is null. /// as a string; if is null, DBNull or an empty string will be returned. /// must not be null or an empty string. public static string ToNonNullNorEmptyString(this T value, string nonNullNorEmptyValue = " ") where T : class { if (string.IsNullOrEmpty(nonNullNorEmptyValue)) throw new ArgumentException("Must not be null or an empty string", "nonNullNorEmptyValue"); if ((object)value == null || value is DBNull) return nonNullNorEmptyValue; string valueAsString = value.ToString(); return (string.IsNullOrEmpty(valueAsString) ? nonNullNorEmptyValue : valueAsString); } /// /// Converts value to string; null objects, DBNull objects, empty strings or all white space strings will return specified . /// /// of to convert to string. /// Value to convert to string. /// to return if is null. /// as a string; if is null, DBNull, empty or all white space, will be returned. /// must not be null, an empty string or white space. public static string ToNonNullNorWhiteSpace(this T value, string nonNullNorWhiteSpaceValue = "_") where T : class { if (string.IsNullOrWhiteSpace(nonNullNorWhiteSpaceValue)) throw new ArgumentException("Must not be null, an empty string or white space", "nonNullNorWhiteSpaceValue"); if ((object)value == null || value is DBNull) return nonNullNorWhiteSpaceValue; string valueAsString = value.ToString(); return (string.IsNullOrWhiteSpace(valueAsString) ? nonNullNorWhiteSpaceValue : valueAsString); } /// /// Converts to a using an appropriate . /// /// Value to convert to a . /// converted to a . /// /// /// If fails, the value's ToString() value will be returned. /// Returned value will never be null, if no value exists an empty string ("") will be returned. /// /// /// You can use the string extension method to /// convert the string back to its original . /// /// public static string TypeConvertToString(object value) { return TypeConvertToString(value, null); } /// /// Converts to a using an appropriate . /// /// Value to convert to a . /// to use for the conversion. /// converted to a . /// /// /// If fails, the value's ToString() value will be returned. /// Returned value will never be null, if no value exists an empty string ("") will be returned. /// /// /// You can use the string extension method to /// convert the string back to its original . /// /// public static string TypeConvertToString(object value, CultureInfo culture) { // Don't proceed further if value is null. if ((object)value == null) return string.Empty; // If value is already a string, no need to attempt conversion string valueAsString = value as string; if ((object)valueAsString != null) return valueAsString; // Initialize culture info if not specified. if ((object)culture == null) culture = CultureInfo.InvariantCulture; try { // Attempt to use type converter to set field value TypeConverter converter = TypeDescriptor.GetConverter(value); return converter.ConvertToString(null, culture, value).ToNonNullString(); } catch { // Otherwise just call object's ToString method return value.ToNonNullString(); } } /// Gets a high-resolution number of seconds, including fractional seconds, that have /// elapsed since 12:00:00 midnight, January 1, 0001. public static double SystemTimer { get { return Ticks.ToSeconds(DateTime.UtcNow.Ticks); } } /// Determines if given item is equal to its default value (e.g., null or 0.0). /// Object to evaluate. /// Result of evaluation as a . /// /// Native types default to zero, not null, therefore this can be used to evaluate if an item is its default (i.e., uninitialized) value. /// public static bool IsDefaultValue(object item) { // Only reference types can be null, therefore null is its default value if ((object)item == null) return true; Type itemType = item.GetType(); if (!itemType.IsValueType) return false; // Handle common types IConvertible convertible = item as IConvertible; if ((object)convertible != null) { try { switch (convertible.GetTypeCode()) { case TypeCode.Boolean: return ((bool)item == default(bool)); case TypeCode.SByte: return ((sbyte)item == default(sbyte)); case TypeCode.Byte: return ((byte)item == default(byte)); case TypeCode.Int16: return ((short)item == default(short)); case TypeCode.UInt16: return ((ushort)item == default(ushort)); case TypeCode.Int32: return ((int)item == default(int)); case TypeCode.UInt32: return ((uint)item == default(uint)); case TypeCode.Int64: return ((long)item == default(long)); case TypeCode.UInt64: return ((ulong)item == default(ulong)); case TypeCode.Single: return ((float)item == default(float)); case TypeCode.Double: return ((double)item == default(double)); case TypeCode.Decimal: return ((decimal)item == default(decimal)); case TypeCode.Char: return ((char)item == default(char)); case TypeCode.DateTime: return ((DateTime)item == default(DateTime)); } } catch (InvalidCastException) { // An exception here indicates that the item is a custom type that // lied about its type code. The type should still be instantiable, // so we can ignore this exception } } // Handle custom value types return ((ValueType)item).Equals(Activator.CreateInstance(itemType)); } /// Determines if given item is a reference type. /// Object to evaluate. /// Result of evaluation as a . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsReference(object item) { return !(item is ValueType); } /// Determines if given item is a reference type but not a string. /// Object to evaluate. /// Result of evaluation as a . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNonStringReference(object item) { return (IsReference(item) && !(item is string)); } /// Determines if given item is numeric. /// Object to evaluate. /// Result of evaluation as a . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNumeric(object item) { IConvertible convertible = item as IConvertible; if ((object)convertible != null) { switch (convertible.GetTypeCode()) { case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; case TypeCode.Char: case TypeCode.String: double result; return double.TryParse(convertible.ToString(null), out result); } } return false; } /// Returns the smallest item from a list of parameters. /// Return type that is the minimum value in the . /// A variable number of parameters of the specified type. /// Result is the minimum value of type in the . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Min(params T[] itemList) { return itemList.Min(); } /// Returns the largest item from a list of parameters. /// Return type that is the maximum value in the . /// A variable number of parameters of the specified type . /// Result is the maximum value of type in the . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Max(params T[] itemList) { return itemList.Max(); } /// Returns the value that is neither the largest nor the smallest. /// of the objects passed to and returned from this method. /// Value 1. /// Value 2. /// Value 3. /// Result is the value that is neither the largest nor the smallest. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Mid(T value1, T value2, T value3) where T : IComparable { if ((object)value1 == null) throw new ArgumentNullException("value1"); if ((object)value2 == null) throw new ArgumentNullException("value2"); if ((object)value3 == null) throw new ArgumentNullException("value3"); int comp1to2 = value1.CompareTo(value2); int comp1to3 = value1.CompareTo(value3); int comp2to3 = value2.CompareTo(value3); // If 3 is the smallest, pick the smaller of 1 and 2 if (comp1to3 >= 0 && comp2to3 >= 0) return (comp1to2 <= 0) ? value1 : value2; // If 2 is the smallest, pick the smaller of 1 and 3 if (comp1to2 >= 0 && comp2to3 <= 0) return (comp1to3 <= 0) ? value1 : value3; // 1 is the smallest so pick the smaller of 2 and 3 return (comp2to3 <= 0) ? value2 : value3; } #region [ Old Code ] ///// Returns the smallest item from a list of parameters. ///// A variable number of parameters of type ///// Result is the minimum value of type in the . //public static object Min(params object[] itemList) //{ // return itemList.Min(CompareObjects); //} ///// Returns the largest item from a list of parameters. ///// A variable number of parameters of type ///// Result is the maximum value of type in the . //public static object Max(params object[] itemList) //{ // return itemList.Max(CompareObjects); //} ///// Compares two elements of any type. ///// Object which is compared to object . ///// Object which is compared against. ///// Result of comparison as an . //public static int CompareObjects(object x, object y) //{ // // Just using Visual Basic runtime to compare two objects of unknown types - this can be a very // // complex process and the VB runtime library is distributed with .NET anyway, so why not use it: // // Note that comparison is based on VB object comparison rules: // // ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_vbalr/html/d6cb12a8-e52e-46a7-8aaf-f804d634a825.htm // return (Microsoft.VisualBasic.CompilerServices.Operators.ConditionalCompareObjectLess(x, y, false) ? -1 : // (Microsoft.VisualBasic.CompilerServices.Operators.ConditionalCompareObjectGreater(x, y, false) ? 1 : 0)); //} // This function is probably not that useful ///// Time zone names enumeration used to look up desired time zone in GetWin32TimeZone function. //public enum TimeZoneName //{ // DaylightName, // DisplayName, // StandardName //} ///// Returns the specified Win32 time zone, using specified name. ///// Value of name used for time zone lookup. ///// Type of name used for time zone lookup. //public static TimeZoneInfo GetTimeZone(string name, TimeZoneName lookupBy) //{ // foreach (TimeZoneInfo timeZone in TimeZoneInfo.GetSystemTimeZones()) // { // if (lookupBy == TimeZoneName.DaylightName) // { // if (string.Compare(timeZone.DaylightName, name, true) == 0) // return timeZone; // } // else if (lookupBy == TimeZoneName.DisplayName) // { // if (string.Compare(timeZone.DisplayName, name, true) == 0) // return timeZone; // } // else if (lookupBy == TimeZoneName.StandardName) // { // if (string.Compare(timeZone.StandardName, name, true) == 0) // return timeZone; // } // } // throw new ArgumentException("Windows time zone with " + lookupBy + " of \"" + name + "\" was not found!"); //} #endregion } }