Что нового

Программа для просмотра информации S.M.A.R.T. жестких дисков компьютера

Aleksandr Prilutskiy

Знающий
Сообщения
29
Репутация
9
AutoIt: 3.3.12.0
Версия: 0.1.1

Категория: Администрирование, Сеть, Система

Описание:
Программа для просмотра информации S.M.A.R.T. жестких дисков компьютера.

Код:
Код:
#Region Header
#cs

	Title:			S.M.A.R.T. Info
	Filename:		SMART_Info.au3
	Description:	Программа для чтения информации S.M.A.R.T. с жестких дисков
	Author:			Aleksandr Prilutskiy
	Version:		0.1.1
	Date:			16.09.2014
	Uses:

#ce
#EndRegion Header

#Region AutoIt3Wrapper directives section
#AutoIt3Wrapper_Icon=Resources\SMART_Info.ico
#AutoIt3Wrapper_OutFile=SMART_Info.exe
#AutoIt3Wrapper_OutFile_Type=exe
#AutoIt3Wrapper_Res_LegalCopyright=(c)2014 Aleksandr Prilutskiy
#AutoIt3Wrapper_Res_Description=HDD S.M.A.R.T. Information Viewer
#AutoIt3Wrapper_Res_Fileversion=0.1.1
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_UseUpx=Y
#AutoIt3Wrapper_UseX64=N
#AutoIt3Wrapper_Version=P
#AutoIt3Wrapper_Compile_both=N
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\ok.ico
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\warning.ico
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\error.ico
#AutoIt3Wrapper_Res_Icon_Add=Resources\Icons\hdd.ico
#AutoIt3Wrapper_Res_Icon_Add=Resources\SMART_Info_QR.ico
#EndRegion AutoIt3Wrapper directives section

#Region S.M.A.R.T. Attribute Names

Global	$sSMARTCodeTxt = "1,Частота ошибок при чтении данных;" & _
						"2,Общая производительность диска;" & _
						"3,Время раскрутки шпинделя;" & _
			            "4,Число циклов включения диска;" & _
						"5,Число переназначенных секторов;" & _
						"6,Запас канала чтения;" & _
						"7,Частота ошибок позиционирования;" & _
						"8,Позиционирование магнитных головок;" & _
						"9,Время во включенном состоянии (POH);" & _
						"10,Число попыток раскрутки шпинделя;" & _
						"11,Число повторов рекалибровки;" & _
						"12,Число циклов включения-выключения;" & _
						"13,Число ошибок программного обеспечения;" & _
						"183,Число ошибок изменения режима SATA;" & _
						"184,Число ошибок обмена через кэш;" & _
						"187,Reported UNC Errors;" & _
						"188,Число прерванных по таймеру операций;" & _
						"189,Число привышения высоты полета головки;" & _
						"190,Температура воздуха внутри диска;" & _
						"191,Число ошибок от ударных нагрузок;" & _
						"192,Число аварийных отказов;" & _
						"193,Число циклов парковки головок;" & _
						"194,Температура диска;" & _
						"195,Число аппаратно исправленных ошибок;" & _
						"196,Число операций переназначения секторов;" & _
						"197,Количество нестабильных секторов;" & _
						"198,Число некорректируемых секторов;" & _
						"199,Число ошибок при передаче по кабелю;" & _
						"200,Число ошибок при записи сектора;" & _
						"201,Частота программных ошибок чтения;" & _
						"202,Число ошибок Data Address Mark (DAM);" & _
						"203,Количество ошибок ECC;" & _
						"204,Число программно исправленных ошибок ECC;" & _
						"205,Число ошибок по причине перегрева;" & _
						"206,Высота головки над поверхностью диска;" & _
						"207,Сила тока при раскрутке диска;" & _
						"208,Number of buzz routines to spin up the drive;" & _
						"209,Производительность оффлайновых операций;" & _
						"220,Дистанция смещения блока пластин дисков;" & _
						"221,Число ошибок из-за нагрузок и ударов;" & _
						"222,Время перемещения магнитных головок;" & _
						"223,Попытки перемещения магнитных головок;" & _
						"224,Сила трения магнитных головок;" & _
						"225,Число парковок магнитных головок;" & _
						"226,Время возврата магнитных головок;" & _
						"227,Попытки компенсировать вращающий момент;" & _
						"228,Число повторов парковки головок;" & _
						"230,Амплитуда дрожания магнитных головок;" & _
						"231,Температура жёсткого диска;" & _
						"240,Время позиционирования головок;" & _
						"250,Число ошибок во время чтения;" & _
						"254,Число падений жесткого диска"

#EndRegion S.M.A.R.T. Attribute Names

#Region Initialization
#include <Constants.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <GUIConstantsEx.au3>
#include <GUITab.au3>
#include <GUIListView.au3>
#include <GUIImageList.au3>
#include <String.au3>
#include <Array.au3>
#include <Math.au3>
Opt("GUIOnEventMode", 1)
Opt("TrayIconHide", 1)

Local	$i ; Константы индексов изображений
Global	$iconOK				= _Set($i, 4)
Global	$iconWarning		= _Inc($i)
Global	$iconError			= _Inc($i)
Global	$iconBigHDD			= _Inc($i, 198)
Global	$imgQR				= _Set($i, 205)


Global	$AppVersion			= "0.1.1"								; текущая версия программы
Global	$WindowName			= "HDD S.M.A.R.T. Info"					; заголовок окна программы
Global	$WindowPosX			= 0										; начальная позиция окна по горизонтали
Global	$WindowPosY			= 0										; начальная позиция окна по вертикали
Global	$WindowWidth		= 700									; ширина окна программы
Global	$WindowHeight		= 600									; высота окна программы
Global	$WindowWidthMin		= 535									; минимальная ширина окна программы
Global	$WindowHeightMin	= 300									; минимальная высота окна программы
Global	$InfoHeight			= 130									; высота информационного поля на вкладках
Global	$WindowAboutName	= $WindowName & ". О программе"			; заголовок окна "О программе"
Global	$WindowAboutWidth	= 250									; ширина окна "О программе"
Global	$WindowAboutHeight	= 370									; высота окна "О программе"
Global	$GUI_WindowAbout											; окно "О программе"
Global	$WindowWaitWidth	= 550									; ширина окна ожидания
Global	$WindowWaitHeight	= 55									; высота окна ожидания
Global	$sIniFileName		= @ScriptDir & "\SysInfo.ini"			; имя файла конфигурации программы
Global	$sExeFileName		= @ScriptDir & "\SMART_Info.exe"		; имя исполняемого файла (для иконок)

