Hardware/HDD/WindowsSmart.cs
author sl
Sun, 03 Feb 2013 18:01:50 +0100
changeset 391 ca4c0e7ae75d
parent 344 3145aadca3d2
permissions -rw-r--r--
Converted project to VisualStudio 2012.
Adding SoundGraphDisplay and SensorFrontView classes.
They were respectively based on SystemTray and SensorNotifyIcon.
SoundGraphDisplay is now able to load iMONDisplay.dll providing it lives on your PATH.
Adding option to sensor context menu for adding it into FrontView.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	Copyright (C) 2010 Paul Werelds
     9   Copyright (C) 2011 Roland Reinl <roland-reinl@gmx.de>
    10 	
    11 */
    12 
    13 using System;
    14 using System.Collections.Generic;
    15 using System.Management;
    16 using System.Runtime.InteropServices;
    17 
    18 namespace OpenHardwareMonitor.Hardware.HDD {
    19 
    20   internal class WindowsSmart : ISmart {
    21     [Flags]
    22     protected enum AccessMode : uint {     
    23       Read = 0x80000000,    
    24       Write = 0x40000000,     
    25       Execute = 0x20000000,     
    26       All = 0x10000000
    27     }
    28 
    29     [Flags]
    30     protected enum ShareMode : uint {
    31       None = 0,     
    32       Read = 1,     
    33       Write = 2,    
    34       Delete = 4
    35     }
    36 
    37     protected enum CreationMode : uint {
    38       New = 1,
    39       CreateAlways = 2,    
    40       OpenExisting = 3,    
    41       OpenAlways = 4,    
    42       TruncateExisting = 5
    43     }
    44 
    45     [Flags]
    46     protected enum FileAttribute : uint {
    47       Readonly = 0x00000001,
    48       Hidden = 0x00000002,
    49       System = 0x00000004,
    50       Directory = 0x00000010,
    51       Archive = 0x00000020,
    52       Device = 0x00000040,
    53       Normal = 0x00000080,
    54       Temporary = 0x00000100,
    55       SparseFile = 0x00000200,
    56       ReparsePoint = 0x00000400,
    57       Compressed = 0x00000800,
    58       Offline = 0x00001000,
    59       NotContentIndexed = 0x00002000,
    60       Encrypted = 0x00004000,
    61     }
    62 
    63     protected enum DriveCommand : uint {
    64       GetVersion = 0x00074080,
    65       SendDriveCommand = 0x0007c084,
    66       ReceiveDriveData = 0x0007c088
    67     }
    68 
    69     protected enum RegisterCommand : byte {
    70       /// <summary>
    71       /// SMART data requested.
    72       /// </summary>
    73       SmartCmd = 0xB0,
    74 
    75       /// <summary>
    76       /// Identify data is requested.
    77       /// </summary>
    78       IdCmd = 0xEC,
    79     }
    80 
    81     protected enum RegisterFeature : byte {
    82       /// <summary>
    83       /// Read SMART data.
    84       /// </summary>
    85       SmartReadData = 0xD0,
    86 
    87       /// <summary>
    88       /// Read SMART thresholds.
    89       /// </summary>
    90       SmartReadThresholds = 0xD1, /* obsolete */
    91 
    92       /// <summary>
    93       /// Autosave SMART data.
    94       /// </summary>
    95       SmartAutosave = 0xD2,
    96 
    97       /// <summary>
    98       /// Save SMART attributes.
    99       /// </summary>
   100       SmartSaveAttr = 0xD3,
   101 
   102       /// <summary>
   103       /// Set SMART to offline immediately.
   104       /// </summary>
   105       SmartImmediateOffline = 0xD4,
   106 
   107       /// <summary>
   108       /// Read SMART log.
   109       /// </summary>
   110       SmartReadLog = 0xD5,
   111 
   112       /// <summary>
   113       /// Write SMART log.
   114       /// </summary>
   115       SmartWriteLog = 0xD6,
   116 
   117       /// <summary>
   118       /// Write SMART thresholds.
   119       /// </summary>
   120       SmartWriteThresholds = 0xD7, /* obsolete */
   121 
   122       /// <summary>
   123       /// Enable SMART.
   124       /// </summary>
   125       SmartEnableOperations = 0xD8,
   126 
   127       /// <summary>
   128       /// Disable SMART.
   129       /// </summary>
   130       SmartDisableOperations = 0xD9,
   131 
   132       /// <summary>
   133       /// Get SMART status.
   134       /// </summary>
   135       SmartStatus = 0xDA,
   136 
   137       /// <summary>
   138       /// Set SMART to offline automatically.
   139       /// </summary>
   140       SmartAutoOffline = 0xDB, /* obsolete */
   141     }
   142 
   143     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   144     protected struct CommandBlockRegisters {
   145       public RegisterFeature Features;         
   146       public byte SectorCount;      
   147       public byte LBALow;       
   148       public byte LBAMid;           
   149       public byte LBAHigh;        
   150       public byte Device;
   151       public RegisterCommand Command;           
   152       public byte Reserved;                  
   153     }
   154 
   155     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   156     protected struct DriveCommandParameter {
   157       public uint BufferSize;           
   158       public CommandBlockRegisters Registers;           
   159       public byte DriveNumber;   
   160       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
   161       public byte[] Reserved;                                
   162     }
   163 
   164     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   165     protected struct DriverStatus {
   166       public byte DriverError;   
   167       public byte IDEError;             
   168       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
   169       public byte[] Reserved;               
   170     }
   171 
   172     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   173     protected struct DriveCommandResult {
   174       public uint BufferSize;
   175       public DriverStatus DriverStatus;
   176     } 
   177 
   178     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   179     protected struct DriveSmartReadDataResult {
   180       public uint BufferSize;           
   181       public DriverStatus DriverStatus;
   182       public byte Version;
   183       public byte Reserved;
   184       [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
   185       public DriveAttributeValue[] Attributes;                                                                                       
   186     }
   187 
   188     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   189     protected struct DriveSmartReadThresholdsResult {
   190       public uint BufferSize;
   191       public DriverStatus DriverStatus;
   192       public byte Version;
   193       public byte Reserved;
   194       [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
   195       public DriveThresholdValue[] Thresholds;
   196     }
   197 
   198     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   199     protected struct Identify {
   200       public ushort GeneralConfiguration;
   201       public ushort NumberOfCylinders;
   202       public ushort Reserved;
   203       public ushort NumberOfHeads;
   204       public ushort UnformattedBytesPerTrack;
   205       public ushort UnformattedBytesPerSector;
   206       public ushort SectorsPerTrack;
   207       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
   208       public ushort[] VendorUnique;
   209       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
   210       public byte[] SerialNumber;
   211       public ushort BufferType;
   212       public ushort BufferSectorSize;
   213       public ushort NumberOfEccBytes;
   214       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
   215       public byte[] FirmwareRevision;
   216       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
   217       public byte[] ModelNumber;
   218       public ushort MoreVendorUnique;
   219       public ushort DoubleWordIo;
   220       public ushort Capabilities;
   221       public ushort MoreReserved;
   222       public ushort PioCycleTimingMode;
   223       public ushort DmaCycleTimingMode;
   224       [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
   225       public byte[] More;
   226     }
   227 
   228     [StructLayout(LayoutKind.Sequential, Pack = 1)]
   229     protected struct DriveIdentifyResult {
   230       public uint BufferSize;
   231       public DriverStatus DriverStatus;
   232       public Identify Identify;
   233     }
   234 
   235     public IntPtr InvalidHandle { get { return (IntPtr)(-1); } }
   236 
   237     private const byte SMART_LBA_MID = 0x4F;
   238     private const byte SMART_LBA_HI = 0xC2;
   239 
   240     private const int MAX_DRIVE_ATTRIBUTES = 512;
   241 
   242     public IntPtr OpenDrive(int driveNumber) {
   243       return NativeMethods.CreateFile(@"\\.\PhysicalDrive" + driveNumber,
   244         AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
   245         IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
   246         IntPtr.Zero);
   247     }
   248 
   249     public bool EnableSmart(IntPtr handle, int driveNumber) {
   250       DriveCommandParameter parameter = new DriveCommandParameter();
   251       DriveCommandResult result;
   252       uint bytesReturned;
   253 
   254       parameter.DriveNumber = (byte)driveNumber;
   255       parameter.Registers.Features = RegisterFeature.SmartEnableOperations;
   256       parameter.Registers.LBAMid = SMART_LBA_MID;
   257       parameter.Registers.LBAHigh = SMART_LBA_HI;
   258       parameter.Registers.Command = RegisterCommand.SmartCmd;
   259 
   260       return NativeMethods.DeviceIoControl(handle, DriveCommand.SendDriveCommand, 
   261         ref parameter, Marshal.SizeOf(typeof(DriveCommandParameter)), out result,
   262         Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned, 
   263         IntPtr.Zero);
   264     }
   265 
   266     public DriveAttributeValue[] ReadSmartData(IntPtr handle, int driveNumber) {
   267       DriveCommandParameter parameter = new DriveCommandParameter();
   268       DriveSmartReadDataResult result;
   269       uint bytesReturned;
   270 
   271       parameter.DriveNumber = (byte)driveNumber;
   272       parameter.Registers.Features = RegisterFeature.SmartReadData;
   273       parameter.Registers.LBAMid = SMART_LBA_MID;
   274       parameter.Registers.LBAHigh = SMART_LBA_HI;
   275       parameter.Registers.Command = RegisterCommand.SmartCmd;
   276 
   277       bool isValid = NativeMethods.DeviceIoControl(handle, 
   278         DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
   279         out result, Marshal.SizeOf(typeof(DriveSmartReadDataResult)), 
   280         out bytesReturned, IntPtr.Zero);
   281 
   282       return (isValid) ? result.Attributes : new DriveAttributeValue[0];
   283     }
   284 
   285     public DriveThresholdValue[] ReadSmartThresholds(IntPtr handle,
   286       int driveNumber) 
   287     {
   288       DriveCommandParameter parameter = new DriveCommandParameter();
   289       DriveSmartReadThresholdsResult result;
   290       uint bytesReturned = 0;
   291 
   292       parameter.DriveNumber = (byte)driveNumber;
   293       parameter.Registers.Features = RegisterFeature.SmartReadThresholds;
   294       parameter.Registers.LBAMid = SMART_LBA_MID;
   295       parameter.Registers.LBAHigh = SMART_LBA_HI;
   296       parameter.Registers.Command = RegisterCommand.SmartCmd;
   297 
   298       bool isValid = NativeMethods.DeviceIoControl(handle,
   299         DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter),
   300         out result, Marshal.SizeOf(typeof(DriveSmartReadThresholdsResult)), 
   301         out bytesReturned, IntPtr.Zero); 
   302 
   303       return (isValid) ? result.Thresholds : new DriveThresholdValue[0];
   304     }
   305 
   306     private string GetString(byte[] bytes) {   
   307       char[] chars = new char[bytes.Length];
   308       for (int i = 0; i < bytes.Length; i += 2) {
   309         chars[i] = (char)bytes[i + 1];
   310         chars[i + 1] = (char)bytes[i];
   311       }
   312       return new string(chars).Trim(new char[] { ' ', '\0' });
   313     }
   314 
   315     public bool ReadNameAndFirmwareRevision(IntPtr handle, int driveNumber, 
   316       out string name, out string firmwareRevision) 
   317     {
   318       DriveCommandParameter parameter = new DriveCommandParameter();
   319       DriveIdentifyResult result;
   320       uint bytesReturned;
   321 
   322       parameter.DriveNumber = (byte)driveNumber;
   323       parameter.Registers.Command = RegisterCommand.IdCmd;
   324 
   325       bool valid = NativeMethods.DeviceIoControl(handle, 
   326         DriveCommand.ReceiveDriveData, ref parameter, Marshal.SizeOf(parameter), 
   327         out result, Marshal.SizeOf(typeof(DriveIdentifyResult)), 
   328         out bytesReturned, IntPtr.Zero);
   329 
   330       if (!valid) {
   331         name = null;
   332         firmwareRevision = null;
   333         return false;
   334       }
   335 
   336       name = GetString(result.Identify.ModelNumber);
   337       firmwareRevision = GetString(result.Identify.FirmwareRevision);
   338       return true;
   339     }
   340 
   341     public void CloseHandle(IntPtr handle) {
   342       NativeMethods.CloseHandle(handle);
   343     }
   344 
   345     public string[] GetLogicalDrives(int driveIndex) {
   346       List<string> list = new List<string>();
   347       try {
   348         using (ManagementObjectSearcher s = new ManagementObjectSearcher(
   349             "root\\CIMV2",
   350             "SELECT * FROM Win32_DiskPartition " +
   351             "WHERE DiskIndex = " + driveIndex))
   352         using (ManagementObjectCollection dpc = s.Get())
   353         foreach (ManagementObject dp in dpc) 
   354           using (ManagementObjectCollection ldc = 
   355             dp.GetRelated("Win32_LogicalDisk"))
   356           foreach (ManagementBaseObject ld in ldc) 
   357             list.Add(((string)ld["Name"]).TrimEnd(':')); 
   358       } catch { }
   359       return list.ToArray();
   360     }
   361 
   362     protected static class NativeMethods {
   363       private const string KERNEL = "kernel32.dll";
   364 
   365       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi,
   366         CharSet = CharSet.Unicode)]
   367       public static extern IntPtr CreateFile(string fileName,
   368         AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
   369         CreationMode creationDisposition, FileAttribute flagsAndAttributes,
   370         IntPtr templateFilehandle);
   371 
   372       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   373       public static extern int CloseHandle(IntPtr handle);
   374 
   375       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   376       [return: MarshalAsAttribute(UnmanagedType.Bool)]
   377       public static extern bool DeviceIoControl(IntPtr handle,
   378         DriveCommand command, ref DriveCommandParameter parameter,
   379         int parameterSize, out DriveSmartReadDataResult result, int resultSize,
   380         out uint bytesReturned, IntPtr overlapped);
   381 
   382       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   383       [return: MarshalAsAttribute(UnmanagedType.Bool)]
   384       public static extern bool DeviceIoControl(IntPtr handle,
   385         DriveCommand command, ref DriveCommandParameter parameter,
   386         int parameterSize, out DriveSmartReadThresholdsResult result, 
   387         int resultSize, out uint bytesReturned, IntPtr overlapped);
   388 
   389       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   390       [return: MarshalAsAttribute(UnmanagedType.Bool)]
   391       public static extern bool DeviceIoControl(IntPtr handle,
   392         DriveCommand command, ref DriveCommandParameter parameter,
   393         int parameterSize, out DriveCommandResult result, int resultSize,
   394         out uint bytesReturned, IntPtr overlapped);
   395 
   396       [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   397       [return: MarshalAsAttribute(UnmanagedType.Bool)]
   398       public static extern bool DeviceIoControl(IntPtr handle,
   399         DriveCommand command, ref DriveCommandParameter parameter,
   400         int parameterSize, out DriveIdentifyResult result, int resultSize,
   401         out uint bytesReturned, IntPtr overlapped);
   402     }    
   403   }
   404 }