HDDのS.M.A.R.T情報を取得する

test103.gif
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」が何を示しているのかは謎のままとなり、本当にこれであっているのかと不安を感じながらの利用となる。

依存環境:ATL
#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;
}

プロジェクトファイルをダウンロード


カテゴリー「システム情報」 のエントリー