Global	$GUI_WindowMain												; главное окно программы
Global	$GUI_LabelMain												; центральное поле с надписью
Global	$GUI_Icons			= -1									; список пиктограмм
Global	$GUI_TabMain												; основной элемент со вкладками
Dim		$GUI_TabItem[1]												; массив вкладок
Dim		$GUI_ListView[1]											; массив таблиц, содержащих данные S.M.A.R.T.

CreateGUI()

#EndRegion Initialization

#Region GUI
;----------------------------------------- НАСТРОЙКА ПОЛЬЗОВАТЕЛЬСКОГО ИНТЕРФЕЙСА -------------------------------

; #FUNCTION# ====================================================================================================
; Name...........:	CreateGUI
; Description....:	Создание главного окна программы.
; Syntax.........:	CreateGUI()
; ===============================================================================================================
Func CreateGUI()
 LoadConfigFile()
 If StringLower(StringRight(@ScriptFullPath, 4)) == ".exe" Then $sExeFileName = @ScriptFullPath
 $GUI_WindowMain = GUICreate($WindowName, $WindowWidth, $WindowHeight, $WindowPosX, $WindowPosY, _
                            BitOR($WS_BORDER, $WS_CAPTION, $WS_SYSMENU, $WS_SIZEBOX))
 WinMove($GUI_WindowMain, "", $WindowPosX, $WindowPosY, $WindowWidth, $WindowHeight)
 GUISetOnEvent($GUI_EVENT_CLOSE, "OnExit")
 GUISetOnEvent($GUI_EVENT_RESIZED, "OnResize")
 Local $GUI_MenuItem = GUICtrlCreateMenu("Файл")
 GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Обновить", $GUI_MenuItem), "_LoadSMARTData")
 GUICtrlSetOnEvent(GUICtrlCreateMenuItem("Выход", $GUI_MenuItem), "OnExit")
 Local $GUI_MenuItem = GUICtrlCreateMenu("Справка")
 GUICtrlSetOnEvent(GUICtrlCreateMenuItem("О программе", $GUI_MenuItem), "OnAbout")
 $GUI_TabMain = GUICtrlCreateTab(5, 5, $WindowWidth - 7, $WindowHeight - 30)
 GUICtrlSetResizing($GUI_TabMain, BitOR($GUI_DOCKTOP, $GUI_DOCKBOTTOM, $GUI_DOCKLEFT, $GUI_DOCKRIGHT))
 GUICtrlSetBkColor($GUI_TabMain, 0xFFFFFF)
 GUICtrlSetState($GUI_TabMain, $GUI_HIDE)
 $GUI_LabelMain = GUICtrlCreateLabel("", 20, $InfoHeight + 35, $WindowWidth - 40, 30, $SS_CENTER)
 GUICtrlSetResizing($GUI_LabelMain, BitOR($GUI_DOCKTOP, $GUI_DOCKHEIGHT))
 GUICtrlSetFont($GUI_LabelMain, 16, 0)
 GUISetState()
 HotKeySet("{ESC}", "OnExit")
 _LoadSMARTData()
 Do
  Sleep(100)
 Until False
EndFunc ;==>CreateGUI

; #FUNCTION# ====================================================================================================
; Name...........:	SaveConfigFile
; Description....:	Сохранение настроек программы в файл конфигурации.
; Syntax.........:	SaveConfigFile()
; ===============================================================================================================
Func SaveConfigFile()
 Local $Size = WinGetPos("[TITLE:" & $WindowName & "]")
 IniWrite($sIniFileName, "SMART", "Pos_X",	$Size[0])
 IniWrite($sIniFileName, "SMART", "Pos_Y",	$Size[1])
 IniWrite($sIniFileName, "SMART", "Size_X",	$Size[2])
 IniWrite($sIniFileName, "SMART", "Size_Y",	$Size[3])
EndFunc ;==>SaveConfigFile

; #FUNCTION# ====================================================================================================
; Name...........:	LoadConfigFile
; Description....:	Загрузка настроек программы из файла конфигурации.
; Syntax.........:	LoadConfigFile()
; ===============================================================================================================
Func LoadConfigFile()
 $WindowPosX	= IniRead($sIniFileName, "SMART", "Pos_X",	$WindowPosX)
 $WindowPosY	= IniRead($sIniFileName, "SMART", "Pos_Y",	$WindowPosY)
 $WindowWidth	= IniRead($sIniFileName, "SMART", "Size_X",	$WindowWidth)
 $WindowHeight	= IniRead($sIniFileName, "SMART", "Size_Y",	$WindowHeight)
EndFunc ;==>LoadConfigFile

; #FUNCTION# ====================================================================================================
; Name...........:	OnResize
; Description....:	Изменение размеров окна программы.
; Syntax.........:	OnResize()
; ===============================================================================================================
Func OnResize()
 Local $size = WinGetPos($GUI_WindowMain)
 If $size[2] < $WindowWidthMin	Then $size[2] = $WindowWidthMin
 If $size[3] < $WindowHeightMin	Then $size[3] = $WindowHeightMin
 WinMove($GUI_WindowMain, "", $size[0], $size[1], $size[2], $size[3])
 $size = WinGetClientSize("[TITLE:" & $WindowName & "]")
 For $i = 0 To UBound($GUI_ListView) - 1
  _GUICtrlListView_SetColumnWidth($GUI_ListView[$i], 2, $size[0] - 443)
 Next
EndFunc ;==>OnResize

