![>](style_images/1/nav_m.gif)
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.226.186.58] |
![]() |
|
Сообщ.
#1
,
|
|
|
Возможно ли это на BCB6? Примеры есть? В интернете с этим туго.
|
Сообщ.
#2
,
|
|
|
Единственный исходный код, который и был найден, и был переделан под билдер - ембаркадеровский последней версии. Был нерабочий и, как выяснилось, логически багнутый. Допилю за неделю - выложу здесь: до целого модуля разросся. Правда, только читать данные умеет.
|
Сообщ.
#3
,
|
|
|
Родился в итоге рабочий модуль для разных семейств дисков.
![]() ![]() /* Модуль тестировался на дисках: - Seagate: ST380215A, ST500DM002, ST3120213A, ST3320413AS, ST3320418AS, ST3250318AS, ST340014A; - Western Digital: WD5000AAKX, WD5000AADS; - Hitachi: HDT725032VLAT80; - Samsung: SP1203N, SV4012H. */ #include "SMART.h" //Для работы со S.M.A.R.T. #include "WinInet.h" //Для работы с сетевыми подключениями. //Индексы атрибута S.M.A.R.T. Hitachi искажает S.M.A.R.T.: смещение Value с 3 на RAW (+2), смещение WORST с 4 на 9. #define INDEX_ATTRIBUTE_INDEX 0 //Идентификатор атрибута. #define INDEX_ATTRIBUTE_STATUSFLAGS 1 //Тип атрибута. //Второго индекса, реально, нет. #define INDEX_ATTRIBUTE_VALUE 3 //Текущее значение атрибута. #define INDEX_ATTRIBUTE_WORST 4 //Наихудшее зафиксированное значение. Погоровое значение - лежит в byteThreshold[1]. Для Hitachi - смещение по Threshold неизвестно. #define INDEX_ATTRIBUTE_RAW 5 //Абсолютное значение. //Типы атрибута S.M.A.R.T. #define PRE_FAILURE_WARRANTY 0x1 //Критический (жизненно важный). #define ON_LINE_COLLECTION 0x2 //Коллекция реального времени. #define PERFORMANCE_ATTRIBUTE 0x4 //Отражает производительность диска. #define ERROR_RATE_ATTRIBUTE 0x8 //Отражает частоту появления ошибок. #define EVENT_COUNT_ATTRIBUTE 0x10 //Счетчик событий. #define SELF_PRESERVING_ATTRIBUTE 0x20 //Самосохраняющийся. //Ошибки драйвера накопителя. #define SMART_NO_ERROR 0 //No error #define SMART_IDE_ERROR 1 //Error from IDE controller #define SMART_INVALID_FLAG 2 //Invalid command flag #define SMART_INVALID_COMMAND 3 //Invalid command byte #define SMART_INVALID_BUFFER 4 //Bad buffer (null, invalid addr..) #define SMART_INVALID_DRIVE 5 //Drive number not valid #define SMART_INVALID_IOCTL 6 //Invalid IOCTL #define SMART_ERROR_NO_MEM 7 //Could not lock user's buffer #define SMART_INVALID_REGISTER 8 //Some IDE Register not valid #define SMART_NOT_SUPPORTED 9 //Invalid cmd flag set #define SMART_NO_IDE_DEVICE 10 //Cmd issued to device not present although drive number is valid. //Для получения информации о производителе накопителя. Возможно получение и типа. #define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) DWORD g_dwBytes_Returned = 0; //Заглушка для выполнения функций. char g_cErrorText_Title[2] = "32"; int g_iErrorText_Icons = 32; bool bSystem_Test(void) { int iDisk_Number = 0; //Номер накопителя. bool bNormal = true; //Флаг нормы теста. Лучше сразу сообщить обо всех ошибках, чтобы 100 раз не разбирать системник. //Сбор данных. AnsiString asDate = DateToStr(Date()); //Критический. Проверка работоспособности батареи BIOS как фактора записи корректной даты съема телеметрии, в т.ч. для печати протоколов. float fHDA_Temperature = fGet_SMART_Parameter(iDisk_Number, 194); //Температура железа накопителя. float fMechanical_Shock = fGet_SMART_Parameter(iDisk_Number, 191); //Счетчик механических ударов и внешних нагрузок. float fDisk_Shift = fGet_SMART_Parameter(iDisk_Number, 220); //Критический. Показатель смещения блока дисков относительно шпинделя. float fWrite_Error_Rate = fGet_SMART_Parameter(iDisk_Number, 200); //Количество сбойных секторов, вместо которых используется резервная область диска (программами проверки поверхности НЕ показываются. bool bLAN_Online = InternetGetConnectedState(&g_dwBytes_Returned, 0); //Флаг "хоть одно сетевое подключение подключено", т.е. передача данных возможна. //Параметры, отсутствующие в S.M.A.R.T. моего HDD WDC WD5000AAKX. float fAirflow_Temperature = fGet_SMART_Parameter(iDisk_Number, 190); float fHDD_Temperature = fGet_SMART_Parameter(iDisk_Number, 231); float fReallocated_Sectors_Count = fGet_SMART_Parameter(iDisk_Number, 5); if (asDate.SubString(asDate.Length()-3, 4).ToInt() < 2019) { Application->MessageBox("Дата установлена неправильно. Возможно, разряжена батарея BIOS на системной плате (как правило, CR2032). Программа завершает работу.", g_cErrorText_Title, g_iErrorText_Icons); bNormal = false; } if (fHDA_Temperature > 40) { Application->MessageBox(("Температура накопителя HDD №" + IntToStr(iDisk_Number) + " выше 40 градусов ("+ FloatToStr(fHDA_Temperature) + "). Почистите пылевые фильтры и вентиляторы ЭВМ, протрите накопитель от пыли и установите температуру помещения в соответствии с ТУ.").c_str(), g_cErrorText_Title, g_iErrorText_Icons); //bNormal = false; } if (fReallocated_Sectors_Count > 200) { Application->MessageBox(("Параметр Reallocated Sectors Count накопителя HDD №" + IntToStr(iDisk_Number) + " выше 200 ("+ FloatToStr(fReallocated_Sectors_Count) + "). Рекомендуется неспешный поиск нового носителя под замену.").c_str(), g_cErrorText_Title, g_iErrorText_Icons); //bNormal = false; } if (fMechanical_Shock > 0) { Application->MessageBox(("Параметр Mechanical Shock накопителя HDD №" + IntToStr(iDisk_Number) + " выше 0 ("+ FloatToStr(fMechanical_Shock) + "). Проверьте КПА на отсутствие вибраций, не допускайте ударов накопителя и КПА при эксплуатации и перевозке.").c_str(), g_cErrorText_Title, g_iErrorText_Icons); //bNormal = false; } if (fDisk_Shift > 0) { Application->MessageBox(("Параметр Disk Shift накопителя HDD №" + IntToStr(iDisk_Number) + " выше 0 ("+ FloatToStr(fDisk_Shift) + "). Это означает, что произошло смещение блока дисков относительно шпинделя. Немедленно обесточьте КПА и приобретите новый носитель с целью переноса информации. С данной ошибкой диск быстро становится неработоспособным.").c_str(), g_cErrorText_Title, g_iErrorText_Icons); bNormal = false; } if (bLAN_Online) { Application->MessageBox("Обнаружено сетевое подключение с состоянием \"подключено\". С активным сетевым подключением работа с КПА невозможна из-за вероятности ложноотрицательных результатов.", g_cErrorText_Title, g_iErrorText_Icons); bNormal = false; } return bNormal; } float fGet_SMART_Parameter(int iDisk_Number, int iParameter_Number) { //Возвращение текущего значения параметра; без порогового значения, т.к. на разных носителях они разные. //В случае отсутствия параметра в S.M.A.R.T. данная функция вернет -2147483648, а не -2147483647 (что за глюки в разрядах у Builder - не знаю). float fResult = -2147483647; bool bData_Getted = false; //Флаг успешного получения информации S.M.A.R.T. //Для получения производителя диска. char cQuery[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0}; char cResult[512] = {0}; //Буфер для получения данных от DeviceIoControl. AnsiString asManufacturer_Disk = ""; //Строка с названием диска и его производителя. bool bWestern_Digital = false; //WDC содержит текущую температуру в RAW, а не в VALUE, - но нет флага отличия WDC от других дисков. В итоге температура на WDC отличается на +2.5 градуса, что критично. bool bHitachi = false; //Hitachi имеет другую структуру S.M.A.R.T. по температуре и расширенный ее съем. bool bSeagate = false; //Для кучи. bool bSamsung = false; //Для кучи. //Открытие физического диска. AnsiString asDrive_Path = "\\\\.\\PhysicalDrive" + IntToStr(iDisk_Number); HANDLE hDrive_Physical = CreateFile(asDrive_Path.c_str(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); if (hDrive_Physical == INVALID_HANDLE_VALUE) { Application->MessageBox(("Не удалось открыть накопитель HDD №" + IntToStr(iDisk_Number) + " для получения его состояния. Проверьте наличие диска в системе и не занят ли он какой-либо программой (например, Victoria).").c_str(), g_cErrorText_Title, g_iErrorText_Icons); return -1; } //Определение производителя диска. bData_Getted = DeviceIoControl(hDrive_Physical, IOCTL_STORAGE_QUERY_PROPERTY, &cQuery, sizeof(cQuery), &cResult, sizeof(cResult), &g_dwBytes_Returned, NULL); if (!bData_Getted) Application->MessageBox(("Не удалось получить производителя накопителя №" + IntToStr(iDisk_Number) + ". Показания температуры в S.M.A.R.T. могут быть искажены.").c_str(), g_cErrorText_Title, g_iErrorText_Icons); else { for (unsigned int iTemp=0; iTemp<g_dwBytes_Returned; iTemp++) { if (cResult[iTemp] != 0) asManufacturer_Disk += cResult[iTemp]; //Исключение терминаторов. } if (asManufacturer_Disk.Pos("ST") != 0) bSeagate = true; //Лучше первым: вероятность наличия "ST" в других фирмах сохраняется. if (asManufacturer_Disk.Pos("WDC") != 0) bWestern_Digital = true; if (asManufacturer_Disk.Pos("HDT") != 0) bHitachi = true; if (asManufacturer_Disk.Pos("SP")!=0 || asManufacturer_Disk.Pos("SV")!=0) bSamsung = true; //ShowMessage(asManufacturer_Disk); } //Получение информации из S.M.A.R.T. //Структура, посылаемая для получения данных в DeviceIoControl. const int iParams_To_DeviceIoControl_Size_const = sizeof(SENDCMDINPARAMS) - 1; //Количество байт данных при выполнении DeviceIoControl. SENDCMDINPARAMS Params_To_DeviceIoControl = {0}; //Структура, посылаемая для получения данных в DeviceIoControl. Params_To_DeviceIoControl.cBufferSize = READ_ATTRIBUTE_BUFFER_SIZE; //Размер буфера для получения атрибутов. Params_To_DeviceIoControl.irDriveRegs.bFeaturesReg = READ_ATTRIBUTES; //Запрос на чтение атрибутов. Params_To_DeviceIoControl.irDriveRegs.bSectorCountReg = 1; //Регистр количества секторов. Params_To_DeviceIoControl.irDriveRegs.bSectorNumberReg = 1; //Регистр номера сектора. Params_To_DeviceIoControl.irDriveRegs.bCylLowReg = SMART_CYL_LOW; //Младший разряд указателя на № цилиндра. Params_To_DeviceIoControl.irDriveRegs.bCylHighReg = SMART_CYL_HI; //Старший разряд указателя на № цилиндра. Params_To_DeviceIoControl.irDriveRegs.bDriveHeadReg = 0xA0|((static_cast<BYTE>(iDisk_Number)&1)<<4); //Регистр диска/головки IDE. Params_To_DeviceIoControl.irDriveRegs.bCommandReg = SMART_CMD; //Команда IDE. const int iParams_From_DeviceIoControl_Size_const = sizeof(SENDCMDOUTPARAMS)-1 + READ_ATTRIBUTE_BUFFER_SIZE; //Количество байт данных при выполнении DeviceIoControl. SENDCMDOUTPARAMS Params_From_DeviceIoControl[iParams_From_DeviceIoControl_Size_const] = {0}; //Структура, принимающая данные из DeviceIoControl (данные). bData_Getted = DeviceIoControl(hDrive_Physical, SMART_RCV_DRIVE_DATA, &Params_To_DeviceIoControl, iParams_To_DeviceIoControl_Size_const, &Params_From_DeviceIoControl, iParams_From_DeviceIoControl_Size_const, &g_dwBytes_Returned, NULL ); if (!bData_Getted) { Application->MessageBox(("Не удалось получить текущие значения параметров S.M.A.R.T. накопителя HDD №" + IntToStr(iDisk_Number) + " для получения его состояния.").c_str(), g_cErrorText_Title, g_iErrorText_Icons); CloseHandle(hDrive_Physical); return -1; } //Получение ошибок драйвера или интерфейса. if (Params_From_DeviceIoControl->DriverStatus.bDriverError != 0) { Application->MessageBox(("Обнаружена ошибка драйвера накопителя HDD №" + IntToStr(iDisk_Number) + ". Данные S.M.A.R.T. могут быть искажены.").c_str(), g_cErrorText_Title, g_iErrorText_Icons); CloseHandle(hDrive_Physical); return -1; } if (Params_From_DeviceIoControl->DriverStatus.bIDEError != 0) { Application->MessageBox(("Обнаружена ошибка интерфейса IDE накопителя HDD №" + IntToStr(iDisk_Number) + ". Данные S.M.A.R.T. могут быть искажены.").c_str(), g_cErrorText_Title, g_iErrorText_Icons); CloseHandle(hDrive_Physical); return -1; } //Данные для получения пороговых значений параметров (подготовка). Params_To_DeviceIoControl.cBufferSize = READ_THRESHOLD_BUFFER_SIZE; Params_To_DeviceIoControl.irDriveRegs.bFeaturesReg = READ_THRESHOLDS; SENDCMDOUTPARAMS Thresholds_From_DeviceIoControl[iParams_From_DeviceIoControl_Size_const] = {0}; //Структура, принимающая данные из DeviceIoControl (пороговые значения). g_dwBytes_Returned = 0; bData_Getted = DeviceIoControl(hDrive_Physical, SMART_RCV_DRIVE_DATA, &Params_To_DeviceIoControl, iParams_To_DeviceIoControl_Size_const, &Thresholds_From_DeviceIoControl, iParams_From_DeviceIoControl_Size_const, &g_dwBytes_Returned, NULL ); if (!bData_Getted) { Application->MessageBox(("Не удалось получить пороговые значения параметров S.M.A.R.T. накопителя HDD №" + IntToStr(iDisk_Number) + " для получения его состояния.").c_str(), g_cErrorText_Title, g_iErrorText_Icons); CloseHandle(hDrive_Physical); return -1; } CloseHandle(hDrive_Physical); //Работа с полученной информацией. BYTE *byteAttributes = static_cast<BYTE*>(Params_From_DeviceIoControl->bBuffer); //Обычно 0x0A. BYTE *byteThresholds = static_cast<BYTE*>(Thresholds_From_DeviceIoControl->bBuffer); //Обычно 0x01. for (int i=0; i<54; ++i) //Кол-во параметров S.M.A.R.T. - 54. { BYTE *byteAttribute = &byteAttributes[2+i*12]; BYTE *byteThreshold = &byteThresholds[2+i*12]; unsigned __int64 uiData = 0; //Флаг определения накопителя Hitachi, у которой смещен S.M.A.R.T. И Western Digital, у которых температура записывается не в Value, а в RAW. if (!byteAttribute[INDEX_ATTRIBUTE_INDEX]) continue; //Пропуск пустых атрибутов. CopyMemory(static_cast<void*>(&uiData),static_cast<void*>(&byteAttribute[INDEX_ATTRIBUTE_RAW]),sizeof(&byteAttribute[INDEX_ATTRIBUTE_RAW])); //Определение uiData для флага Hitachi. if (byteAttribute[INDEX_ATTRIBUTE_INDEX] == iParameter_Number) { if (iParameter_Number==194 || iParameter_Number==190 || iParameter_Number==231) //Танцы с бубном с температурой. 194-й - самый приближенный к физической реальности: температура железа. { if (bHitachi) //Преобразование для Hitachi. uiData показывает на Seagate и WDC просто температуру. Для Hitachi предполагается показ 3 температур как сумма минимальной, текущей и максимальной. { fResult = byteAttribute[INDEX_ATTRIBUTE_RAW]; //if (iParameter_Number==194) byteAttribute[INDEX_ATTRIBUTE_RAW+2] - минимальная температура, byteAttribute[INDEX_ATTRIBUTE_RAW+4] - максимальная. } else if (bWestern_Digital) fResult = byteAttribute[INDEX_ATTRIBUTE_RAW]; else fResult = byteAttribute[INDEX_ATTRIBUTE_VALUE]; if (fResult > 80) fResult = (fResult-32) * 5/9; //Жесткие диски могут возвращать температуру и в кельвинах, и в цельсиях. } else fResult = byteAttribute[INDEX_ATTRIBUTE_VALUE]; //Обычный параметр с одним значением. //byteAttribute[INDEX_ATTRIBUTE_WORST] - максимальное зафиксированное значение, byteThreshold[1] - пороговое. Пороговому - нет доверия. break; } } return fResult; } |