![]()
HDDの動作時の温度などのSMART情報はDeviceIoControlを利用してHDDへ直接ATA/ATAPIコマンドを送ることで取得できる。
SMART情報の取得自体は比較的簡単にできる。しかし、取得した値の"意味"をきちんと解説している文章を見つけることは出来なかった。そのため取得した情報を元に想像するしかないようだ。
例えばhttp://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コマンドセット(ドラフト案)
// http://www.t13.org/
// 上のHPのトップページから「ATAPI」で検索。検索結果の「ATA8-ACS」から「1699Dr0-ATA8-ACS.pdf」
//
//・SMART情報
// http://www.t13.org/
// 上のHPのトップページから「SMART」で検索。
//
//・Microsoftの用意しているサンプルアプリケーション(ソースコード)
// http://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;
}