; #FUNCTION# ====================================================================================================
; Name...........:	OnExit
; Description....:	Выход из программы или прерывание загрузки файла.
; Syntax.........:	OnExit()
; ===============================================================================================================
Func OnExit()
 SaveConfigFile()
 GUIDelete()
 Exit
EndFunc ;==>OnExit

#EndRegion GUI

#Region Help
;-------------------------------------------- ФУНКЦИИ РАБОТЫ С ОКНОМ СПРАВКИ ------------------------------------

; #FUNCTION# ====================================================================================================
; Name...........:	OnAbout
; Description....:  Создание окна "О программе".
; Syntax.........:	OnAbout()
; ===============================================================================================================
Func OnAbout()
 Local $s = "[TITLE:" & $WindowAboutName & "]"
 Local $QRSizeX = 100
 Local $QRSizeY = 100
 If WinExists($s) Then Return WinActivate($s)
 $s = WinGetPos("[TITLE:" & $WindowName & "]")
 Local $x = $s[0] + ($WindowWidth - $WindowAboutWidth) / 2
 Local $y = $s[1] + ($WindowHeight - $WindowAboutHeight) / 2
 $GUI_WindowHelp = GUICreate($WindowAboutName, $WindowAboutWidth, $WindowAboutHeight, $x, $y, _
                    BitOR($WS_BORDER, $WS_CLIPSIBLINGS, $DS_SETFOREGROUND, $WS_CAPTION, $DS_MODALFRAME))
 GUICtrlCreateLabel("Программа " & $WindowName, 10, _Set($y, 30), $WindowAboutWidth - 20, 20, $SS_CENTER)
 GUICtrlCreateLabel("Версия " & $AppVersion & ".", 10, _Inc($y, 20), $WindowAboutWidth - 20, 20, $SS_CENTER)
 GUICtrlCreateLabel("Программа для просмотра состояния жестких дисков с использованием технологии S.M.A.R.T.", _
                    10, _Inc($y, 20), $WindowAboutWidth - 20, 50, $SS_CENTER)
 GUICtrlCreateLabel("(Self Monitoring Analysing and Reporting Technology).", _
                    10, _Inc($y, 40), $WindowAboutWidth - 20, 50, $SS_CENTER)
 GUICtrlCreateLabel("Описание, обсуждение и исходный код программы на форуме русского сообщества AutoIt:", _
                    10, _Inc($y, 40), $WindowAboutWidth - 20, 40, $SS_CENTER)
 GUICtrlCreateLabel("http://autoit-script.ru", 10, _Inc($y, 40), $WindowAboutWidth - 20, 20, $SS_CENTER)
 GUICtrlSetColor(-1, 0x0000ff)
 GUICtrlSetOnEvent(-1, "OnAboutOpenForum")
 GUICtrlCreateIcon($sExeFileName, $imgQR, ($WindowAboutWidth - $QRSizeX) / 2, _Inc($y, 20), $QRSizeX, $QRSizeY)
 GUICtrlSetOnEvent(-1, "OnAboutOpenForum")
 GUICtrlSetOnEvent(GUICtrlCreateButton("Закрыть", $WindowAboutWidth / 2 - 70, _
                   $WindowAboutHeight - 40, 140, 30), "OnAboutExit")
 GUISetState()
 HotKeySet("{ESC}", "OnAboutExit")
EndFunc ;==>OnHelp

; #FUNCTION# ====================================================================================================
; Name...........:	OnAboutOpenForum
; Description....:  Открытие в браузере страницы обсуждения программы на форуме autoit-script.ru.
; Syntax.........:	OnAboutOpenForum()
; ===============================================================================================================
Func OnAboutOpenForum()
 OnAboutExit()
 ShellExecute("explorer", "http://link.ac/3Plw38")
EndFunc ;==>OnAboutOpenForum

; #FUNCTION# ====================================================================================================
; Name...........:	OnAboutExit
; Description....:  Закрытие окна "О программе".
; Syntax.........:	OnAboutExit()
; ===============================================================================================================
Func OnAboutExit()
 GUIDelete($GUI_WindowAbout)
 HotKeySet("{ESC}")
EndFunc ;==>OnAboutExit

#EndRegion Help

#Region HDD functions
;------------------------------------------- ФУНКЦИИ РАБОТЫ С ЖЕСТКИМИ ДИСКАМИ ----------------------------------

