Количество циклов загрузки / выгрузки с использованием SMART и WMI - PullRequest
4 голосов
/ 24 марта 2012

В попытке разработать инструмент анализа жесткого диска, я пытаюсь получить значение счетчика циклов загрузки / выгрузки из данных S.M.A.R.T моего жесткого диска, мне интересно, знает ли кто-нибудь, как это сделать. Что я пытаюсь:

  1. Я ищу данные класса WMI MSStorageDriver_ATAPISmartData, где номер атрибута 193 - это то, что мне нужно (атрибут, представляющий количество циклов загрузки / выгрузки)
  2. Данные, которые я получаю, выглядят как

enter image description here

Я думаю, что я близок, данные красным цветом совпадают с тем, что показывает издание Everest Home, когда я его запускаю, в идеале я бы хотел, чтобы последняя часть (атрибут называется data)

enter image description here

Метод сбора этих данных:

static void doStuff()
{
    try
    {

        byte TEMPERATURE_ATTRIBUTE = 193;

        ManagementObjectSearcher searcher = new ManagementObjectSearcher(@"\root\WMI", "SELECT * FROM MSStorageDriver_ATAPISmartData");
        //loop through all the hard disks
        foreach (ManagementObject queryObj in searcher.Get())
        {
            byte[] arrVendorSpecific = (byte[])queryObj.GetPropertyValue("VendorSpecific");

            int tempIndex = Array.IndexOf(arrVendorSpecific, TEMPERATURE_ATTRIBUTE);
            Console.WriteLine("HDD TEMP: " + arrVendorSpecific[tempIndex + 5].ToString());

            foreach (byte dat in arrVendorSpecific)
            {
                Console.Write(dat.ToString() + " ");
            }
        }

    }
    catch (Exception err) { Console.WriteLine(err.Message); }
}

P.S. этот метод работает для определения температуры жесткого диска (для этого и нужна строка Console.WriteLine("HDD TEMP: " + arrVendorSpecific[tempIndex + 5].ToString());, но я не уверен, почему ее значение tempIndex + 5

1 Ответ

9 голосов
/ 24 марта 2012

Код, который вы используете, является неправильным, потому что вы используете последовательный поиск (Array.IndexOf), чтобы найти SMART Attribute ID (у вас могут быть ложные срабатывания, потому что это значение может совпадать с другим в массиве), ID этих атрибутов имеет фиксированное положение внутри документированной структуры (SMART Attribute Overview).

Таблица атрибутов SMART

Offset  Length  Description
        (bytes) 
0         2      SMART structure version (this is vendor-specific)
2         12     Attribute entry 1
2+(12)    12     Attribute entry 2
. . .
2+(12*29) 12     Attribute entry 30

Запись в таблице атрибутов

enter image description here

отсюда вы можете написать код для поиска местоположения каждого атрибута и получения значений, которые вы ищете

using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
using System.Runtime.InteropServices;

namespace GetWMI_Info
{
    class Program
    {

        [StructLayout(LayoutKind.Sequential)]
        public struct Attribute
        {
            public byte AttributeID;
            public ushort Flags;
            public byte Value;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] VendorData;
        }

        static void Main(string[] args)
        {
            try
            {
                Attribute AtributeInfo;
                ManagementScope Scope = new ManagementScope(String.Format("\\\\{0}\\root\\WMI", "localhost"), null);
                Scope.Connect();
                ObjectQuery Query = new ObjectQuery("SELECT VendorSpecific FROM MSStorageDriver_ATAPISmartData");
                ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
                byte LoadCycleCount = 0xC1;
                int Delta  = 12;
                foreach (ManagementObject WmiObject in Searcher.Get())
                {
                    byte[] VendorSpecific = (byte[])WmiObject["VendorSpecific"];
                    for (int offset = 2; offset < VendorSpecific.Length; )
                    {
                        if (VendorSpecific[offset] == LoadCycleCount)
                        {

                            IntPtr buffer = IntPtr.Zero;
                            try
                            {
                                buffer = Marshal.AllocHGlobal(Delta);
                                Marshal.Copy(VendorSpecific, offset, buffer, Delta);
                                AtributeInfo = (Attribute)Marshal.PtrToStructure(buffer, typeof(Attribute));
                                Console.WriteLine("AttributeID {0}", AtributeInfo.AttributeID);
                                Console.WriteLine("Flags {0}", AtributeInfo.Flags);
                                Console.WriteLine("Value {0}", AtributeInfo.Value);
                                Console.WriteLine("Value {0}", BitConverter.ToString(AtributeInfo.VendorData));
                            }
                            finally
                            {
                                if (buffer != IntPtr.Zero)
                                {
                                    Marshal.FreeHGlobal(buffer);
                                }
                            }                                                
                        }
                        offset += Delta;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(String.Format("Exception {0} Trace {1}",e.Message,e.StackTrace));
            }
            Console.WriteLine("Press Enter to exit");
            Console.Read();
        }
    }
}
...