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