; #FUNCTION# ====================================================================================================
; Name...........:	_LoadSMARTData
; Description....:	Чтение данных S.M.A.R.T и заполнение таблиц в окне программы.
; Syntax.........:	_LoadSMARTData()
; ===============================================================================================================
Func _LoadSMARTData()
 Local $objItem, $i, $j, $n
 If $GUI_Icons <> - 1 Then
  GUICtrlDelete($GUI_Icons)
  For $i = 0 To UBound($GUI_ListView) - 1
   GUICtrlDelete($GUI_ListView[$i])
   GUICtrlDelete($GUI_TabItem[$i])
  Next
 EndIf
 GUICtrlSetState($GUI_TabMain, $GUI_HIDE)
 GUICtrlSetData($GUI_LabelMain, "Сбор информации о дисках...")
 GUICtrlSetState($GUI_LabelMain, $GUI_SHOW)
 $objService = ObjGet("winmgmts:\\" & @ComputerName & "\root\WMI")
 $objItems = $objService.ExecQuery("SELECT * FROM MSStorageDriver_ATAPISmartData", "WQL", 0x30)
 If IsObj($objItems) Then
  Dim $DiskID[1]; массив идентификаторов физических дисков (привязан к индексам вкладок)
  Dim $aLogicalDisk[1][1]
  _LoadLogicalDiskInfo($aLogicalDisk)
  Local $size = WinGetClientSize("[TITLE:" & $WindowName & "]")
  $GUI_Icons = _GUIImageList_Create(16, 16, 5, 3)
  _GUIImageList_AddIcon($GUI_Icons, $sExeFileName, $iconOK)
  _GUIImageList_AddIcon($GUI_Icons, $sExeFileName, $iconWarning)
  _GUIImageList_AddIcon($GUI_Icons, $sExeFileName, $iconError)
  Local $disk = 0; счетчик дисков
  For $objItem In $objItems
   ReDim $DiskID[$disk + 1]
   ReDim $GUI_TabItem[$disk + 1]
   ReDim $GUI_ListView[$disk + 1]
   $DiskID[$disk] = $objItem.InstanceName
   $GUI_TabItem[$disk] = GUICtrlCreateTabItem("Диск " & $disk)
   $GUI_ListView[$disk] = GUICtrlCreateListView("", 10, $InfoHeight + 33, $size[0] - 20, $size[1] - $InfoHeight - 45)
   GUICtrlSetResizing(-1, BitOR($GUI_DOCKTOP, $GUI_DOCKBOTTOM, $GUI_DOCKLEFT, $GUI_DOCKRIGHT))
   _GUICtrlListView_SetImageList($GUI_ListView[$disk], $GUI_Icons, 1)
   _GUICtrlListView_AddColumn(-1, "", 25, 2)
   _GUICtrlListView_AddColumn(-1, "ID", 35, 2)
   _GUICtrlListView_AddColumn(-1, "Описание", $size[0] - 443, 0)
   _GUICtrlListView_AddColumn(-1, "Значение", 80, 2)
   _GUICtrlListView_AddColumn(-1, "Порог", 80, 2)
   _GUICtrlListView_AddColumn(-1, "Худшее", 80, 2)
   _GUICtrlListView_AddColumn(-1, "Всего", 100, 1)
   Local $line = 0;  стетчик строк в отображаемом списке
   Local $sVendorSpecific = $objItem.VendorSpecific
   Local $sTemp = ""
   For $i = 2 to UBound($sVendorSpecific) - 1 Step 12
    If $sVendorSpecific[$i] == 0 then ContinueLoop
    Local $raw = ((((($sVendorSpecific[$i + 8] * 256 ) + $sVendorSpecific[$i + 7]) * 256) + _
     $sVendorSpecific[$i + 6]) * 256) + $sVendorSpecific[$i + 5]
    _GUICtrlListView_AddItem(-1, "", 0)
    _GUICtrlListView_AddSubItem(-1, $line,  $sVendorSpecific[$i], 1)
    _GUICtrlListView_AddSubItem(-1, $line,  _StringSMARTCodeTxt($sVendorSpecific[$i]), 2)
    _GUICtrlListView_AddSubItem(-1, $line,  _StringIntSpace($sVendorSpecific[$i + 3]), 3)
    _GUICtrlListView_AddSubItem(-1, $line,  _StringIntSpace($sVendorSpecific[$i + 4]), 5)
    _GUICtrlListView_AddSubItem(-1, $line,  _StringIntSpace($raw), 6)
	If $sVendorSpecific[$i] = 194 Then $sTemp = _Min($sVendorSpecific[$i + 3], $raw)
    $line = $line + 1
   Next
   Local $sDrives = "", $sModel = "", $sSerial = "", $sSize = ""
   For $i = 1 To $aLogicalDisk[0][0]
	Local $s = StringUpper(StringLeft($DiskID[$disk], StringLen($aLogicalDisk[$i][2])))
    If $aLogicalDisk[$i][2] == "" Or $s == "" Then ContinueLoop
    If $s <> StringUpper($aLogicalDisk[$i][2]) Then ContinueLoop
    $sDrives = $sDrives & $aLogicalDisk[$i][0] & ", "
 	$sModel = $aLogicalDisk[$i][3]
	$sSerial = $aLogicalDisk[$i][4]
    $sSize = _FormatInfoSize($aLogicalDisk[$i][5])
   Next
   GUICtrlCreateIcon($sExeFileName, $iconBigHDD, 20, 40, 128, 128)
   GUICtrlSetResizing(-1, BitOR($GUI_DOCKTOP, $GUI_DOCKLEFT, $GUI_DOCKWIDTH, $GUI_DOCKHEIGHT))
   GUICtrlCreateLabel("Модель: " & $sModel,  170, _Set($j, 35), 250, 16)
   GUICtrlSetResizing(-1, BitOR($GUI_DOCKTOP, $GUI_DOCKLEFT, $GUI_DOCKWIDTH, $GUI_DOCKHEIGHT))
   GUICtrlCreateLabel("Серийный номер: " & $sSerial,  170, _Inc($j, 18), $size[0] - 180, 16)
   GUICtrlSetResizing(-1, BitOR($GUI_DOCKTOP, $GUI_DOCKLEFT, $GUI_DOCKWIDTH, $GUI_DOCKHEIGHT))
   GUICtrlCreateLabel("Емкость диска: " & $sSize,  170, _Inc($j, 18), 250, 16)
   GUICtrlSetResizing(-1, BitOR($GUI_DOCKTOP, $GUI_DOCKLEFT, $GUI_DOCKWIDTH, $GUI_DOCKHEIGHT))
   GUICtrlCreateLabel("Температура: " & $sTemp & "°C",  170, _Inc($j, 18), 250, 16)
   GUICtrlSetResizing(-1, BitOR($GUI_DOCKTOP, $GUI_DOCKLEFT, $GUI_DOCKWIDTH, $GUI_DOCKHEIGHT))
   GUICtrlCreateLabel("Содержит логические диски: " & StringTrimRight($sDrives, 2), 170, _Inc($j, 18), 250, 16)
   GUICtrlSetResizing(-1, BitOR($GUI_DOCKTOP, $GUI_DOCKLEFT, $GUI_DOCKWIDTH, $GUI_DOCKHEIGHT))
   $disk = $disk + 1
  Next
  $objItems = $objService.ExecQuery("SELECT * FROM MSStorageDriver_FailurePredictThresholds", "WQL", 0x30)
  If IsObj($objItems) Then; чтение пороговых значений
   For $objItem In $objItems
	Local $sInstanceName = $objItem.InstanceName
    Local $sVendorSpecific = $objItem.VendorSpecific
    For $i = 2 to UBound($sVendorSpecific) - 1 Step 12
     For $j = 0 To UBound($DiskID) - 1
      If $sInstanceName <> $DiskID[$j] Then ContinueLoop
      For $n = 0 To _GUICtrlListView_GetItemCount($GUI_ListView[$j]) - 1
	   Local $ItemData = _GUICtrlListView_GetItemTextArray($GUI_ListView[$j], $n)
	   If $sVendorSpecific[$i] <> $ItemData[2] Then ContinueLoop
	   $ItemData[5] = $sVendorSpecific[$i + 1]
       _GUICtrlListView_AddSubItem($GUI_ListView[$j], $n,  _StringIntSpace($ItemData[5]), 4)
	   _GUICtrlListView_SetItemImage($GUI_ListView[$j], $n, _CheckSMARTError($ItemData))
	   ExitLoop
      Next
     Next
    Next
   Next
  EndIf
  If $GUI_TabItem[0] <> -1 Then GUICtrlSetState($GUI_TabItem[0], $GUI_SHOW)
  GUICtrlSetData($GUI_LabelMain, "")
 Else
 EndIf
 If _GUICtrlTab_GetItemCount($GUI_TabMain) > 0 Then
  GUICtrlSetState($GUI_LabelMain, $GUI_HIDE)
  GUICtrlSetState($GUI_TabMain, $GUI_SHOW)
 Else
  GUICtrlSetData($GUI_LabelMain, "Не удалось получить информацию о дисках.")
 EndIf
