Hallo,
ich will die S.M.A.R.T. Daten der Festplatten auslesen. Dazu habe ich eine VB.NET Klasse gefunden Hier!.
Diese habe ich nun nach C# übersetzt und ab geändert so wie es halt nötig war. Mein problem, beim aufruf der DLL-Funktion DeviceIoControl() wird das Programm einfach beendet. Der Output im VisualStudio:
Ich hänge mal meine von VB nach C# übersetzte Smart-Klasse dran. Aber wie gesagt manche Sachen musste ich ändern.
Und hier noch mein Aufruf der Klasse:
Hoffentlich kann mir jemand helfen!
ich will die S.M.A.R.T. Daten der Festplatten auslesen. Dazu habe ich eine VB.NET Klasse gefunden Hier!.
Diese habe ich nun nach C# übersetzt und ab geändert so wie es halt nötig war. Mein problem, beim aufruf der DLL-Funktion DeviceIoControl() wird das Programm einfach beendet. Der Output im VisualStudio:
The program '[3352] SmartView.vshost.exe: Managed (v2.0.50727)' has exited with code -1073740791 (0xc0000409).
Ich hänge mal meine von VB nach C# übersetzte Smart-Klasse dran. Aber wie gesagt manche Sachen musste ich ändern.
C#:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Management;
using System.Linq;
using System.Text;
using System.Collections;
using System.Windows.Forms;
namespace SmartView
{
#region ReadSmartResult Enum
public enum ReadSmartResult
{
DRIVE_DOES_NOT_EXIST = 0,
ACCESS_DENIED = 1,
NO_SMART_AVAILABLE = 2,
SUCCEEDED = 3
}
#endregion
#region Attributes 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,
// Fequency of mistakes as a result of impact loads
SMART_ATTRIB_AIRFLOW_TEMPERATURE = 190,
// Fequency 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
}
#endregion
public class Smart
{
public string[] Drives;
public string[] Names;
public STORAGE_PREDICT_FAILURE SmartData;
#region Konstanten
private const int IOCTL_STORAGE_PREDICT_FAILURE = 0x2D1100; // uint könnte probleme geben
private const uint STATUS_INVALID_DEVICE_REQUEST = 0xC0000010;
private const short FILE_SHARE_NONE = 0;
private const short OPEN_EXISTING = 3;
private const short INVALID_HANDLE_VALUE = -1;
private const uint GENERIC_READ = 0x80000000; // fehler beim casten?
private const int GENERIC_WRITE = 0x40000000;
private const int FILE_SHARE_READ = 1;
private const int FILE_SHARE_WRITE = 2;
#endregion
#region DLL Deklaration
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
IntPtr lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
private static extern int DeviceIoControl(IntPtr hDevice,
int dwioControlCode,
IntPtr lpInBuffer,
int nInBufferSize,
out STORAGE_PREDICT_FAILURE lpOutBuffer,
int nOutBufferSize,
ref int lpBytesReturned,
IntPtr lpOverlapped);
#endregion
#region Funktionen
// Festplatten (und auch USB-Laufwerke) per WMI ermitteln
public int GetPhysicalDrives()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
Hashtable ht = new Hashtable();
int i = 0;
ManagementObjectCollection moc = searcher.Get();
Drives = new string[moc.Count];
Names = new string[moc.Count];
try
{
foreach (ManagementObject wmi_HD in moc)
{
ht.Add(wmi_HD.Properties["deviceid"].Value, wmi_HD.Properties["caption"].Value);
// Hier kommt die Exception
Drives[i] = wmi_HD.Properties["deviceid"].Value.ToString();
Names[i] = wmi_HD.Properties["caption"].Value.ToString();
i++;
}
return i;
}
catch (Exception ex)
{
return 0;
}
finally
{
ht = null;
}
}
// Smart-Werte für angegebenes Laufwerk lesen
// stehen danach in SmartData zur Verfügung
public ReadSmartResult ReadSmart(string Drive)
{
IntPtr Device;
bool Result;
int ReturnedBytes = 0;
this.SmartData = new STORAGE_PREDICT_FAILURE();
IntPtr zeroPtr = new IntPtr(0);
// Laufwerk öffnen
Device = CreateFile(Drive,
GENERIC_READ,
FILE_SHARE_READ,
IntPtr.Zero,
OPEN_EXISTING,
0,
IntPtr.Zero);
if (Device.ToInt32() == INVALID_HANDLE_VALUE)
{
if (Marshal.GetLastWin32Error() == 2)
{
//Zugriff verweigert, wahrscheinlich fehlen Adminrechte
return ReadSmartResult.ACCESS_DENIED;
}
else
{
// das angegebene Laufwerk existiert nicht
return ReadSmartResult.DRIVE_DOES_NOT_EXIST;
}
}
// S.M.A.R.T. auslesen
Result = Convert.ToBoolean(DeviceIoControl(Device,
IOCTL_STORAGE_PREDICT_FAILURE,
IntPtr.Zero,
0,
out SmartData,
Marshal.SizeOf(SmartData),
ref ReturnedBytes,
IntPtr.Zero));
CloseHandle(Device);
if (Result)
{
// erfolgreich
return ReadSmartResult.SUCCEEDED;
}
else
{
// es konnten keine S.M.A.R.T. Eigenschaften gelesen werden
return ReadSmartResult.NO_SMART_AVAILABLE;
}
}
// Attributsnamen (falls vohanden) ausgeben
public string GetAttribute(Attributes Index)
{
string outString;
outString = Index.ToString();
// Wenn outString noch numerisch ist, dann ist kein
// Beschreibungstext in der Definition angegeben,
// Ersatztext wird ausgegeben
if (IsNumeric(outString))
outString = "<Herstellerspezifisch>";
return outString;
}
// Smart-Wert auswerten, 12Byte beginnend ab Offset
// Offset = X * 12 + 2
public void GetSmartValue(int Offset,
ref int Attribut,
ref long Value,
ref long Worst,
ref long Data)
{
// 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];
string str = "";
for (int i = 11; i <= 5; i--)
{
str += Convert.ToString((SmartData.VendorSpecific[Offset + i]), 16);
}
Data = Convert.ToInt64(str, 16);
}
#endregion
// Werte aus SmartData in Listview eintragen
public void AddSmartToListView(ListView lv, int Index)
{
int Attribut = 0;
long Value = 0, Worst = 0, Data = 0;
for (int i = 0; i <= 29; i++)
{
GetSmartValue(i * 12 + 2, ref Attribut, ref Value, ref Worst, ref Data);
// 0 ist kein gültiger Wert, d.h. dieser Speicherblock enthält
// kein Attribut
if (!Attribut.Equals(Attributes.SMART_ATTRIB_Invalid))
{
// ins Listview eintragen
ListViewItem lvi = new ListViewItem();
//Attributes at = new Attributes();
//string att = Enum.GetName(typeof(Attributes), Attribut);
Attributes at = (Attributes)Enum.Parse(typeof(Attributes), Convert.ToString(Attribut));
//string attributeName = Enum.GetName(typeof(Attributes), Convert.ToString(1));
//Attributes attr = (Attributes) Enum.Parse(typeof(Attributes), attributeName);
lvi.Text = Attribut + " - " + GetAttribute(at);
lvi.SubItems.Add(Value.ToString());
lvi.SubItems.Add(Worst.ToString());
lvi.SubItems.Add(Data.ToString());
for (int j = 0; j <= lv.Groups.Count - 1; i++)
{
if (lv.Groups[j].Name == "LW" + Index)
lvi.Group = lv.Groups[j];
}
lv.Items.Add(lvi);
}
}
}
#region Hilfsklasse zur Zwischenspeicherung
[StructLayout(LayoutKind.Sequential)]
public class STORAGE_PREDICT_FAILURE
{
public int PredictFailure;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] VendorSpecific;
public STORAGE_PREDICT_FAILURE()
{
VendorSpecific = new byte[511];
}
}
#endregion
#region IsNumeric Methode
// IsNumeric Function
static bool IsNumeric(object Expression)
{
// Variable to collect the Return value of the TryParse method.
bool isNum;
// Define variable to collect out parameter of the TryParse method. If the conversion fails, the out parameter is zero.
double retNum;
// The TryParse method converts a string in a specified style and culture-specific format to its double-precision floating point number equivalent.
// The TryParse method does not generate an exception if the conversion fails. If the conversion passes, True is returned. If it does not, False is returned.
isNum = Double.TryParse(Convert.ToString(Expression), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);
return isNum;
}
#endregion
}
}
Und hier noch mein Aufruf der Klasse:
C#:
private void button1_Click(object sender, EventArgs e)
{
Smart smart = new Smart();
listView1.Items.Clear();
listView1.Groups.Clear();
// Laufwerke ermitteln
int j = smart.GetPhysicalDrives() - 1;
// S.M.A.R.T. Eigenschaften auslesen und ins Listview eintragen
for(int i = 0; i <= j; i++) {
switch(smart.ReadSmart(smart.Drives[i])) {
case ReadSmartResult.SUCCEEDED:
// S.M.A.R.T.-Werte wurden ausgelesen und werden
// ins Listview eingetragen
listView1.Groups.Add("LW" + i, smart.Names[i] + " (" + smart.Drives[i] + ")");
smart.AddSmartToListView(listView1, i);
break;
case ReadSmartResult.NO_SMART_AVAILABLE:
// S.M.A.R.T. ist für dieses Laufwerk nicht verfügbar
listView1.Groups.Add("LW" + i, smart.Names[i] + " (" + smart.Drives[i] + ")");
ListViewItem lvi = new ListViewItem();
lvi.Text = "S.M.A.R.T. not available";
lvi.Group = listView1.Groups[i];
listView1.Items.Add(lvi);
break;
case ReadSmartResult.ACCESS_DENIED:
// Zugriff uafs Laufwerk verweigert, wahrscheinlich fehlen
// Adminrechte (v.a. unter Vista)
listView1.Groups.Add("LW" + i, smart.Names[i] + " (" + smart.Drives[i] + ")");
ListViewItem lvi2 = new ListViewItem();
lvi2.Text = "Zugriff verweigert, Administratorrechte benötigt!";
lvi2.Group = listView1.Groups[i];
listView1.Items.Add(lvi2);
break;
case ReadSmartResult.DRIVE_DOES_NOT_EXIST:
// Das angegebene Laufwerk existiert nicht
// nichts ausgeben
break;
}
}
}
Hoffentlich kann mir jemand helfen!
