Die Community zu .NET und Classic VB.
Menü

VB.NET-Tipp 0093: S.M.A.R.T-Werte der Festplatten auslesen

 von 

Beschreibung

Mit der Self-Monitoring, Analysis and Reporting Technology (SMART) ist es möglich allerlei Kennzahlen der Festplatte auszulesen, welche dazu verwendet werden können vor drohendem Datenverlust zu warnen. Dieser Tipp demonstriert, wie die entsprechenden Werte ausgelesen werden können. Dabei ist die Auswertung der 8 Byte Daten herstellerspezifisch und hier an Samsung-Festplatten orientiert.

Zur Ausführung werden Administratorrechte benötigt!

Schwierigkeitsgrad:

Schwierigkeitsgrad 2

Framework-Version(en):

.NET Framework 1.1, .NET Framework 2.0, .NET Framework 3.0, .NET Framework 3.5

.NET-Version(en):

Visual Basic 2003, Visual Basic 2005, Visual Basic 2008

Download:

Download des Beispielprojektes [17,5 KB]

' Dieser Quellcode stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!

' Projektversion:   Visual Studio 2005
'
' Referenzen: 
'  - System
'  - System.Data
'  - System.Deployment
'  - System.Drawing
'  - System.Windows.Forms
'  - System.Xml
'
' Imports: 
'  - Microsoft.VisualBasic
'  - System
'  - System.Collections
'  - System.Collections.Generic
'  - System.Data
'  - System.Drawing
'  - System.Diagnostics
'  - System.Windows.Forms
'

' ##############################################################################
' ################################# Smart.vb ###################################
' ##############################################################################
Imports System.Runtime.InteropServices