EndFunc ;==>_LoadSMARTData

; #FUNCTION# ====================================================================================================
; Name...........:	_LoadLogicalDiskInfo
; Description....:	Получение информации о логических дисках.
; Syntax.........:	_LoadLogicalDiskInfo($aLogicalDisk)
; Parameter(s)...:	$aLogicalDisk	- Массив, который будет преобразован и заполнен информацией.
; Return value(s):	On Success - Возвращает массив, содержащий:
;						$aLogicalDisk[0][0]  = Общее количество логических дисков
;						$aLogicalDisk[$i][0] = Обозначение (буква) диска
;						$aLogicalDisk[$i][1] = Индекс жесткого диска (0 = 1й жесткий диск)
;						$aLogicalDisk[$i][2] = PNP идентификатор устройства
;						$aLogicalDisk[$i][3] = Модель жесткого диска
;						$aLogicalDisk[$i][4] = Серийный номер жесткого диска
;						$aLogicalDisk[$i][5] = Размер жесткого диска (в байтах)
; ===============================================================================================================
Func _LoadLogicalDiskInfo(ByRef $aLogicalDisk)
 ReDim $aLogicalDisk[1][1]
 $aLogicalDisk[0][0] = 0
 Local $objService = ObjGet("winmgmts:\\" & @ComputerName & "\root\CIMV2")
 Local $objItems = $objService.ExecQuery("SELECT * FROM Win32_LogicalDiskToPartition", "WQL", 0x30)
 If Not IsObj($objItems) Then Return
 For $objItem In $objItems
  $aLogicalDisk[0][0] = $aLogicalDisk[0][0] + 1
  ReDim $aLogicalDisk[$aLogicalDisk[0][0] + 1][6]
  $aLogicalDisk[$aLogicalDisk[0][0]][0] = _StringGetParam($objItem.Dependent)
  $aLogicalDisk[$aLogicalDisk[0][0]][1] = -1
  $aLogicalDisk[$aLogicalDisk[0][0]][2] = _StringGetParam($objItem.Antecedent)
  $aLogicalDisk[$aLogicalDisk[0][0]][3] = ""
  $aLogicalDisk[$aLogicalDisk[0][0]][5] = ""
  $aLogicalDisk[$aLogicalDisk[0][0]][4] = -1
 Next
 Local $objItems = $objService.ExecQuery("SELECT * FROM Win32_DiskPartition", "WQL", 0x30)
 If Not IsObj($objItems) Then Return
 For $objItem In $objItems
  Local $sDeviceID = $objItem.DeviceID
  For $i = 1 To $aLogicalDisk[0][0]
   If $sDeviceID <> $aLogicalDisk[$i][2] Then ContinueLoop
   $aLogicalDisk[$i][1] = $objItem.DiskIndex
   ExitLoop
  Next
 Next
 Local $objItems = $objService.ExecQuery("SELECT * FROM Win32_DiskDrive", "WQL", 0x30)
 If Not IsObj($objItems) Then Return
 For $objItem In $objItems
  Local $Index = $objItem.Index
  For $i = 1 To $aLogicalDisk[0][0]
   If $Index <> $aLogicalDisk[$i][1] Then ContinueLoop
   $aLogicalDisk[$i][2] = $objItem.PNPDeviceID
   $aLogicalDisk[$i][3] = $objItem.Model
   $aLogicalDisk[$i][4] = StringReplace($objItem.SerialNumber, " " , "")
   $aLogicalDisk[$i][5] = $objItem.Size
  Next
 Next
EndFunc ;==>_LoadLogicalDiskInfo

; #FUNCTION# ====================================================================================================
; Name...........:	_CheckSMARTError
; Description....:	Проверка значений элемента таблицы S.M.A.R.T. жесткого диска.
; Syntax.........:	_CheckSMARTError($aSMARTItem)
; Parameter(s)...:	$aSMARTItem	- Массив, содержащий элемент таблицы S.M.A.R.T. жесткого диска в формате:
;								$aSMARTItem[0] = число элементов в массиве;
;								$aSMARTItem[1] = не используется;
;								$aSMARTItem[2] = код атрибута;
;								$aSMARTItem[3] = краткое описание атрибута;
;								$aSMARTItem[4] = текущее значение атрибута;
;								$aSMARTItem[5] = пороговое значение атрибута;
;								$aSMARTItem[6] = значение Worst атрибута;
;								$aSMARTItem[7] = значение RAW атрибута.
; Return value(s): Success      - Одно из следующих значений:
;								0 = ошибок не обнаружено;
;								1 = предупреждение;
;								2 = обнаружена критическая ошибка.
;				   Failure		- Устанавливает @error = 1 и возвращает -1.
; ===============================================================================================================
Func _CheckSMARTError($aSMARTItem)
If $aSMARTItem[0] < 7 Then Return SetError(1, 0, -1)
 Switch $aSMARTItem[2]
  Case 5; были переназначены "битые" сектора
   If $aSMARTItem[7] > 0 Then Return 1
  Case 11; были перекалибровки
   If $aSMARTItem[7] > 0 Then Return 1
  Case 184; ошибки передачи данных через кэш
   If $aSMARTItem[7] > 0 Then Return 1
  Case 194; температура диска
   If _Min($aSMARTItem[4], $aSMARTItem[7]) > 45 Then Return 1
  Case 196; число переназначений секторов
   If $aSMARTItem[7] > 0 Then Return 1
  Case 197; число нестабильных секторов
   If $aSMARTItem[7] > 0 Then Return 1
  Case 198; число некорректируемых секторов
   If $aSMARTItem[7] > 0 Then Return 1
  Case Else
   If $aSMARTItem[5] <> 0 And $aSMARTItem[4] <= $aSMARTItem[5] Then Return 2
   Return 0
 EndSwitch
