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.
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
}