Public Module Smart

    Public Enum ReadSmart_Results
        DRIVE_DOES_NOT_EXIST
        ACCESS_DENIED
        NO_SMART_AVAILABLE
        SUCCEEDED
    End Enum

    Public Enum Attributes
        ' Invalid attribute identifier
        SMART_ATTRIB_Invalid = 0
        ' Frequency of errors while reading raw data
        SMART_ATTRIB_RAW_READ_ERROR_RATE = 1
        ' Average efficiency of a hard disk
        SMART_ATTRIB_THROUGHPUT_PERFORMANCE = 2
        ' needed to spin up
        SMART_ATTRIB_SPIN_UP_TIME = 3
        ' Number of spindle start/stop cycles
        SMART_ATTRIB_START_STOP_COUNT = 4
        ' Quantity of remapped sectors
        SMART_ATTRIB_REALLOCATION_SECTOR_COUNT = 5
        ' Reserve of channel while reading
        SMART_ATTRIB_Read_Channel_Margin = 6
        ' Frequency of errors while positioning
        SMART_ATTRIB_SEEK_ERROR_RATE = 7
        ' Average efficiency of operations while positioning
        SMART_ATTRIB_Seek_TimerPerformance = 8
        ' Number of hours elapsed in the power-on state
        SMART_ATTRIB_POWER_ON_HOURS_COUNT = 9
        ' Number of retry attempts to spin up
        SMART_ATTRIB_SPIN_RETRY_COUNT = 10
        ' Count number of attempts to calibrate the device
        SMART_ATTRIB_RECALIBRATION_RETRIES = 11
        ' Number of power-on events
        SMART_ATTRIB_DEVICE_POWER_CYCLE_COUNT = 12
        ' Frequency of ‘program’ errors while reading from a disk
        SMART_ATTRIB_SOFT_READ_ERROR_RATE = 13
        ' Frequency of mistakes as a result of impact loads
        SMART_ATTRIB_AIRFLOW_TEMPERATURE = 190
        ' Frequency of mistakes as a result of impact loads
        SMART_ATTRIB_G_Sense_Error_Rate = 191
        ' Number of power-off or emergency retract cycles
        SMART_ATTRIB_Power_Off_Retract_Count = 192
        ' Number of cycles into landing zone position
        SMART_ATTRIB_LOAD_UNLOAD_CYCLE_COUNT = 193
        ' Temperature of a hard disk assembly
        SMART_ATTRIB_HDA_TEMPERATURE = 194
        ' Number of ECC on-the-fly errors
        SMART_ATTRIB_Hardware_ECC_Recovered = 195
        ' Number of remapping operations
        SMART_ATTRIB_REALLOCATION_COUNT = 196
        ' Number of unstable sectors (waiting for remapping)
        SMART_ATTRIB_CURRENT_PENDING_SECTOR_COUNT = 197
        ' Number of uncorrected errors
        SMART_ATTRIB_UNCORRECTABLE_SECTOR_COUNT = 198
        ' Number of CRC errors during UDMA mode
        SMART_ATTRIB_ULTRA_DMA_CRC_ERROR_COUNT = 199
        ' Number of errors while writing to disk (or) multi-zone error 
        ' rate (or) flying height
        SMART_ATTRIB_WRITE_ERROR_RATE = 200
        ' Number of off-track errors
        SMART_ATTRIB_Soft_Read_Error_Count = 201
        ' Number of Data Address Mark (DAM) errors (or) vendor-specific
        SMART_ATTRIB_Data_Address_Mark_Errors = 202
        ' Number of ECC errors
        SMART_ATTRIB_Run_Out_Cancel = 203
        ' Number of errors corrected by software ECC
        SMART_ATTRIB_Soft_ECC_Correction = 204
        ' Number of thermal asperity errors
        SMART_ATTRIB_Thermal_Asperity_Rate = 205
        ' Height of heads above the disk surface
        SMART_ATTRIB_Flying_Height = 206
        ' Amount of high current used to spin up the drive
        SMART_ATTRIB_Spin_High_Current = 207
        ' Number of buzz routines to spin up the drive
        SMART_ATTRIB_Spin_Buzz = 208
        ' Drive’s seek performance during offline operations
        SMART_ATTRIB_Offline_Seek_Performance = 209
        ' Shift of disk is possible as a result of strong shock loading in the 
        ' store, as a result of falling (or) temperature
        SMART_ATTRIB_Disk_Shift = 220
        ' Number of errors as a result of impact loads as detected by 
        ' a shock sensor
        SMART_ATTRIB_G_SENSE_ERROR_Count = 221
        ' Number of hours in general operational state
        SMART_ATTRIB_Loaded_Hours = 222
        ' Loading on drive caused by numerous recurrences of operations, like 
        ' reading, recording, positioning of heads, etc.
        SMART_ATTRIB_Load_Unload_Retry_Count = 223
        ' Load on drive caused by friction in mechanical parts of the store
        SMART_ATTRIB_Load_Friction = 224
        ' Total number of load cycles
        SMART_ATTRIB_Load_Unload_Cycle_Count1 = 225
        ' General time for loading in a drive
        SMART_ATTRIB_Load_In_Time = 226
        ' Quantity efforts of the rotating moment of a drive
        SMART_ATTRIB_Torque_Amplification_Count = 227
        ' Number of power-off retract events.
        SMART_ATTRIB_POWER_OFF_RETRACT_COUNT1 = 228
        ' Amplitude of heads trembling (GMR-head) in running mode
        SMART_ATTRIB_GMR_Head_Amplitude = 230
        ' Temperature of a drive
        SMART_ATTRIB_Drive_Temperature = 231
        ' Time while head is positioning
        SMART_ATTRIB_Head_Flying_Hours = 240
        ' Number of errors while reading from a disk
        SMART_ATTRIB_Read_Error_Retry_Rate = 250
    End Enum

    Private Const IOCTL_STORAGE_PREDICT_FAILURE As Integer = &H2D1100
    Private Const STATUS_INVALID_DEVICE_REQUEST As Integer = &HC0000010

    Private Const FILE_SHARE_NONE As Short = 0
    Private Const OPEN_EXISTING As Short = 3
    Private Const INVALID_HANDLE_VALUE As Short = -1
    Private Const GENERIC_READ As Integer = &H80000000
    Private Const GENERIC_WRITE As Integer = &H40000000
    Private Const FILE_SHARE_READ As Integer = 1
    Private Const FILE_SHARE_WRITE As Integer = 2

    <DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Function CreateFile(ByVal lpFileName As String, _
        ByVal dwDesiredAccess As Integer, _
        ByVal dwShareMode As Integer, _
        ByVal lpSecurityAttributes As IntPtr, _
        ByVal dwCreationDisposition As Integer, _
        ByVal dwFlagsAndAttributes As Integer, _
        ByVal hTemplateFile As IntPtr) As IntPtr
    End Function

    <DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Function CloseHandle(ByVal hObject As IntPtr) As Boolean
    End Function

    <DllImport("kernel32.dll", ExactSpelling:=True, SetLastError:=True, _
        CharSet:=CharSet.Auto)> _
    Private Function DeviceIoControl(ByVal hDevice As IntPtr, _
        ByVal dwIoControlCode As Integer, _
        ByVal lpInBuffer As IntPtr, _
        ByVal nInBufferSize As Integer, _
        <Out()> ByVal lpOutBuffer As STORAGE_PREDICT_FAILURE, _
        ByVal nOutBufferSize As Integer, _
        ByRef lpBytesReturned As Integer, _
        ByVal lpOverlapped As IntPtr) As Integer
    End Function

    Public Drives As String()
    Public Names As String()
    Public SmartData As STORAGE_PREDICT_FAILURE

    ' Alle Festplatten ermitteln
    Public Function GetPhysicalDrives()
        Dim objWMIService, colItems, objItem As Object
        Dim i As Integer

        ' winmgmts:{impersonationLevel=impersonate}!\\
        objWMIService = GetObject("winmgmts:\\.\root\cimv2")
        colItems = objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive")

        Drives = New String(colItems.count - 1) {}
        Names = New String(colItems.count - 1) {}
        i = 0

        For Each objItem In colItems
            Drives(i) = objItem.deviceid()
            Names(i) = objItem.caption
            i += 1
        Next

        Return colItems.Count
    End Function

    ' Smart-Werte für angegebenes Laufwerk lesen, stehen danach in 
    '  SmartData zur Verfügung
    Public Function ReadSmart(ByVal Drive As String) As ReadSmart_Results
        Dim Device As IntPtr
        Dim Result As Boolean
        Dim ReturnedBytes As Integer

        SmartData = New STORAGE_PREDICT_FAILURE

        Device = CreateFile(Drive, _
            GENERIC_READ, _
            FILE_SHARE_READ, _
            IntPtr.Zero, _
            OPEN_EXISTING, _
            0, _
            IntPtr.Zero)

        If Device.ToInt32 = INVALID_HANDLE_VALUE Then
            If Marshal.GetLastWin32Error = 5 Then
                Return ReadSmart_Results.ACCESS_DENIED
            Else
                Return ReadSmart_Results.DRIVE_DOES_NOT_EXIST
            End If
        End If

        Result = DeviceIoControl(Device, _
            IOCTL_STORAGE_PREDICT_FAILURE, _
            IntPtr.Zero, _
            0, _
            SmartData, _
            Marshal.SizeOf(SmartData), _
            ReturnedBytes, _
            IntPtr.Zero)

        CloseHandle(Device)

        If Result Then
            Return ReadSmart_Results.SUCCEEDED
        Else
            Return ReadSmart_Results.NO_SMART_AVAILABLE
        End If
    End Function

    ' Attributsnamen (falls vohanden) ausgeben
    Public Function GetAttribute(ByVal Index As Attributes) As String
        Dim outString As String

        outString = Index.ToString
        If IsNumeric(outString) Then outString = "<Herstellerspezifisch>"

        Return outString
    End Function

    ' Smart-Wert auswerten, 12Byte beginnend ab Offset = X * 12 + 2
    Public Sub GetSmartValue(ByVal Offset As Integer, _
        ByRef Attribut As Integer, ByRef Value As Integer, _
        ByRef Worst As Integer, ByRef Data As Integer)

        ' Der S.M.A.R.T.-Wert setzt sich aus 12Byte zusammen
        ' 1. Byte - Attributesnamen
        Attribut = SmartData.VendorSpecific(Offset)
        ' 2./3. Byte - Herstellerspezifisch
        '  interessant ist hier das 1. Bit, falls der Wert dieses Smartwertes 
        '  unter dem Grenzwert liegt, gibt dieses Bit an, ob die Festplatte 
        '  innerhalb der nächsten 24h ausfallen wird!
        ' 4. Byte - Wert
        Value = SmartData.VendorSpecific(Offset + 3)
        ' 5.-12. Byte - RAW-Value (herstellerspezifisch)
        Worst = SmartData.VendorSpecific(Offset + 4)
        Dim str As String = ""
        For i As Integer = 11 To 5 Step -1
            str &= Hex(SmartData.VendorSpecific(Offset + i))
        Next
        Data = Convert.ToInt64(str, 16)
    End Sub

    ' Werte aus SmartData in Listview eintragen
    Public Sub AddSmartToListView(ByVal lv As ListView, ByVal Index As Integer)
        Dim Attribut, Value, Worst, Data As Integer

        For i As Integer = 0 To 29
            GetSmartValue(i * 12 + 2, Attribut, Value, Worst, Data)
            '0 ist kein gültiger Wert!
            If Not Attribut = Attributes.SMART_ATTRIB_Invalid Then
                Dim lvi As New ListViewItem
                lvi.Text = Attribut & " - " & GetAttribute(Attribut)
                lvi.SubItems.Add(Value)
                lvi.SubItems.Add(Worst)
                lvi.SubItems.Add(Data)
                For j As Integer = 0 To lv.Groups.Count - 1
                    If lv.Groups(j).Name = "LW" & Index Then _
                        lvi.Group = lv.Groups(j)
                Next
                lv.Items.Add(lvi)
            End If
        Next
    End Sub