EndFunc ;==>_CheckSMARTError

#EndRegion HDD functions

#Region Additional functions
;------------------------------------------------ ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ---------------------------------------

; #FUNCTION# ====================================================================================================
; Name...........:	_StringGetParam
; Description....:	Получение значения, заключенного в кавычках (").
; Syntax.........:	_StringGetParam($sString)
; Parameter(s)...:	$sString	- Исходная строка.
; Return value(s):	Строка, содержащаяся в камычках в конце исходной строки.
; ===============================================================================================================
Func _StringGetParam($sString)
 Local $iPosition = StringInStr(StringTrimRight($sString, 1), '"', 0, -1)
 If $iPosition <= 0 Then Return ""
 Return StringTrimLeft(StringTrimRight($sString, 1), $iPosition)
EndFunc ;==>_StringGetParam

; #FUNCTION# ====================================================================================================
; Name...........:	_StringIntSpace
; Description....:	Форматирование десятичного числа.
; Syntax.........:	_StringIntSpace($sInt)
; Parameter(s)...:	$sInt		- Число, которое необходимо отформатировать.
; Return value(s):	Число, в котором тысячи, миллионы, миллиарды и триллионы отделены пробелами.
; ===============================================================================================================
Func _StringIntSpace($sInt)
 Local $s = Round($sInt)
 If StringLen($s) > 12 Then $s = StringTrimRight($s, 12) & " " & StringRight($s, 12)
 If StringLen($s) > 9 Then $s = StringTrimRight($s, 9) & " " & StringRight($s, 9)
 If StringLen($s) > 6 Then $s = StringTrimRight($s, 6) & " " & StringRight($s, 6)
 If StringLen($s) > 3 Then $s = StringTrimRight($s, 3) & " " & StringRight($s, 3)
 Return $s
EndFunc ;==>_StringIntSpace

; #FUNCTION# ====================================================================================================
; Name...........:	_FormatInfoSize
; Description ...:	Преобразование числа в килобайты, мегабайты, гигабайты или терабайты.
; Syntax.........:	_FormatInfoSize($Data)
; Parameter(s)...:	$Data		- Число, которое необходимо преобразовать.
; Return value(s):	Success		- Строка, содержащая эквивалент числа с единицами измерения.
; ===============================================================================================================
Func _FormatInfoSize($Data)
 Local $n = 1099511627776
 If $Data > $n Then Return Floor(10 * $Data / $n) / 10 & " ТБ"
 $n = 1073741824
 If $Data > 1073741824 Then Return Floor(10 * $Data / $n) / 10 & " ГБ"
 $n = 1048576
 If $Data > $n Then Return Floor(10 * $Data / $n) / 10 & " МБ"
 $n = 1024
 If $Data > $n Then Return Floor(10 * $Data / $n) / 10 & " КБ"
 Return $Data & " Б"
EndFunc ;==>_FormatInfoSize

; #FUNCTION# ====================================================================================================
; Name...........:	_StringSMARTCodeTxt
; Description....:	Получение описания записи в таблице S.M.A.R.T. по её коду.
; Syntax.........:	_StringSMARTCodeTxt($iCode)
; Parameter(s)...:	$iCode		- Код записи.
; Return value(s):	Текстовая строка, содержащая описание записи, соответствующего коду.
; ===============================================================================================================
Func _StringSMARTCodeTxt($iCode)
 Local $i, $sResult = "Параметр определяется производителем"
 Local $aCode = _StringExplode($sSMARTCodeTxt, ";")
 For $i = 0 To UBound($aCode) - 1
  Local $aData = _StringExplode($aCode[$i], ",")
  If $aData[0] <> $iCode Then ContinueLoop
  $sResult = $aData[1]
  ExitLoop
 Next
 Return $sResult
EndFunc ;==>_StringSMARTCodeTxt

; #FUNCTION# ====================================================================================================
; Name...........:	_Set
; Description....:	Присвоение значение переменной.
; Syntax.........:	_Set($Var[, $Add])
; Parameter(s)...:	$Var		- Переменная.
;					$Add		- Присваиваемое значение.
; Return value(s):	Значение переменной поле присвоения нового значения.
; ===============================================================================================================
Func _Set(ByRef $Var, $Data = 0)
 $Var = $Data
 Return $Var
EndFunc ;==>_Set

; #FUNCTION# ====================================================================================================
; Name...........:	_Inc
; Description....:	Инкремент числа.
; Syntax.........:	_Inc($Var[, $Add])
; Parameter(s)...:	$Var		- Переменная, которую необходимо увеличить (аргумент).
;					$Add		- Величина, на которое необходимо увеличить число.
; Return value(s):	Значение переменной поле инкремента.
; ===============================================================================================================
Func _Inc(ByRef $Var, $Add = 1)
 $Var = $Var + $Add
 Return $Var
EndFunc ;==>_Inc

#EndRegion Additional functions

Файлы:
Исполняемый файл: SMART_Info.exe
Исходник с картинками: SMART_Info.zip

Снимок:


История версий:
Версия 0.1.1 (16.09.2014) - Внесены следующие изменения:
- исправлен алгоритм определения температуры блока магнитных дисков;
- добавлено окно "О программе";
- добавлены некоторые шасшифровки кодов данных S.M.A.R.T.

Версия 0.1.0 (12.09.2014) - Впервые обнародованная версия программы.
- чтение данных S.M.A.R.T. и предоставление из в виде таблицы;
- для каждого физического диска в окне программы организована отдельная вкладка;
- реализована простая функция оценки работоспособности дисков (требует совершенствования);
- сопоставление физических и логических дисков;
- вывод краткой информации о каждом их физических дисков.

Источник: autoit-script.ru
Автор: Aleksandr Prilutskiy

Руководство пользователя
1. Запустить программу.
2. Смотреть что получилось.

Примечание: Если программа выдает сообщение "Не удалось получить информацию о дисках.":
1. Запустите программу с правами администратора (не могу понять почему, но иногда, это требуется, хотя часто программа работает и без прав администратора);
2. Проверьте, не отключена ли поддержка S.M.A.R.T. в BIOS-е (мало вероятно, но может быть что Ваш BIOS отключает S.M.A.R.T.);
3. По идее может быть, что сам диск не поддерживает S.M.A.R.T., но это еще менее вероятно.

История разработки и использованные ресурсы
Как и в прошлой моей программке, размещенной на этом форуме (Программа удаленного управления загрузками µTorrent ), идея написания программы связана с другим проектом. Я делаю Web-интерфейс для управления домашним сервером (NAS) под Windows. И решил, что было бы полезно видеть удаленно состояние S.M.A.R.T. дисков на сервере.
Пришлось разбираться с технологией S.M.A.R.T. Получилась, собственно эта вот программка.
Обычно для контроля S.M.A.R.T. я использовал программу S.M.A.R.T. Vision, но в последнее время у меня с ней стали часто возникать проблемы. По непонятной причине после перезагрузки компьютера она отказывается запускаться, выдавая массу окон с сообщениями об ошибках. Но при нескольких перезагрузках эта проблема самоустраняется. Конечно, это доставляет неудобства.
Кроме того, "своё" всегда лучше. :smile:
Аналогичных программ много. Но, критерии оценки работоспособности дисков у всех разные. Собственная программа даёт возможность самостоятельно добавлять и совершенствовать методы диагностики жестких дисков используя S.M.A.R.T.

Планы на будущее:
- Совершенствовать критерии оценки работоспособности дисков.
- Добавить сохранение и чтение предыдущих значений для отслеживания изменений параметров S.M.A.R.T.
- Добавить возможность просмотра подробной информации о дисках.
- Добавить справку по S.M.A.R.T..
 

InnI

AutoIT Гуру
Сообщения
4 402
Репутация
1 192
Опечатка в заголовке: "Значание"

На скриншоте температура 104 градуса: этому можно (нужно) верить?

С правами администратора действительно странность: несколько запусков без прав не смогли получить информацию. Один запуск с правами администратора - и все последующие запуски без прав читают информацию. До перезагрузки или до прошествия примерно минут пятнадцати. После перезагрузки (или после минут 15-ти) нужно опять один раз запустить с правами администратора, чтобы далее получать информацию "без прав" до очередной перезагрузки или до ожидания минут 15-ти (Win7, UAC включён). Кэшируется она, что-ли?
 

oesoes

xor eax,eax
Сообщения
171
Репутация
9
Информацию получаете через WMI или как-то иначе?
 

oesoes

xor eax,eax
Сообщения
171
Репутация
9
В архиве - исходник ;)
Да, увидел ) Сначала провтыкал его. Сначала просто код под спойлером смотрел как даун в маленьком окошке ) А там сорец, та ещё и с картинками ) А то я же не люблю, когда без картинок ) это у меня с детства )
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
OffTopic:
отступ в один пробел - экзотичненько ;D
 

