diff --git a/Tests/NullGuardTest.cs b/Tests/NullGuardTest.cs index c04d259..b05c232 100644 --- a/Tests/NullGuardTest.cs +++ b/Tests/NullGuardTest.cs @@ -18,5 +18,15 @@ public void MakeSureNullGuardIsWorking() Assert.Throws(() => new FileInfo(null)); #endif } + + [Fact] + public void CheckOSVersionImplementation() + { + Environment env = new Environment(); + + Assert.NotNull(env.OSVersion.Edition); + Assert.NotNull(env.OSVersion.Name); + Assert.True(env.OSVersion.ToString().Length > 7); + } } } diff --git a/src/AssemblyFacade.cs b/src/AssemblyFacade.cs index 6c000ae..ad08ef3 100644 --- a/src/AssemblyFacade.cs +++ b/src/AssemblyFacade.cs @@ -1,8 +1,8 @@ -using System; +using NullGuard; +using System; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using NullGuard; namespace Rothko { diff --git a/src/DirectoryInfo.cs b/src/DirectoryInfo.cs index 71533c3..d89e486 100644 --- a/src/DirectoryInfo.cs +++ b/src/DirectoryInfo.cs @@ -88,7 +88,7 @@ public IEnumerable EnumerateDirectories(string searchPattern) return inner.EnumerateDirectories(searchPattern).Select(Wrap); } - public IEnumerable EnumerateDirectories(string searchPattern, System.IO.SearchOption searchOption) + public IEnumerable EnumerateDirectories(string searchPattern, SearchOption searchOption) { return inner.EnumerateDirectories(searchPattern, searchOption).Select(Wrap); } @@ -103,7 +103,7 @@ public IEnumerable EnumerateFiles(string searchPattern) return inner.EnumerateFiles(searchPattern).Select(FileInfo.Wrap); } - public IEnumerable EnumerateFiles(string searchPattern, System.IO.SearchOption searchOption) + public IEnumerable EnumerateFiles(string searchPattern, SearchOption searchOption) { return inner.EnumerateFiles(searchPattern, searchOption).Select(FileInfo.Wrap); } @@ -118,7 +118,7 @@ public IEnumerable EnumerateFileSystemInfos(string searchPatter return inner.EnumerateFileSystemInfos(searchPattern).Select(Wrap); } - public IEnumerable EnumerateFileSystemInfos(string searchPattern, System.IO.SearchOption searchOption) + public IEnumerable EnumerateFileSystemInfos(string searchPattern, SearchOption searchOption) { return inner.EnumerateFileSystemInfos(searchPattern, searchOption).Select(Wrap); } diff --git a/src/FileInfo.cs b/src/FileInfo.cs index c6bc793..4c417b8 100644 --- a/src/FileInfo.cs +++ b/src/FileInfo.cs @@ -1,5 +1,4 @@  -using System; using System.Diagnostics; namespace Rothko diff --git a/src/FileSystemWatcher.cs b/src/FileSystemWatcher.cs index e63e5ef..b245475 100644 --- a/src/FileSystemWatcher.cs +++ b/src/FileSystemWatcher.cs @@ -203,9 +203,9 @@ public System.IO.WaitForChangedResult WaitForChanged(System.IO.WatcherChangeType Justification = "It doesn't!")] public override bool Equals([AllowNull] object obj) { - if (Object.ReferenceEquals(this, obj)) + if (ReferenceEquals(this, obj)) return true; - if (Object.ReferenceEquals(null, obj)) + if (ReferenceEquals(null, obj)) return false; var other = obj as FileSystemWatcher; diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs new file mode 100644 index 0000000..2a338a8 Binary files /dev/null and b/src/GlobalSuppressions.cs differ diff --git a/src/Infrastructure/DirectoryFacade.cs b/src/Infrastructure/DirectoryFacade.cs index 3739b71..84c583a 100644 --- a/src/Infrastructure/DirectoryFacade.cs +++ b/src/Infrastructure/DirectoryFacade.cs @@ -29,8 +29,8 @@ public bool IsEmpty(string path) throw new DirectoryNotFoundException( String.Format(CultureInfo.InvariantCulture, "The directory '{0}' does not exist", path)); } - return directory.IsEmpty; + return directory.IsEmpty; } } } diff --git a/src/Infrastructure/IDialogFacade.cs b/src/Infrastructure/IDialogFacade.cs index fcf6ed4..5cfd095 100644 --- a/src/Infrastructure/IDialogFacade.cs +++ b/src/Infrastructure/IDialogFacade.cs @@ -8,7 +8,7 @@ public interface IDialogFacade } [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", - Justification = "TODO: Should tchis even be a struct?")] + Justification = "TODO: Should this even be a struct?")] public struct SaveDialogResult { readonly bool _success; diff --git a/src/Infrastructure/IDirectoryFacade.cs b/src/Infrastructure/IDirectoryFacade.cs index b901037..e0811cf 100644 --- a/src/Infrastructure/IDirectoryFacade.cs +++ b/src/Infrastructure/IDirectoryFacade.cs @@ -25,7 +25,7 @@ public interface IDirectoryFacade /// Returns true if the directory exists at the specified path. /// /// Path to the directory - /// True if the directory exists, otherewise false. + /// True if the directory exists, otherwise false. bool Exists(string path); /// diff --git a/src/Infrastructure/IDirectoryInfo.cs b/src/Infrastructure/IDirectoryInfo.cs index e8f25b5..18cc342 100644 --- a/src/Infrastructure/IDirectoryInfo.cs +++ b/src/Infrastructure/IDirectoryInfo.cs @@ -51,16 +51,16 @@ public interface IDirectoryInfo : IFileSystemInfo /// /// The access control to apply to the directory. /// - /// The directory specified by is read-only or is not empty. + /// The directory specified by is read-only or is not empty. /// /// /// The caller does not have the required permission. /// /// - /// is a zero-length string, contains only white space, or contains one or more - /// invalid characters as defined by . + /// is a zero-length string, contains only white space, or contains one or more + /// invalid characters as defined by . /// - /// is null. + /// is null. /// /// The specified path, file name, or both exceed the system-defined maximum length. For example, on /// Windows-based platforms, paths must be less than 248 characters, and file names must be less than @@ -73,7 +73,7 @@ public interface IDirectoryInfo : IFileSystemInfo /// Creating a directory with only the colon (:) character was attempted. /// /// - /// The directory specified by is read-only or is not empty. + /// The directory specified by is read-only or is not empty. /// /// 1 /// diff --git a/src/Infrastructure/IFileInfo.cs b/src/Infrastructure/IFileInfo.cs index 1e0a495..b9c7aaf 100644 --- a/src/Infrastructure/IFileInfo.cs +++ b/src/Infrastructure/IFileInfo.cs @@ -395,7 +395,7 @@ public interface IFileInfo : IFileSystemInfo /// Creates a read-only . /// A new read-only object. /// - /// is read-only or is a directory. + /// Inner object path is read-only or is a directory. /// /// /// The specified path is invalid, such as being on an unmapped drive. @@ -417,7 +417,7 @@ public interface IFileInfo : IFileSystemInfo /// /// The file is not found. /// - /// is read-only or is a directory. + /// Inner object path is read-only or is a directory. /// /// /// The specified path is invalid, such as being on an unmapped drive. @@ -458,15 +458,15 @@ public interface IFileInfo : IFileSystemInfo /// The name of a file to replace with the current file. /// /// - /// The name of a file with which to create a backup of the file described by the + /// The name of a file with which to create a backup of the file described by the /// parameter. /// /// - /// The path described by the parameter was not of a legal form.-or- - /// The path described by the parameter was not of a legal form. + /// The path described by the parameter was not of a legal form.-or- + /// The path described by the parameter was not of a legal form. /// /// - /// The parameter is null. + /// The parameter is null. /// /// /// The file described by the current object could not be found.-or- @@ -494,7 +494,7 @@ public interface IFileInfo : IFileSystemInfo /// The name of a file to replace with the current file. /// /// - /// The name of a file with which to create a backup of the file described by the + /// The name of a file with which to create a backup of the file described by the /// parameter. /// /// @@ -502,11 +502,11 @@ public interface IFileInfo : IFileSystemInfo /// file; otherwise false. /// /// - /// The path described by the parameter was not of a legal form.-or- - /// The path described by the parameter was not of a legal form. + /// The path described by the parameter was not of a legal form.-or- + /// The path described by the parameter was not of a legal form. /// /// - /// The parameter is null. + /// The parameter is null. /// /// /// The file described by the current object could not be found.-or- diff --git a/src/Infrastructure/IFileSystemFacade.cs b/src/Infrastructure/IFileSystemFacade.cs index de324d0..c7f105d 100644 --- a/src/Infrastructure/IFileSystemFacade.cs +++ b/src/Infrastructure/IFileSystemFacade.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; namespace Rothko { @@ -20,7 +16,7 @@ public interface IFileSystemFacade /// /// /// is a zero-length string, contains only white space, or contains one or - /// more invalid characters as defined by . + /// more invalid characters as defined by . /// -or- is prefixed with, or contains only a colon character (:). /// /// is null. @@ -60,7 +56,7 @@ public interface IFileSystemFacade /// /// /// is a zero-length string, contains only white space, or contains one - /// or more invalid characters as defined by . + /// or more invalid characters as defined by . /// /// is null. /// @@ -101,7 +97,7 @@ public interface IFileSystemFacade /// /// /// is a zero-length string, contains only white space, or contains one or - /// more invalid characters as defined by . + /// more invalid characters as defined by . /// /// is null. /// @@ -121,12 +117,12 @@ public interface IFileSystemFacade void DeleteDirectory(string path, bool recursive); /// Determines whether the given path refers to an existing directory on disk. - /// true if refers to an existing directory; otherwise, false. - /// The path to test. - /// 1 - /// - /// - /// + /// true if refers to an existing directory; otherwise, false. + /// The path to test. + /// 1 + /// + /// + /// bool DirectoryExists(string path); /// Gets a representing the specified path. diff --git a/src/Infrastructure/IOperatingSystem.cs b/src/Infrastructure/IOperatingSystem.cs index efaf0f8..979481b 100644 --- a/src/Infrastructure/IOperatingSystem.cs +++ b/src/Infrastructure/IOperatingSystem.cs @@ -9,5 +9,7 @@ public interface IOperatingSystem : ICloneable, ISerializable string ServicePack { get; } Version Version { get; } string VersionString { get; } + string Name { get; } + string Edition { get; } } } \ No newline at end of file diff --git a/src/Infrastructure/IRegistryKey.cs b/src/Infrastructure/IRegistryKey.cs index 722bde7..19d0878 100644 --- a/src/Infrastructure/IRegistryKey.cs +++ b/src/Infrastructure/IRegistryKey.cs @@ -1,8 +1,8 @@ -using System; +using Microsoft.Win32; +using Microsoft.Win32.SafeHandles; +using System; using System.Collections.Generic; using System.Security.AccessControl; -using Microsoft.Win32; -using Microsoft.Win32.SafeHandles; namespace Rothko { diff --git a/src/OperatingSystem.cs b/src/OperatingSystem.cs index ef28361..7808692 100644 --- a/src/OperatingSystem.cs +++ b/src/OperatingSystem.cs @@ -1,45 +1,585 @@ using System; +using System.Globalization; using System.Runtime.Serialization; +using Rothko.Win32; namespace Rothko { + /// + /// Represents information about an operating system, such as the version and platform identifier. This class cannot be inherited. + /// public sealed class OperatingSystem : IOperatingSystem { + #region PRODUCT + private const int PRODUCT_UNDEFINED = 0x00000000; + private const int PRODUCT_ULTIMATE = 0x00000001; + private const int PRODUCT_HOME_BASIC = 0x00000002; + private const int PRODUCT_HOME_PREMIUM = 0x00000003; + private const int PRODUCT_ENTERPRISE = 0x00000004; + private const int PRODUCT_HOME_BASIC_N = 0x00000005; + private const int PRODUCT_BUSINESS = 0x00000006; + private const int PRODUCT_STANDARD_SERVER = 0x00000007; + private const int PRODUCT_DATACENTER_SERVER = 0x00000008; + private const int PRODUCT_SMALLBUSINESS_SERVER = 0x00000009; + private const int PRODUCT_ENTERPRISE_SERVER = 0x0000000A; + private const int PRODUCT_STARTER = 0x0000000B; + private const int PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C; + private const int PRODUCT_STANDARD_SERVER_CORE = 0x0000000D; + private const int PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E; + private const int PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F; + private const int PRODUCT_BUSINESS_N = 0x00000010; + private const int PRODUCT_WEB_SERVER = 0x00000011; + private const int PRODUCT_CLUSTER_SERVER = 0x00000012; + private const int PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014; + private const int PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015; + private const int PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016; + private const int PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017; + private const int PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018; + private const int PRODUCT_SMALLBUSINESS_SERVER_PREMIUM = 0x00000019; + private const int PRODUCT_HOME_PREMIUM_N = 0x0000001A; + private const int PRODUCT_ENTERPRISE_N = 0x0000001B; + private const int PRODUCT_ULTIMATE_N = 0x0000001C; + private const int PRODUCT_WEB_SERVER_CORE = 0x0000001D; + private const int PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E; + private const int PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F; + private const int PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020; + private const int PRODUCT_SERVER_FOUNDATION = 0x00000021; + private const int PRODUCT_HOME_PREMIUM_SERVER = 0x00000022; + private const int PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023; + private const int PRODUCT_STANDARD_SERVER_V = 0x00000024; + private const int PRODUCT_DATACENTER_SERVER_V = 0x00000025; + private const int PRODUCT_ENTERPRISE_SERVER_V = 0x00000026; + private const int PRODUCT_DATACENTER_SERVER_CORE_V = 0x00000027; + private const int PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028; + private const int PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029; + private const int PRODUCT_HYPERV = 0x0000002A; + private const int PRODUCT_STORAGE_EXPRESS_SERVER_CORE = 0x0000002B; + private const int PRODUCT_STORAGE_STANDARD_SERVER_CORE = 0x0000002C; + private const int PRODUCT_STORAGE_WORKGROUP_SERVER_CORE = 0x0000002D; + private const int PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE = 0x0000002E; + private const int PRODUCT_STARTER_N = 0x0000002F; + private const int PRODUCT_PROFESSIONAL = 0x00000030; + private const int PRODUCT_PROFESSIONAL_N = 0x00000031; + private const int PRODUCT_SB_SOLUTION_SERVER = 0x00000032; + private const int PRODUCT_SERVER_FOR_SB_SOLUTIONS = 0x00000033; + private const int PRODUCT_STANDARD_SERVER_SOLUTIONS = 0x00000034; + private const int PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE = 0x00000035; + private const int PRODUCT_SB_SOLUTION_SERVER_EM = 0x00000036; + private const int PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM = 0x00000037; + private const int PRODUCT_SOLUTION_EMBEDDEDSERVER = 0x00000038; + private const int PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE = 0x00000039; + private const int PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT = 0x0000003B; + private const int PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL = 0x0000003C; + private const int PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC = 0x0000003D; + private const int PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC = 0x0000003E; + private const int PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE = 0x0000003F; + private const int PRODUCT_CLUSTER_SERVER_V = 0x00000040; + private const int PRODUCT_EMBEDDED = 0x00000041; + private const int PRODUCT_STARTER_E = 0x00000042; + private const int PRODUCT_HOME_BASIC_E = 0x00000043; + private const int PRODUCT_HOME_PREMIUM_E = 0x00000044; + private const int PRODUCT_PROFESSIONAL_E = 0x00000045; + private const int PRODUCT_ENTERPRISE_E = 0x00000046; + private const int PRODUCT_ULTIMATE_E = 0x00000047; + #endregion PRODUCT + + #region VERSIONS + private const int VER_NT_WORKSTATION = 1; + private const int VER_NT_SERVER = 3; + private const int VER_SUITE_ENTERPRISE = 2; + private const int VER_SUITE_DATACENTER = 128; + private const int VER_SUITE_PERSONAL = 512; + private const int VER_SUITE_BLADE = 1024; + #endregion VERSIONS + readonly System.OperatingSystem _operatingSystem; + private string _edition; + private string _name; + /// + /// Initializes a new instance of the class, using the specified platform identifier value and version object. + /// + /// A valid instance of class. Usually is given by the Env.OSVersion property. public OperatingSystem(System.OperatingSystem operatingSystem) { _operatingSystem = operatingSystem; } + /// + /// Creates an object that is identical to this instance. + /// + /// public object Clone() { return _operatingSystem.Clone(); } + /// + /// Populates a object with the data necessary to deserialize this instance. + /// + /// The object to populate with serialization information. + /// The place to store and retrieve serialized data. Reserved for future use. + /// info is null. public void GetObjectData(SerializationInfo info, StreamingContext context) { _operatingSystem.GetObjectData(info, context); } + /// + /// Gets a enumeration value that identifies the operating system platform. + /// public PlatformID Platform { get { return _operatingSystem.Platform; } } + /// + /// Gets the service pack version represented by this OperatingSystem object. + /// public string ServicePack { get { return _operatingSystem.ServicePack; } } + /// + /// Gets a object that identifies the operating system. + /// public Version Version { get { return _operatingSystem.Version; } } + /// + /// Gets the concatenated string representation of the platform identifier, version, and service pack that are currently installed on the operating system. + /// public string VersionString { get { return _operatingSystem.VersionString; } } + + /// + /// Gets the edition of the operating system running on this computer. + /// + public string Edition + { + get + { + if (_edition != null) + return _edition; + + string edition = String.Empty; + OsVersionInfoEx osVersion = new OsVersionInfoEx(); + + if (NativeMethods.GetVersionEx(osVersion)) + { + switch (osVersion.MajorVersion) + { + case 4: + edition = GetEditionMajorVersionFour(osVersion.ProductType, osVersion.SuiteMask); + break; + case 5: + edition = GetEditionMajorVersionFive(osVersion.MinorVersion, osVersion.ProductType, osVersion.SuiteMask); + break; + case 6: + edition = GetEditionMajorVersionSix(osVersion); + break; + } + } + + _edition = edition; + return edition; + } + } + + /// + /// Gets the name of the operating system running on this computer. + /// + public string Name + { + get + { + if (_name != null) + return _name; + + string name = "unknown"; + + OsVersionInfoEx osVersion = new OsVersionInfoEx(); + + if (NativeMethods.GetVersionEx(osVersion)) + { + switch (_operatingSystem.Platform) + { + case PlatformID.Win32Windows: + { + if (osVersion.MajorVersion == 4) + { + name = GetWin32VersionName(osVersion.MinorVersion, osVersion.CSDVersion); + } + + break; + } + case PlatformID.Win32NT: + { + name = GetWin32NTVersionName(osVersion.MajorVersion, osVersion.MinorVersion, osVersion.ProductType); + } + + break; + } + } + + _name = name; + return name; + } + } + + /// + /// Converts the value of this object to its equivalent string representation. + /// + /// The commercial name of the running operating system. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations", Justification = "The violation is caused by an exception declaration instead of a thrown exception.")] + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "{0} {1} with {2}", Name, Edition, ServicePack); + } + + private static string GetWin32VersionName(int minorVersion, string csdVersion) + { + switch (minorVersion) + { + case 0: + if (csdVersion == "B" || csdVersion == "C") + { + return "Windows 95 OSR2"; + } + + return "Windows 95"; + case 10: + if (csdVersion == "A") + { + return "Windows 98 Second Edition"; + } + + return "Windows 98"; + + case 90: + return "Windows Me"; + + default: + return string.Empty; + } + } + + private static string GetWin32NTVersionName(int majorVersion, int minorVersion, int productType) + { + switch (majorVersion) + { + case 3: + return "Windows NT 3.51"; + case 4: + switch (productType) + { + case 1: + return "Windows NT 4.0"; + case 3: + return "Windows NT 4.0 Server"; + } + + return string.Empty; + case 5: + switch (minorVersion) + { + case 0: + return "Windows 2000"; + case 1: + return "Windows XP"; + case 2: + return "Windows Server 2003"; + } + + return string.Empty; + case 6: + return GetVersionSixOsName(minorVersion, productType); + default: + return string.Empty; + } + } + + private static string GetVersionSixOsName(int minorVersion, int productType) + { + switch (minorVersion) + { + case 0: + switch (productType) + { + case 1: + return "Windows Vista"; + case 3: + return "Windows Server 2008"; + } + + return string.Empty; + case 1: + switch (productType) + { + case 1: + return "Windows 7"; + case 3: + return "Windows Server 2008 R2"; + } + + return string.Empty; + case 2: + switch (productType) + { + case 1: + return "Windows 8"; + case 3: + return "Windows Server 2012"; + } + + return string.Empty; + case 3: + switch (productType) + { + case 1: + return "Windows 8.1"; + case 3: + return "Windows Server 2012 R2"; + } + + return string.Empty; + + default: + return string.Empty; + } + } + + private static string GetEditionMajorVersionFour(byte productType, short suiteMask) + { + if (productType == VER_NT_WORKSTATION) + { + // Windows NT 4.0 Workstation + return "Workstation"; + } + + if (productType == VER_NT_SERVER) + { + if ((suiteMask & VER_SUITE_ENTERPRISE) != 0) + { + // Windows NT 4.0 Server Enterprise + return "Enterprise Server"; + } + + // Windows NT 4.0 Server + return "Standard Server"; + } + + return string.Empty; + } + + private static string GetEditionMajorVersionFive(int minorVersion, byte productType, short suiteMask) + { + if (productType == VER_NT_WORKSTATION) + { + if ((suiteMask & VER_SUITE_PERSONAL) != 0) + { + return "Home"; + } + + if (NativeMethods.GetSystemMetrics(SystemMetric.SM_TABLETPC) == 0) + { + return "Professional"; + } + + return "Tablet PC Edition"; + } + + + if (productType == VER_NT_SERVER) + { + if (minorVersion == 0) + { + if ((suiteMask & VER_SUITE_DATACENTER) != 0) + { + // Windows 2000 Datacenter Server + return "Datacenter Server"; + } + + return (suiteMask & VER_SUITE_ENTERPRISE) != 0 ? "Advanced Server" : "Server"; + } + + + if ((suiteMask & VER_SUITE_DATACENTER) != 0) + { + // Windows Server 2003 Datacenter Edition + return "Datacenter"; + } + + if ((suiteMask & VER_SUITE_ENTERPRISE) != 0) + { + // Windows Server 2003 Enterprise Edition + return "Enterprise"; + } + + return (suiteMask & VER_SUITE_BLADE) != 0 ? "Web Edition" : "Standard"; + } + + return string.Empty; + } + + private static string GetEditionMajorVersionSix(OsVersionInfoEx osVersion) + { + int ed; + if (NativeMethods.GetProductInfo(osVersion.MajorVersion, osVersion.MinorVersion, + osVersion.ServicePackMajor, osVersion.ServicePackMinor, + out ed)) + { + switch (ed) + { + case PRODUCT_BUSINESS: + return "Business"; + case PRODUCT_BUSINESS_N: + return "Business N"; + case PRODUCT_CLUSTER_SERVER: + return "HPC Edition"; + case PRODUCT_CLUSTER_SERVER_V: + return "HPC Edition without Hyper-V"; + case PRODUCT_DATACENTER_SERVER: + return "Datacenter Server"; + case PRODUCT_DATACENTER_SERVER_CORE: + return "Datacenter Server (core installation)"; + case PRODUCT_DATACENTER_SERVER_V: + return "Datacenter Server without Hyper-V"; + case PRODUCT_DATACENTER_SERVER_CORE_V: + return "Datacenter Server without Hyper-V (core installation)"; + case PRODUCT_EMBEDDED: + return "Embedded"; + case PRODUCT_ENTERPRISE: + return "Enterprise"; + case PRODUCT_ENTERPRISE_N: + return "Enterprise N"; + case PRODUCT_ENTERPRISE_E: + return "Enterprise E"; + case PRODUCT_ENTERPRISE_SERVER: + return "Enterprise Server"; + case PRODUCT_ENTERPRISE_SERVER_CORE: + return "Enterprise Server (core installation)"; + case PRODUCT_ENTERPRISE_SERVER_CORE_V: + return "Enterprise Server without Hyper-V (core installation)"; + case PRODUCT_ENTERPRISE_SERVER_IA64: + return "Enterprise Server for Itanium-based Systems"; + case PRODUCT_ENTERPRISE_SERVER_V: + return "Enterprise Server without Hyper-V"; + case PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT: + return "Essential Business Server MGMT"; + case PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL: + return "Essential Business Server ADDL"; + case PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC: + return "Essential Business Server MGMTSVC"; + case PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC: + return "Essential Business Server ADDLSVC"; + case PRODUCT_HOME_BASIC: + return "Home Basic"; + case PRODUCT_HOME_BASIC_N: + return "Home Basic N"; + case PRODUCT_HOME_BASIC_E: + return "Home Basic E"; + case PRODUCT_HOME_PREMIUM: + return "Home Premium"; + case PRODUCT_HOME_PREMIUM_N: + return "Home Premium N"; + case PRODUCT_HOME_PREMIUM_E: + return "Home Premium E"; + case PRODUCT_HOME_PREMIUM_SERVER: + return "Home Premium Server"; + case PRODUCT_HYPERV: + return "Microsoft Hyper-V Server"; + case PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT: + return "Windows Essential Business Management Server"; + case PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING: + return "Windows Essential Business Messaging Server"; + case PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY: + return "Windows Essential Business Security Server"; + case PRODUCT_PROFESSIONAL: + return "Professional"; + case PRODUCT_PROFESSIONAL_N: + return "Professional N"; + case PRODUCT_PROFESSIONAL_E: + return "Professional E"; + case PRODUCT_SB_SOLUTION_SERVER: + return "SB Solution Server"; + case PRODUCT_SB_SOLUTION_SERVER_EM: + return "SB Solution Server EM"; + case PRODUCT_SERVER_FOR_SB_SOLUTIONS: + return "Server for SB Solutions"; + case PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM: + return "Server for SB Solutions EM"; + case PRODUCT_SERVER_FOR_SMALLBUSINESS: + return "Windows Essential Server Solutions"; + case PRODUCT_SERVER_FOR_SMALLBUSINESS_V: + return "Windows Essential Server Solutions without Hyper-V"; + case PRODUCT_SERVER_FOUNDATION: + return "Server Foundation"; + case PRODUCT_SMALLBUSINESS_SERVER: + return "Windows Small Business Server"; + case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: + return "Windows Small Business Server Premium"; + case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE: + return "Windows Small Business Server Premium (core installation)"; + case PRODUCT_SOLUTION_EMBEDDEDSERVER: + return "Solution Embedded Server"; + case PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE: + return "Solution Embedded Server (core installation)"; + case PRODUCT_STANDARD_SERVER: + return "Standard Server"; + case PRODUCT_STANDARD_SERVER_CORE: + return "Standard Server (core installation)"; + case PRODUCT_STANDARD_SERVER_SOLUTIONS: + return "Standard Server Solutions"; + case PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE: + return "Standard Server Solutions (core installation)"; + case PRODUCT_STANDARD_SERVER_CORE_V: + return "Standard Server without Hyper-V (core installation)"; + case PRODUCT_STANDARD_SERVER_V: + return "Standard Server without Hyper-V"; + case PRODUCT_STARTER: + return "Starter"; + case PRODUCT_STARTER_N: + return "Starter N"; + case PRODUCT_STARTER_E: + return "Starter E"; + case PRODUCT_STORAGE_ENTERPRISE_SERVER: + return "Enterprise Storage Server"; + case PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE: + return "Enterprise Storage Server (core installation)"; + case PRODUCT_STORAGE_EXPRESS_SERVER: + return "Express Storage Server"; + case PRODUCT_STORAGE_EXPRESS_SERVER_CORE: + return "Express Storage Server (core installation)"; + case PRODUCT_STORAGE_STANDARD_SERVER: + return "Standard Storage Server"; + case PRODUCT_STORAGE_STANDARD_SERVER_CORE: + return "Standard Storage Server (core installation)"; + case PRODUCT_STORAGE_WORKGROUP_SERVER: + return "Workgroup Storage Server"; + case PRODUCT_STORAGE_WORKGROUP_SERVER_CORE: + return "Workgroup Storage Server (core installation)"; + case PRODUCT_UNDEFINED: + return "Unknown product"; + case PRODUCT_ULTIMATE: + return "Ultimate"; + case PRODUCT_ULTIMATE_N: + return "Ultimate N"; + case PRODUCT_ULTIMATE_E: + return "Ultimate E"; + case PRODUCT_WEB_SERVER: + return "Web Server"; + case PRODUCT_WEB_SERVER_CORE: + return "Web Server (core installation)"; + } + } + + return string.Empty; + } } } diff --git a/src/RegistryKey.cs b/src/RegistryKey.cs index cb69423..19e9951 100644 --- a/src/RegistryKey.cs +++ b/src/RegistryKey.cs @@ -1,7 +1,7 @@  +using NullGuard; using System.Collections.Generic; using System.Diagnostics; -using NullGuard; namespace Rothko { diff --git a/src/Rothko.csproj b/src/Rothko.csproj index ac7a876..2c23100 100644 --- a/src/Rothko.csproj +++ b/src/Rothko.csproj @@ -69,13 +69,16 @@ + + + @@ -108,9 +111,11 @@ + + diff --git a/src/Win32/NativeMethods.cs b/src/Win32/NativeMethods.cs index 4202f80..fab4c03 100644 --- a/src/Win32/NativeMethods.cs +++ b/src/Win32/NativeMethods.cs @@ -1,5 +1,9 @@ using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Security; +using Rothko.Win32; namespace Rothko { @@ -15,5 +19,22 @@ internal static class NativeMethods [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ShowWindow(IntPtr hWnd, ShowWindowOption nCmdShow); + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2205:UseManagedEquivalentsOfWin32Api", Justification = "System.Environment.OSVersion is not exposing the necessary information."), + DllImport("kernel32")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetVersionEx([In, Out] OsVersionInfoEx osVer); + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetProductInfo( + int osMajorVersion, + int osMinorVersion, + int spMajorVersion, + int spMinorVersion, + out int edition); + + [DllImport("user32.dll")] + public static extern int GetSystemMetrics(SystemMetric smIndex); } } diff --git a/src/Win32/OsVersionInfoEx.cs b/src/Win32/OsVersionInfoEx.cs new file mode 100644 index 0000000..13e9118 --- /dev/null +++ b/src/Win32/OsVersionInfoEx.cs @@ -0,0 +1,72 @@ +using System.Runtime.InteropServices; + +namespace Rothko.Win32 +{ + [StructLayout(LayoutKind.Sequential)] + internal class OsVersionInfoEx + { + public OsVersionInfoEx() + { + OSVersionInfoSize = Marshal.SizeOf(this); + } + + /// + /// The size of this data structure, in bytes. Set this member to sizeof(OSVERSIONINFO). + /// + public int OSVersionInfoSize = 0; + + /// + /// The major version number of the operating system. + /// + public int MajorVersion = 0; + + /// + /// The minor version number of the operating system. + /// + public int MinorVersion = 0; + + /// + /// The build number of the operating system. + /// + public int BuildNumber = 0; + + /// + /// The operating system platform. This member can be VER_PLATFORM_WIN32_NT (2). + /// + public int PlatformId = 0; + + /// + /// A null-terminated string, such as "Service Pack 3", that indicates the latest Service Pack installed on the system. + /// If no Service Pack has been installed, the string is empty. + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string CSDVersion = null; + + /// + /// The major version number of the latest Service Pack installed on the system. + /// For example, for Service Pack 3, the major version number is 3. If no Service Pack has been installed, the value is zero. + /// + public ushort ServicePackMajor = 0; + + /// + /// The minor version number of the latest Service Pack installed on the system. + /// For example, for Service Pack 3, the minor version number is 0. + /// + public ushort ServicePackMinor = 0; + + /// + /// A bit mask that identifies the product suites available on the system. + /// + public short SuiteMask = 0; + + /// + /// Any additional information about the system. + /// + public byte ProductType = 0; + + /// + /// Reserved for future use. + /// + public byte Reserved = 0; + } +} diff --git a/src/Win32/SafeNativeMethods.cs b/src/Win32/SafeNativeMethods.cs index a25fea7..c121000 100644 --- a/src/Win32/SafeNativeMethods.cs +++ b/src/Win32/SafeNativeMethods.cs @@ -1,6 +1,4 @@ -using System; -using System.Runtime.InteropServices; -using System.Security; +using System.Security; namespace Rothko { diff --git a/src/Win32/ShowWindowOption.cs b/src/Win32/ShowWindowOption.cs index ef31ee9..2cdf3b0 100644 --- a/src/Win32/ShowWindowOption.cs +++ b/src/Win32/ShowWindowOption.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - + namespace Rothko { public enum ShowWindowOption diff --git a/src/Win32/SystemMetric.cs b/src/Win32/SystemMetric.cs new file mode 100644 index 0000000..e1904d1 --- /dev/null +++ b/src/Win32/SystemMetric.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Rothko.Win32 +{ + /// + /// The system metric or configuration setting index. + /// + public enum SystemMetric + { + /// + /// The width of the screen of the primary display monitor, in pixels. + /// + SM_CXSCREEN = 0, + /// + /// Windows XP Tablet PC Edition + /// + SM_TABLETPC = 86, + /// + /// Windows XP Media Center Edition + /// + SM_MEDIACENTER = 87, + /// + /// Windows XP Starter Edition + /// + SM_STARTER = 88, + /// + /// Windows Server 2003 R2 + /// + SM_SERVERR2 = 89 + } +}