End Module

<StructLayout(LayoutKind.Sequential)> _
Public Class STORAGE_PREDICT_FAILURE

    Public PredictFailure As Integer
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=512)> _
    Public VendorSpecific() As Byte

    Sub New()
        VendorSpecific = New Byte(511) {}
    End Sub
End Class


' ##############################################################################
' ################################ Testform.vb #################################
' ##############################################################################
Public Class Testform

    Private Sub Button1_Click(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles Button1.Click

        ListView1.Items.Clear()
        ListView1.Groups.Clear()

        Dim j As Integer = GetPhysicalDrives() - 1

        For i As Integer = 0 To j
            Select Case ReadSmart(Drives(i))
                Case ReadSmart_Results.SUCCEEDED
                    ListView1.Groups.Add("LW" & i, Names(i) & _
                        "  (" & Drives(i) & ")")
                    AddSmartToListView(Me.ListView1, i)
                Case ReadSmart_Results.NO_SMART_AVAILABLE
                    ListView1.Groups.Add("LW" & i, Names(i) & _
                        "  (" & Drives(i) & ")")
                    Dim lvi As New ListViewItem
                    lvi.Text = "S.M.A.R.T. not available"
                    lvi.Group = ListView1.Groups(i)
                    ListView1.Items.Add(lvi)
                Case ReadSmart_Results.ACCESS_DENIED
                    ListView1.Groups.Add("LW" & i, Names(i) & _
                        "  (" & Drives(i) & ")")
                    Dim lvi As New ListViewItem
                    lvi.Text = _
                        "Zugriff verweigert, Administratorrechte benötigt!"
                    lvi.Group = ListView1.Groups(i)
                    ListView1.Items.Add(lvi)
                Case ReadSmart_Results.DRIVE_DOES_NOT_EXIST
                    'Das angegebene Laufwerk existiert nicht
                    'nicht ausgeben
            End Select
        Next
    End Sub

    Private Sub Testform_Load(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load

        ListView1.Columns(0).Width = 360
        ListView1.Columns(1).Width = 100
        ListView1.Columns(2).Width = 100
        ListView1.Columns(3).Width = 150
    End Sub
End Class

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 2 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von Henning Paschke am 26.05.2010 um 18:52

Wie kann ich aus STORAGE_PREDICT_FAILURE die Grenze für ein SMART-Attribut auslesen. Auch der Attribut-Type wäre wichtig. Bei den smartmontools hat die Tabelle folgende Werte
ID, ATTRIBUTE_NAME, FLAG, VALUE, WORST, THRESH, TYPE, UPDATED, WHEN_FAILED, RAW_VALUE
Wo finde ich die entsprechenden Werte?

Kommentar von Carsten am 02.06.2009 um 01:31

Und wie könnte man andere Festplatten damit überwachen? Gibt es dafür schon eine Routine?

Vielen Dank!