HDDの動作時の温度などのSMART情報はDeviceIoControlを利用してHDDへ直接ATA/ATAPIコマンドを送ることで取得できる。
SMART情報の取得自体は比較的簡単にできる。しかし、取得した値の"意味"をきちんと解説している文章を見つけることは出来なかった。そのため取得した情報を元に想像するしかないようだ。
例えばhttps://www.t13.org/のトップページから「SMART」と検索して見つかる情報によると、HDDの温度はSMART情報のIDが0xC2の情報として取得できるとある。実際の取得結果のRAWデータ部では「26 00 0E 00 2A 00」となっている。ここから想像すると最後の2バイトが摂氏の温度を示していることが分かる。この場合は42度(0x002A)だ。しかしそのほかの「26 00 0E 00」が何を示しているのかは謎のままとなり、本当にこれであっているのかと不安を感じながらの利用となる。
#include "winioctl.h" #include "atlstr.h" // // ATA/ATAPIデバイス情報取得用クラス // //以下の情報を参照しています。 // //・ATA/ATAPI-8コマンドセット(ドラフト案) // https://www.t13.org/ // 上のHPのトップページから「ATAPI」で検索。検索結果の「ATA8-ACS」から「1699Dr0-ATA8-ACS.pdf」 // //・SMART情報 // https://www.t13.org/ // 上のHPのトップページから「SMART」で検索。 // //・Microsoftの用意しているサンプルアプリケーション(ソースコード) // https://download.microsoft.com/download/winddk/sample3/9x/W9X/EN-US/SmartApp.exe // class CDnpATAPI { protected: enum IO_CONTROL_CODE { DFP_RECEIVE_DRIVE_DATA = 0x0007c088, }; enum ATAPI_COMMAND_CODE { ATAPI_IDENTIFY_DEVICE = 0xEC, ATAPI_SMART_READ_DATA = 0xB0, }; #pragma pack(push,1) struct IDENTIFY_DEVICE_OUTDATA { SENDCMDOUTPARAMS sSendCmdOutParam; BYTE pData[IDENTIFY_BUFFER_SIZE - 1]; }; struct SMART_READ_DATA_OUTDATA { SENDCMDOUTPARAMS sSendCmdOutParam; BYTE pData[READ_ATTRIBUTE_BUFFER_SIZE - 1]; }; typedef struct _DRIVEATTRIBUTE { BYTE bAttrID; // Identifies which attribute WORD wStatusFlags; // see bit definitions below BYTE bAttrValue; // Current normalized value BYTE bWorstValue; // How bad has it ever been? BYTE bRawValue[6]; // Un-normalized value BYTE bReserved; // ... } DRIVEATTRIBUTE, *PDRIVEATTRIBUTE, *LPDRIVEATTRIBUTE; public: // // IDENTIFY_DEVICEの取得結果構造体 // struct IDENTIFY_DEVICE { USHORT wGeneralConfiguration; //0 //15bit:0=ATAデバイス、7bit:1=リムーバブルメディア・デバイス USHORT wObsolute1; //1 USHORT wSpecificConfiguration; //2 USHORT wObsolute2; //3 USHORT wRetired1[2]; //4-5 USHORT wObsolute3; //6 ULONG ulReservedForCompactFlash; //7-8 USHORT wRetired2; //9 CHAR pszSerialNumber[20]; //10-19 //シリアルナンバー ULONG ulRetired3; //20-21 USHORT wObsolute4; //22 CHAR pszFirmwareRev[8]; //23-26 //ファームウエア・バージョン CHAR pszModelNumber[40]; //27-46 //モデル名 USHORT wMaxNumPerInterupt; //47 USHORT wReserved1; //48 USHORT wCapabilities1; //49 //8bit:1=DMA対応 9bit:1=LBA対応 10bit:1=IORDY無効 11bit:1=IORDY対応/0=不明 USHORT wCapabilities2; //50 ULONG ulObsolute5; //51-52 USHORT wField88and7063; //53 //2bit:1=88ワード目情報利用可能 1bit:1=70:64ワード目情報利用可能 USHORT wObsolute6[5]; //54-58 USHORT wMultSectorStuff; //59 ULONG ulTotalAddressableSectors; //60-61 USHORT wObsolute7; //62 USHORT wMultiWordDMA; //63 //0bit:1=mode0対応 1bit:1=mode1対応 2bit:1=mode2対応 8bit:1=mode0選択 9bit:mode1選択 10bit:mode2選択 USHORT wPIOMode; //64 USHORT wMinMultiwordDMACycleTime; //65 USHORT wRecommendedMultiwordDMACycleTime; //66 USHORT wMinPIOCycleTimewoFlowCtrl; //67 USHORT wMinPIOCycleTimeWithFlowCtrl; //68 USHORT wReserved2[6]; //69-74 USHORT wQueueDepth; //75 USHORT wReserved3[4]; //76-79 USHORT wMajorVersion; //80 //4bit:1=ATA/ATAPI-4対応 5bit:1=ATA/ATAPI-5対応 6bit:1=ATA/ATAPI-6対応 7bit:1=ATA/ATAPI-7対応 USHORT wMinorVersion; //81 USHORT wCommandSetSupported1; //82 //0bit:1=SMART対応 1bit:SecurityMode対応 .... USHORT wCommandSetSupported2; //83 //0bit:1=DOWNLOAD Microcode対応 .... USHORT wCommandSetSupported3; //84 //0bit:1=SMART error logging対応 1bit:1=SMART self-test対応 .... USHORT wCommandSetEnable1; //85 //0bit:1=SMART利用可能 .... USHORT wCommandSetEnable2; //86 //0bit:1=DOWNLOAD Microcode利用可能 .... USHORT wCommandSetDefault; //87 USHORT wUltraDMAMode; //88 //0bit:1=UltraDMAmode0対応 1bit:1=UltraDMAmode1対応 .... USHORT wTimeReqForSecurityErase; //89 USHORT wTimeReqForEnhancedSecure; //90 USHORT wCurrentPowerManagement; //91 USHORT wMasterPasswordRevision; //92 USHORT wHardwareResetResult; //93 USHORT wAcoustricmanagement; //94 USHORT wStreamMinRequestSize; //95 USHORT wStreamingTimeDMA; //96 USHORT wStreamingAccessLatency; //97 ULONG ulStreamingPerformance; //98-99 USHORT pwMaxUserLBA[4]; //100-103 USHORT wStremingTimePIO; //104 USHORT wReserved4; //105 USHORT wSectorSize; //106 USHORT wInterSeekDelay; //107 USHORT wIEEEOUI; //108 USHORT wUniqueID3; //109 USHORT wUniqueID2; //110 USHORT wUniqueID1; //111 USHORT wReserved5[4]; //112-115 USHORT wReserved6; //116 ULONG ulWordsPerLogicalSector; //117-118 USHORT wReserved7[8]; //119-126 USHORT wRemovableMediaStatus; //127 USHORT wSecurityStatus; //128 USHORT pwVendorSpecific[31]; //129-159 USHORT wCFAPowerMode1; //160 USHORT wReserved8[15]; //161-175 CHAR pszCurrentMediaSerialNo[60];//176-205 USHORT wReserved9[49]; //206-254 USHORT wIntegrityWord; //255 //0-7bit:Signature 8-15bit:Checksum }; #pragma pack(pop) protected: // // 文字列並びの整形 // VOID ChangeByteOrder(PCHAR szString, USHORT uscStrSize) { USHORT i; CHAR temp; for(i = 0; i < uscStrSize; i+=2) { temp = szString[i]; szString[i] = szString[i+1]; szString[i+1] = temp; } } // // DeviceIoControlへ渡すハンドルの取得 // bool GetIoCtrlHandle(HANDLE* phIoCtrl,int nDeviceNo) { BOOL ret; HANDLE hIoCtrl; OSVERSIONINFO sVerInfo; if(phIoCtrl == NULL) return false; *phIoCtrl = INVALID_HANDLE_VALUE; ::ZeroMemory(&sVerInfo,sizeof(OSVERSIONINFO)); sVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); ret = ::GetVersionEx(&sVerInfo); if(ret == FALSE) return false; //OSによってCreateFile処理を変える if(sVerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) hIoCtrl = ::CreateFile(_T("\\\\.\\SMARTVSD"), 0,0,0,CREATE_NEW, 0, 0); //Windows 9x else { CAtlString strDevice; strDevice.Format(_T("\\\\.\\PhysicalDrive%d"),nDeviceNo); hIoCtrl = ::CreateFile(strDevice,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); } if(hIoCtrl == INVALID_HANDLE_VALUE) return false; *phIoCtrl = hIoCtrl; return true; } public: class CSmartAttribute { BYTE _pAttributeData[READ_ATTRIBUTE_BUFFER_SIZE]; DRIVEATTRIBUTE* _ppInfo[30]; public: CSmartAttribute() { Init(); } void Init(void) { ::ZeroMemory(_pAttributeData,READ_ATTRIBUTE_BUFFER_SIZE); ::ZeroMemory(_ppInfo,sizeof(DRIVEATTRIBUTE*) * 30); } bool SetData(const BYTE* pData,int cbSize) { if(cbSize != READ_ATTRIBUTE_BUFFER_SIZE) return false; Init(); memcpy(_pAttributeData,pData,READ_ATTRIBUTE_BUFFER_SIZE); int i; DRIVEATTRIBUTE** ppInfo; DRIVEATTRIBUTE* pAttribute; ppInfo = _ppInfo; pAttribute = (DRIVEATTRIBUTE*)&(_pAttributeData[2]); for(i = 0; i < 30; i++) { if(pAttribute->bAttrID) { *ppInfo = pAttribute; ppInfo++; } pAttribute++; } return true; } bool GetAttributeCount(int* pnCount) { int i; if(pnCount == NULL) return false; *pnCount = 0; for(i = 0; i < 30; i++) { if(_ppInfo[i] && _ppInfo[i]->bAttrID == 0) break; (*pnCount)++; } return true; } bool GetAttribute(int nIndex,BYTE* pcbAttrID,WORD* pwFlags,BYTE* pcbValue,BYTE* pcbWorstValue,BYTE pcbRawValue[6],BYTE* pcbReserved) { if(nIndex < 0 || nIndex > 30 || _ppInfo[nIndex] == NULL || _ppInfo[nIndex]->bAttrID == 0) return false; if(pcbAttrID) *pcbAttrID = _ppInfo[nIndex]->bAttrID; if(pwFlags) *pwFlags = _ppInfo[nIndex]->wStatusFlags; if(pcbValue) *pcbValue = _ppInfo[nIndex]->bAttrValue; if(pcbWorstValue) *pcbWorstValue = _ppInfo[nIndex]->bWorstValue; if(pcbRawValue) memcpy(pcbRawValue,_ppInfo[nIndex]->bRawValue,6); if(pcbReserved) *pcbReserved = _ppInfo[nIndex]->bReserved; return true; } // // SMARTの属性IDの説明文字列を取得する // //TODO:※日本語訳や意味に間違えがある可能性があります! // bool GetAttributeIdString(BYTE cbAttrID,CAtlString* pstrName,CAtlString* pstrNameJp,CAtlString* pstrDesctiption) { switch(cbAttrID) { case 0x01: if(pstrName) *pstrName = _T("Raw read error rate"); if(pstrNameJp) *pstrNameJp = _T("読み込みエラー率"); if(pstrDesctiption) *pstrDesctiption= _T("読み込み時に発生したエラーの割合です。"); break; case 0x02: if(pstrName) *pstrName = _T("Throughput performance"); if(pstrNameJp) *pstrNameJp = _T("スループット"); if(pstrDesctiption) *pstrDesctiption= _T("HDDの効率です。"); break; case 0x03: if(pstrName) *pstrName = _T("Spinup time"); if(pstrNameJp) *pstrNameJp = _T("スピンアップ時間"); if(pstrDesctiption) *pstrDesctiption= _T("回転開始に必要な時間です。"); break; case 0x04: if(pstrName) *pstrName = _T("Start/Stop count"); if(pstrNameJp) *pstrNameJp = _T("回転/停止数"); if(pstrDesctiption) *pstrDesctiption= _T("モーターの回転開始/停止の回数です。"); break; case 0x05: if(pstrName) *pstrName = _T("Reallocated sector count"); if(pstrNameJp) *pstrNameJp = _T("再割り当てセクター数"); if(pstrDesctiption) *pstrDesctiption= _T("セクター不良などで再割り当てされたセクター数です。"); break; case 0x06: if(pstrName) *pstrName = _T("Read channel margin"); if(pstrNameJp) *pstrNameJp = _T("リード・チャンネル・マージン"); if(pstrDesctiption) *pstrDesctiption= _T("読み込み時に割り当てたチャンネル数です。"); break; case 0x07: if(pstrName) *pstrName = _T("Seek error rate"); if(pstrNameJp) *pstrNameJp = _T("シークエラー率"); if(pstrDesctiption) *pstrDesctiption= _T("シークの際に生じたエラーの割合です。"); break; case 0x08: if(pstrName) *pstrName = _T("Seek timer performance"); if(pstrNameJp) *pstrNameJp = _T("シークタイム性能"); if(pstrDesctiption) *pstrDesctiption= _T("シークの平均効率です。"); break; case 0x09: if(pstrName) *pstrName = _T("Power-on hours count"); if(pstrNameJp) *pstrNameJp = _T("合計利用時間"); if(pstrDesctiption) *pstrDesctiption= _T("電源を入れていた時間の合計です。"); break; case 0x0A: if(pstrName) *pstrName = _T("Spinup retry count"); if(pstrNameJp) *pstrNameJp = _T("スピンアップ再試行回数"); if(pstrDesctiption) *pstrDesctiption= _T("スピンアップを繰り返した回数です。"); break; case 0x0B: if(pstrName) *pstrName = _T("Calibration retry count"); if(pstrNameJp) *pstrNameJp = _T("キャリブレーション再試行回数"); if(pstrDesctiption) *pstrDesctiption= _T("デバイス初期化を繰り返した回数です。"); break; case 0x0C: if(pstrName) *pstrName = _T("Power cycle count"); if(pstrNameJp) *pstrNameJp = _T("電源投入回数"); if(pstrDesctiption) *pstrDesctiption= _T("電源投入イベントの実行された回数です。"); break; case 0x0D: case 0xC9: if(pstrName) *pstrName = _T("Soft read error rate"); if(pstrNameJp) *pstrNameJp = _T("論理読み込みエラー率"); if(pstrDesctiption) *pstrDesctiption= _T("読み込み中に生じたプログラム実行エラーの割合です。"); break; case 0xBB: case 0xBD: case 0xBE: if(pstrName) *pstrName = _T("vendor-specific"); if(pstrNameJp) *pstrNameJp = _T("ベンダー独自情報"); if(pstrDesctiption) *pstrDesctiption= _T("製造メーカーの独自情報です。"); break; case 0xBF: if(pstrName) *pstrName = _T("G-sense error rate"); if(pstrNameJp) *pstrNameJp = _T("加速度センサー検出エラー率"); if(pstrDesctiption) *pstrDesctiption= _T("物理衝撃によるエラーの割合です。"); break; case 0xC0: if(pstrName) *pstrName = _T("Power-off retract count"); if(pstrNameJp) *pstrNameJp = _T("電源切断回避数"); if(pstrDesctiption) *pstrDesctiption= _T("電源切断もしくは緊急時のヘッド回避回数です。"); break; case 0xC1: if(pstrName) *pstrName = _T("Load/Unload cycle count"); if(pstrNameJp) *pstrNameJp = _T("ロード/アンロード・サイクル数"); if(pstrDesctiption) *pstrDesctiption= _T("ヘッド回避位置へ移動した回数です。"); break; case 0xC2: if(pstrName) *pstrName = _T("HDA temperature"); if(pstrNameJp) *pstrNameJp = _T("温度"); if(pstrDesctiption) *pstrDesctiption= _T("HDDの内部温度です。"); break; case 0xC3: if(pstrName) *pstrName = _T("Hardware ECC recovered"); if(pstrNameJp) *pstrNameJp = _T("ハードウエアECC復旧"); if(pstrDesctiption) *pstrDesctiption= _T("ECCによるエラー検出数です。"); break; case 0xC4: if(pstrName) *pstrName = _T("Reallocation count"); if(pstrNameJp) *pstrNameJp = _T("再割り当て数"); if(pstrDesctiption) *pstrDesctiption= _T("割り当て命令の実行数です。"); break; case 0xC5: if(pstrName) *pstrName = _T("Current pending sector count"); if(pstrNameJp) *pstrNameJp = _T("不安定セクター数"); if(pstrDesctiption) *pstrDesctiption= _T("再割り当て待ちの不安定なセクター数です。"); break; case 0xC6: if(pstrName) *pstrName = _T("Offline scan uncorrectable count"); if(pstrNameJp) *pstrNameJp = _T("未訂正エラー数"); if(pstrDesctiption) *pstrDesctiption= _T("訂正できなかったエラー数です。"); break; case 0xC7: if(pstrName) *pstrName = _T("UDMA CRC error rate"); if(pstrNameJp) *pstrNameJp = _T("UltraDMA CRCエラー"); if(pstrDesctiption) *pstrDesctiption= _T("UltraDMAモードにおけるCRCエラー数です。"); break; case 0xC8: if(pstrName) *pstrName = _T("Write error rate"); if(pstrNameJp) *pstrNameJp = _T("書き込みエラー率"); if(pstrDesctiption) *pstrDesctiption= _T("書き込み時に生じたエラーの割合です。"); break; //case 0xC9: case 0xCA: if(pstrName) *pstrName = _T("Data Address Mark errors"); if(pstrNameJp) *pstrNameJp = _T("DAM(Data Address Mark)エラー"); if(pstrDesctiption) *pstrDesctiption= _T("DAMエラーの生じた回数もしくはベンダー独自情報です。"); break; case 0xCB: if(pstrName) *pstrName = _T("Run out cancel"); if(pstrNameJp) *pstrNameJp = _T("ECCエラー"); if(pstrDesctiption) *pstrDesctiption= _T("ECCエラーの生じた回数です。"); break; case 0xCC: if(pstrName) *pstrName = _T("Soft ECC correction"); if(pstrNameJp) *pstrNameJp = _T("論理ECC訂正"); if(pstrDesctiption) *pstrDesctiption= _T("ソフトウエアECCによるエラー訂正数です。"); break; case 0xCD: if(pstrName) *pstrName = _T("Thermal asperity rate(TAR)"); if(pstrNameJp) *pstrNameJp = _T("熱エラー率(TAR)"); if(pstrDesctiption) *pstrDesctiption= _T("TARエラーの生じた回数です。"); break; case 0xCE: if(pstrName) *pstrName = _T("Flying height"); if(pstrNameJp) *pstrNameJp = _T("ヘッド高"); if(pstrDesctiption) *pstrDesctiption= _T("ディスク面とヘッドとの隙間です。"); break; case 0xCF: if(pstrName) *pstrName = _T("Spin high current"); if(pstrNameJp) *pstrNameJp = _T("最大回転電流"); if(pstrDesctiption) *pstrDesctiption= _T("モーターに流れた最大電流です。"); break; case 0xD0: if(pstrName) *pstrName = _T("Spin buzz"); if(pstrNameJp) *pstrNameJp = _T("ヘッド制御"); if(pstrDesctiption) *pstrDesctiption= _T("スピンアップ時のヘッド制御処理の数です。"); break; case 0xD1: if(pstrName) *pstrName = _T("Offline seek performance"); if(pstrNameJp) *pstrNameJp = _T("オフライン・シーク性能"); if(pstrDesctiption) *pstrDesctiption= _T("オフライン時のシーク性能です。"); break; case 0xDC: if(pstrName) *pstrName = _T("Disk shift"); if(pstrNameJp) *pstrNameJp = _T("ディスク交換"); if(pstrDesctiption) *pstrDesctiption= _T("(内容不明)"); break; case 0xDD: if(pstrName) *pstrName = _T("G-sense error rate"); if(pstrNameJp) *pstrNameJp = _T("加速度センサー検出エラー率"); if(pstrDesctiption) *pstrDesctiption= _T("衝撃によるエラーの検出割合です。"); break; case 0xDE: if(pstrName) *pstrName = _T("Loaded hours"); if(pstrNameJp) *pstrNameJp = _T("利用時間"); if(pstrDesctiption) *pstrDesctiption= _T("利用可能状態にある時間数です。"); break; case 0xDF: if(pstrName) *pstrName = _T("Load/unload retry count"); if(pstrNameJp) *pstrNameJp = _T("ロード/アンロード再試行回数"); if(pstrDesctiption) *pstrDesctiption= _T("ロードを繰り返した回数です。"); break; case 0xE0: if(pstrName) *pstrName = _T("Load friction"); if(pstrNameJp) *pstrNameJp = _T("ロード抵抗"); if(pstrDesctiption) *pstrDesctiption= _T("物理的摩擦で生じたロード数です。"); break; case 0xE1: if(pstrName) *pstrName = _T("Load/Unload cycle count"); if(pstrNameJp) *pstrNameJp = _T("ロード/アンロード・サイクル数"); if(pstrDesctiption) *pstrDesctiption= _T("ロードの合計数です。"); break; case 0xE2: if(pstrName) *pstrName = _T("Load-in time"); if(pstrNameJp) *pstrNameJp = _T("ロードイン時間"); if(pstrDesctiption) *pstrDesctiption= _T("ドライブのロードにかかる時間です。"); break; case 0xE3: if(pstrName) *pstrName = _T("Torque amplification count"); if(pstrNameJp) *pstrNameJp = _T("トルク増幅数"); if(pstrDesctiption) *pstrDesctiption= _T("回転モーメントの影響量です。"); break; case 0xE4: if(pstrName) *pstrName = _T("Power-off retract count"); if(pstrNameJp) *pstrNameJp = _T("電源切断退避数"); if(pstrDesctiption) *pstrDesctiption= _T("電源切断によるヘッドの退避回数です。"); break; case 0xE6: if(pstrName) *pstrName = _T("GMR head amplitude"); if(pstrNameJp) *pstrNameJp = _T("GMRヘッド振幅"); if(pstrDesctiption) *pstrDesctiption= _T("GMRヘッドの振動の振幅です。"); break; case 0xE7: if(pstrName) *pstrName = _T("Temperature"); if(pstrNameJp) *pstrNameJp = _T("温度"); if(pstrDesctiption) *pstrDesctiption= _T("ドライブの温度です。"); break; case 0xF0: if(pstrName) *pstrName = _T("Head flying hours"); if(pstrNameJp) *pstrNameJp = _T("シーク移動時間"); if(pstrDesctiption) *pstrDesctiption= _T("ヘッドが動いている時間です。"); break; case 0xFA: if(pstrName) *pstrName = _T("Read error retry rate"); if(pstrNameJp) *pstrNameJp = _T("読み込みエラー再試行数"); if(pstrDesctiption) *pstrDesctiption= _T("読み込みエラーの回数です。"); break; default: if(pstrName) *pstrName = _T("Unknown"); if(pstrNameJp) *pstrNameJp = _T("不明"); if(pstrDesctiption) *pstrDesctiption= _T("用途不明です。"); return false; } return true; } }; // // SMART情報取得 // bool GetSmartReadData(int nDeviceNo,CSmartAttribute* pInfo) { bool ret; BOOL bRet; HANDLE hIoCtrl; DWORD dwReturned; SENDCMDINPARAMS sSendCmd; SMART_READ_DATA_OUTDATA sSendCmdOutParam; if(pInfo == NULL) return false; pInfo->Init(); //ハンドル取得 ret = GetIoCtrlHandle(&hIoCtrl,nDeviceNo); if(ret == false) return false; ::ZeroMemory(&sSendCmdOutParam,sizeof(SMART_READ_DATA_OUTDATA)); ::ZeroMemory(&sSendCmd,sizeof(SENDCMDINPARAMS)); sSendCmd.irDriveRegs.bFeaturesReg = 0xd0; sSendCmd.irDriveRegs.bCylLowReg = 0x4f; sSendCmd.irDriveRegs.bCylHighReg = 0xc2; sSendCmd.irDriveRegs.bDriveHeadReg = 0xA0 | ((nDeviceNo & 1) << 4); //ドライブ番号 sSendCmd.irDriveRegs.bCommandReg = ATAPI_SMART_READ_DATA; //SMART READ DATAコマンド番号 sSendCmd.cBufferSize = READ_ATTRIBUTE_BUFFER_SIZE; sSendCmd.bDriveNumber = nDeviceNo; //ドライブ番号 //コマンドの実行 bRet = ::DeviceIoControl(hIoCtrl,DFP_RECEIVE_DRIVE_DATA,&sSendCmd,sizeof(SENDCMDINPARAMS),&sSendCmdOutParam,sizeof(SMART_READ_DATA_OUTDATA),&dwReturned,NULL); ::CloseHandle(hIoCtrl); if(ret == FALSE || dwReturned != sizeof(SMART_READ_DATA_OUTDATA)) return false; return pInfo->SetData(sSendCmdOutParam.sSendCmdOutParam.bBuffer,READ_ATTRIBUTE_BUFFER_SIZE); } class CModelInfo { public: CAtlString _strModel; CAtlString _strFirmware; CAtlString _strSerialNo; }; // // デバイス情報取得 // bool GetIdentifyDevice(int nDeviceNo,IDENTIFY_DEVICE* pData,CModelInfo* pInfo=NULL) { bool ret; BOOL bRet; HANDLE hIoCtrl; DWORD dwReturned; IDENTIFY_DEVICE_OUTDATA sSendCmdOutParam; SENDCMDINPARAMS sSendCmd; if(pData == NULL) return false; ::ZeroMemory(pData,sizeof(IDENTIFY_DEVICE)); if(pInfo) *pInfo = CModelInfo(); //ハンドル取得 ret = GetIoCtrlHandle(&hIoCtrl,nDeviceNo); if(ret == false) return false; ::ZeroMemory(&sSendCmdOutParam,sizeof(IDENTIFY_DEVICE_OUTDATA)); ::ZeroMemory(&sSendCmd,sizeof(SENDCMDINPARAMS)); sSendCmd.irDriveRegs.bCommandReg = ATAPI_IDENTIFY_DEVICE; //IDENTIFY DEVICEコマンド番号 sSendCmd.irDriveRegs.bDriveHeadReg = 0xA0 | ((nDeviceNo & 1) << 4); //ドライブ番号 sSendCmd.cBufferSize = IDENTIFY_BUFFER_SIZE; sSendCmd.bDriveNumber = nDeviceNo; //ドライブ番号 //IDENTIFY DEVICEコマンドの実行 bRet = ::DeviceIoControl(hIoCtrl,DFP_RECEIVE_DRIVE_DATA,&sSendCmd,sizeof(SENDCMDINPARAMS),&sSendCmdOutParam,sizeof(IDENTIFY_DEVICE_OUTDATA),&dwReturned,NULL); ::CloseHandle(hIoCtrl); if(ret == FALSE || dwReturned != sizeof(IDENTIFY_DEVICE_OUTDATA)) return false; memcpy_s(pData,sizeof(IDENTIFY_DEVICE),sSendCmdOutParam.sSendCmdOutParam.bBuffer,sizeof(IDENTIFY_DEVICE)); if(pInfo) { char pszBuff[256]; IDENTIFY_DEVICE* pData; pData = (IDENTIFY_DEVICE*)sSendCmdOutParam.sSendCmdOutParam.bBuffer; ChangeByteOrder(pData->pszModelNumber,sizeof(pData->pszModelNumber)); ChangeByteOrder(pData->pszFirmwareRev,sizeof(pData->pszFirmwareRev)); ChangeByteOrder(pData->pszSerialNumber,sizeof(pData->pszSerialNumber)); strncpy_s(pszBuff,256,pData->pszModelNumber,sizeof(pData->pszModelNumber)); pInfo->_strModel = pszBuff; strncpy_s(pszBuff,256,pData->pszFirmwareRev,sizeof(pData->pszFirmwareRev)); pInfo->_strFirmware = pszBuff; strncpy_s(pszBuff,256,pData->pszSerialNumber,sizeof(pData->pszSerialNumber)); pInfo->_strSerialNo = pszBuff; } return true; } }; bool Test() { int j; //PCに接続されているATAドライブのうち最初の4つの情報を取得&表示する for(j = 0; j < 4; j++) { bool ret; int i; int nSize; CAtlString strMessage; CDnpATAPI cIDE; CDnpATAPI::CSmartAttribute cAttrInfo; ret = cIDE.GetSmartReadData(j,&cAttrInfo); if(ret == false) continue; ret = cAttrInfo.GetAttributeCount(&nSize); if(ret == false) continue; for(i = 0; i < nSize; i++) { BYTE cbAttrID; BYTE cbValue; BYTE pcbRawData[6]; CAtlString strName; CAtlString strNameJp; CAtlString strDescription; CAtlString strBuff; ret = cAttrInfo.GetAttribute(i,&cbAttrID,NULL,&cbValue,NULL,pcbRawData,NULL); if(ret == false) continue; ret = cAttrInfo.GetAttributeIdString(cbAttrID,&strName,&strNameJp,&strDescription); if(ret == false) continue; strBuff.Format(_T("%s(%s) %s\n"),strNameJp,strName,strDescription); strMessage += strBuff; strBuff.Format(_T("%02X %03d %02X%02X %02X%02X %02X%02X\n\n"),cbAttrID,cbValue,pcbRawData[0],pcbRawData[1],pcbRawData[2],pcbRawData[3],pcbRawData[4],pcbRawData[5]); strMessage += strBuff; } ::MessageBox(NULL,strMessage,_T(""),MB_OK); } return true; }