joiner

Модератор
Локальный модератор
Сообщения
3 254
Репутация
552
Aleksandr Prilutskiy [?]
Аналогичных программ много. Но, критерии оценки работоспособности дисков у всех разные.
вот поэтому не доверяю по поводу смарта. если биос поддерживает такую функцию, то лучше в нем включить смарт. для меня, к примеру, как для "лечащего" компы нужна программа исправляющая битые сектора, способная перезаписать загрузчик, ну и прочее. а инфа о том, что мой диск якобы уже никакой весьма сомнительна. у меня один такой диск уже почти десять лет живет и дышит..
ну а вобщем. молодец. ну хотя бы за старание :smile:
 
Автор
Aleksandr Prilutskiy

Aleksandr Prilutskiy

Знающий
Сообщения
29
Репутация
9
Kaster сказал(а):
OffTopic:
отступ в один пробел - экзотичненько ;D
сорри, олдскул, бро...

имею идиотскую привычку распечатывать код на принтере и читать его когда есть лишнее время.
 

oesoes

xor eax,eax
Сообщения
171
Репутация
9
Aleksandr Prilutskiy [?]
имею идиотскую привычку распечатывать код на принтере и читать его когда есть лишнее время
Мой отец так делает (приучил и меня). Тебе наверное лет эдак под 50? "Не порть глаза", говорил он, "читай с листа", говорил он. Ничего "идиотского" тут нет.
 

Garrett

Модератор
Локальный модератор
Сообщения
3 999
Репутация
964
OffTopic:
Уважаемые форумчане, давайте по существу!
Не стоит флудить, для этого есть раздел Общение
 
Автор
Aleksandr Prilutskiy

Aleksandr Prilutskiy

Знающий
Сообщения
29
Репутация
9
InnI сказал(а):
На скриншоте температура 104 градуса: этому можно (нужно) верить?
Сам терзаюсь в догадках. На работе есть куча разных БУ винтов. Многие показывают температуру более 100 градусов.
Думаю это правда. Они достаточно горячие, а температура что показывает параметр 194 - это температура блока дисков. Снаружи винт горячий. Градусов 60-70 примерно, так что внутри более 100 это вполне может быть.
Другие параметры температуры (согласно Интернету) могут показывать не температуру, а что угодно в зависимости от производителя: разницу с другими датчиками температур, что то минус температура и т.д., но 194 по всем описаниям что я встречал показывает температуру по цельсию.
А вот насколько это нормально - не знаю. Как раз пытаюсь найти информацию по этому поводу. Буду признателен, если кто нибудь поделится в теме своим опытом.

