Fixed a NullReferenceException in the HDD SMART code.
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 The contents of this file are subject to the Mozilla Public License Version
6 1.1 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 for the specific language governing rights and limitations under the License.
15 The Original Code is the Open Hardware Monitor code.
17 The Initial Developer of the Original Code is
18 Michael Möller <m.moeller@gmx.ch>.
19 Portions created by the Initial Developer are Copyright (C) 2009-2010
20 the Initial Developer. All Rights Reserved.
24 Alternatively, the contents of this file may be used under the terms of
25 either the GNU General Public License Version 2 or later (the "GPL"), or
26 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 in which case the provisions of the GPL or the LGPL are applicable instead
28 of those above. If you wish to allow use of your version of this file only
29 under the terms of either the GPL or the LGPL, and not to allow others to
30 use your version of this file under the terms of the MPL, indicate your
31 decision by deleting the provisions above and replace them with the notice
32 and other provisions required by the GPL or the LGPL. If you do not delete
33 the provisions above, a recipient may use your version of this file under
34 the terms of any one of the MPL, the GPL or the LGPL.
39 using System.Collections.Generic;
40 using System.Runtime.InteropServices;
42 namespace OpenHardwareMonitor.Hardware.HDD {
47 public enum Status : ushort {
48 PreFailureWarranty = 0x01,
49 OnLineCollection = 0x02,
56 public enum AttributeID : byte {
58 ThroughputPerformance = 0x02,
60 StartStopCount = 0x04,
61 ReallocatedSectorsCount = 0x05,
62 ReadChannelMargin = 0x06,
64 SeekTimePerformance = 0x08,
66 SpinRetryCount = 0x0A,
67 RecalibrationRetries = 0x0B,
68 PowerCycleCount = 0x0C,
69 SoftReadErrorRate = 0x0D,
71 HardwareECCRecovered = 0xC3,
72 ReallocationEventCount = 0xC4,
73 CurrentPendingSectorCount = 0xC5,
74 UncorrectableSectorCount = 0xC6,
75 UltraDMACRCErrorCount = 0xC7,
79 [StructLayout(LayoutKind.Sequential, Pack = 1)]
80 public struct DriveAttribute {
81 public AttributeID ID;
82 public Status StatusFlags;
83 public byte AttrValue;
84 public byte WorstValue;
85 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
86 public byte[] RawValue;
91 private enum AccessMode : uint {
99 private enum ShareMode : uint {
106 private enum CreationMode : uint {
115 private enum FileAttribute : uint {
116 Readonly = 0x00000001,
119 Directory = 0x00000010,
120 Archive = 0x00000020,
123 Temporary = 0x00000100,
124 SparseFile = 0x00000200,
125 ReparsePoint = 0x00000400,
126 Compressed = 0x00000800,
127 Offline = 0x00001000,
128 NotContentIndexed = 0x00002000,
129 Encrypted = 0x00004000,
132 private enum DriveCommand : uint {
133 GetVersion = 0x00074080,
134 SendDriveCommand = 0x0007c084,
135 ReceiveDriveData = 0x0007c088
138 [StructLayout(LayoutKind.Sequential, Pack = 1)]
139 private struct CommandBlockRegisters {
140 public byte Features;
141 public byte SectorCount;
147 public byte Reserved;
150 [StructLayout(LayoutKind.Sequential, Pack = 1)]
151 private struct DriveCommandParameter {
152 private uint BufferSize;
153 public CommandBlockRegisters Registers;
154 public byte DriveNumber;
155 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)]
156 public byte[] Reserved;
159 [StructLayout(LayoutKind.Sequential, Pack = 1)]
160 private struct DriverStatus {
161 public byte DriverError;
162 public byte IDEError;
163 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
164 public byte[] Reserved;
167 [StructLayout(LayoutKind.Sequential, Pack = 1)]
168 private struct DriveCommandResult {
169 public uint BufferSize;
170 public DriverStatus DriverStatus;
173 [StructLayout(LayoutKind.Sequential, Pack = 1)]
174 private struct DriveSmartReadResult {
175 public uint BufferSize;
176 public DriverStatus DriverStatus;
178 public byte Reserved;
179 [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)]
180 public DriveAttribute[] Attributes;
183 [StructLayout(LayoutKind.Sequential, Pack = 1)]
184 private struct Identify {
185 public ushort GeneralConfiguration;
186 public ushort NumberOfCylinders;
187 public ushort Reserved;
188 public ushort NumberOfHeads;
189 public ushort UnformattedBytesPerTrack;
190 public ushort UnformattedBytesPerSector;
191 public ushort SectorsPerTrack;
192 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
193 public ushort[] VendorUnique;
194 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
195 public byte[] SerialNumber;
196 public ushort BufferType;
197 public ushort BufferSectorSize;
198 public ushort NumberOfEccBytes;
199 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
200 public byte[] FirmwareRevision;
201 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
202 public byte[] ModelNumber;
203 public ushort MoreVendorUnique;
204 public ushort DoubleWordIo;
205 public ushort Capabilities;
206 public ushort MoreReserved;
207 public ushort PioCycleTimingMode;
208 public ushort DmaCycleTimingMode;
209 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 406)]
213 [StructLayout(LayoutKind.Sequential, Pack = 1)]
214 private struct DriveIdentifyResult {
215 public uint BufferSize;
216 public DriverStatus DriverStatus;
217 public Identify Identify;
220 public static readonly IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
222 private const byte SMART_CMD = 0xB0;
223 private const byte ID_CMD = 0xEC;
225 private const byte SMART_READ_DATA = 0xD0;
226 private const byte SMART_ENABLE_OPERATIONS = 0xD8;
228 private const byte SMART_LBA_MID = 0x4F;
229 private const byte SMART_LBA_HI = 0xC2;
231 private const int MAX_DRIVE_ATTRIBUTES = 512;
233 private const string KERNEL = "kernel32.dll";
235 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
236 private static extern IntPtr CreateFile(string fileName,
237 AccessMode desiredAccess, ShareMode shareMode, IntPtr securityAttributes,
238 CreationMode creationDisposition, FileAttribute flagsAndAttributes,
239 IntPtr templateFilehandle);
241 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
242 public static extern int CloseHandle(IntPtr handle);
244 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
245 private static extern bool DeviceIoControl(IntPtr handle,
246 DriveCommand command, ref DriveCommandParameter parameter,
247 int parameterSize, out DriveSmartReadResult result, int resultSize,
248 out uint bytesReturned, IntPtr overlapped);
250 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
251 private static extern bool DeviceIoControl(IntPtr handle,
252 DriveCommand command, ref DriveCommandParameter parameter,
253 int parameterSize, out DriveCommandResult result, int resultSize,
254 out uint bytesReturned, IntPtr overlapped);
256 [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
257 private static extern bool DeviceIoControl(IntPtr handle,
258 DriveCommand command, ref DriveCommandParameter parameter,
259 int parameterSize, out DriveIdentifyResult result, int resultSize,
260 out uint bytesReturned, IntPtr overlapped);
262 public static IntPtr OpenPhysicalDrive(int driveNumber) {
263 return CreateFile(@"\\.\PhysicalDrive" + driveNumber,
264 AccessMode.Read | AccessMode.Write, ShareMode.Read | ShareMode.Write,
265 IntPtr.Zero, CreationMode.OpenExisting, FileAttribute.Device,
269 public static bool EnableSmart(IntPtr handle, int driveNumber) {
270 DriveCommandParameter parameter = new DriveCommandParameter();
271 DriveCommandResult result;
274 parameter.DriveNumber = (byte)driveNumber;
275 parameter.Registers.Features = SMART_ENABLE_OPERATIONS;
276 parameter.Registers.LBAMid = SMART_LBA_MID;
277 parameter.Registers.LBAHigh = SMART_LBA_HI;
278 parameter.Registers.Command = SMART_CMD;
280 return DeviceIoControl(handle, DriveCommand.SendDriveCommand,
281 ref parameter, Marshal.SizeOf(parameter), out result,
282 Marshal.SizeOf(typeof(DriveCommandResult)), out bytesReturned,
286 public static DriveAttribute[] ReadSmart(IntPtr handle, int driveNumber) {
287 DriveCommandParameter parameter = new DriveCommandParameter();
288 DriveSmartReadResult result;
291 parameter.DriveNumber = (byte)driveNumber;
292 parameter.Registers.Features = SMART_READ_DATA;
293 parameter.Registers.LBAMid = SMART_LBA_MID;
294 parameter.Registers.LBAHigh = SMART_LBA_HI;
295 parameter.Registers.Command = SMART_CMD;
297 bool valid = DeviceIoControl(handle, DriveCommand.ReceiveDriveData,
298 ref parameter, Marshal.SizeOf(parameter), out result,
299 Marshal.SizeOf(typeof(DriveSmartReadResult)), out bytesReturned,
305 return result.Attributes;
308 public static string ReadName(IntPtr handle, int driveNumber) {
309 DriveCommandParameter parameter = new DriveCommandParameter();
310 DriveIdentifyResult result;
313 parameter.DriveNumber = (byte)driveNumber;
314 parameter.Registers.Command = ID_CMD;
316 bool valid = DeviceIoControl(handle, DriveCommand.ReceiveDriveData,
317 ref parameter, Marshal.SizeOf(parameter), out result,
318 Marshal.SizeOf(typeof(DriveIdentifyResult)), out bytesReturned,
325 byte[] bytes = result.Identify.ModelNumber;
326 char[] chars = new char[bytes.Length];
327 for (int i = 0; i < bytes.Length; i += 2) {
328 chars[i] = (char)bytes[i + 1];
329 chars[i + 1] = (char)bytes[i];
332 return new string(chars).Trim();