На скриншоте я специально привел результат теста самого "убитого винта" что у меня есть под рукой. Естественно, я его не использую. Основной винт весь "зелененький". Температуру показывает 30 и максимум была зафиксирована 46 градусов.

InnI сказал(а):
Опечатка в заголовке: "Значание"
Спасибо. Исправил. Прогнал текст через Word. Нашел еще несколько ошибок - все в комментариях.
Как добавлю окно справки - выложу обновленную версию.
 

firex

AutoIT Гуру
Сообщения
943
Репутация
203
Aleksandr Prilutskiy [?]
но 194 по всем описаниям что я встречал показывает температуру по цельсию.А вот насколько это нормально - не знаю.
ИМХО С такой температурой вы в один момент уничтожите все сектора, на среднестатистических винтах такая температура невозможна.
 
Автор
Aleksandr Prilutskiy

Aleksandr Prilutskiy

Знающий
Сообщения
29
Репутация
9
firex сказал(а):
Aleksandr Prilutskiy [?]
но 194 по всем описаниям что я встречал показывает температуру по цельсию.А вот насколько это нормально - не знаю.
ИМХО С такой температурой вы в один момент уничтожите все сектора, на среднестатистических винтах такая температура невозможна.
Не уверен что эти умозаключения верны.
В зависимости от материала поверхности дисков его температура может быть 100 градусов и выше, без проблем. Я не уверен, но вполне это допускаю.
У меня дисков, которые греются выше 100 градусов достаточно много, и они вполне рабочие. Самое интересное, что на них SMART Vision не ругается, но ругается на один SSD диск, которые обычно греется до 55 градусов.
 

oesoes

xor eax,eax
Сообщения
171
Репутация
9
Нормальная температура хдд - 35–45°, так что 104 градуса - это конечно бред. Даже если проверить тактильно, сразу станет понятно, гонит смарт или нет.
 
Автор
Aleksandr Prilutskiy

Aleksandr Prilutskiy

Знающий
Сообщения
29
Репутация
9
oesoes сказал(а):
Нормальная температура хдд - 35–45°, так что 104 градуса - это конечно бред. Даже если проверить тактильно, сразу станет понятно, гонит смарт или нет.
Этот винт (скриншот которого я показал в качестве примера) научным методом пальпации диагностируется также (как очень горячий). Снаружи температура не 100 градусов, конечно, но палец больше чем пара секунд удержать не получается - очень горячо. Но у меня есть подозрение что это греется плата контроллера.. Какая температура шпинделя попробовать нет возможности.
SMART Vision тоже показывает сейчас на нем тоже 100 - 111 градусов в поле "значение", как и моя программка. Но почему то выводит как результат значение из поля RAW (около 45 градусов). У меня есть подозрение что значение температуры нужно брать или из RAW (у меня это поле подписано как "Всего") или вычислять минимальное значение между RAW и "текущим значением".
Только что провел эксперимент - поставил к этому винту вентилятор. Значение RAW уменьшилось, а "текущее значение" увеличилось.
Так что думаю, в RAW как раз таки правильное значение, а "текущее значение" значение считает разницу между температурой и критической температурой.
То есть, если температура увеличивается "текущее значение" уменьшается и когда достигает "порога" - считается что винт неисправный.
Но это мои догадки. Доказательства этому я пока не нашел.

Для установления истины и уточнения алгоритма вычисления температуры диска предлагаю сбрасывать сюда свои результаты, что показывает программка в поле "194 Температура диска" на разных жестких дисках.

У меня на домашнем сервере 3 винта Seagate, показывают:
№1: Значение=31 Порог=0 Худшее=51 Всего=31
№2: Значение=30 Порог=0 Худшее=51 Всего=30
№3: Значение=35 Порог=0 Худшее=47 Всего=35
и один SSD винт Kingstone
Значение=57 Порог=30 Худшее=57 Всего=2 752 555

на рабочей машине тоже Seagate:
Значение=33 Порог=0 Худшее=46 Всего=33
тестовый глюкавый винт (WD):
Значение=110 Порог=0 Худшее=90 Всего=37
 

oesoes

xor eax,eax
Сообщения
171
Репутация
9
что показывает программка в поле "194 Температура диска" на разных жестких дисках.
На моем WD5000AAKX вообще такого поля нет.

На ST1000DM003 - 34 | 0 | 46 | 34
 

InnI

AutoIT Гуру
Сообщения
4 402
Репутация
1 192
Модель: ST500DM002-1BD142 ATA Device
Температура: 43°C
v | 194 | Температура диска | 43 | 0 | 47 | 43

И ещё. У моего диска серийный номер какой-то длинный... не влезает в отведённое место и переносится на вторую строку (см. вложение)
 

Вложения

  • 7,8 КБ Просмотры: 29

oesoes

xor eax,eax
Сообщения
171
Репутация
9
InnI [?]
И ещё. У моего диска серийный номер какой-то длинный... не влезает в отведённое место и переносится на вторую строку (см. вложение)
Ну та же беда... На оба диска. в исходнике на 291 строке поправить на
Код:
GUICtrlCreateLabel("Серийный номер: " & $sSerial,  170, _Inc($j, 18))
 
Автор
Aleksandr Prilutskiy

Aleksandr Prilutskiy

Знающий
Сообщения
29
Репутация
9
oesoes сказал(а):
InnI [?]
И ещё. У моего диска серийный номер какой-то длинный... не влезает в отведённое место и переносится на вторую строку (см. вложение)
Ну та же беда... На оба диска. в исходнике на 291 строке поправить на
Код:
GUICtrlCreateLabel("Серийный номер: " & $sSerial,  170, _Inc($j, 18))
Спасибо за информацию. Сделаю поле для номера побольше. Вообще то я планировал рядом с номером и прочей информацией еще столбик какой нибудь добавить... Но подумаю как лучше сделать.
 
Верх