
HDDのシリアルナンバーを取得するにはDeviceIoControlを利用して、HDDへ直接ATA/ATAPIのコマンドを送る。
シリアル番号以外にも取得できる情報はたくさんある。詳しくはATA/ATAPIの仕様書を参照するといいだろう。
http://www.t13.org/内で「ATAPI」と検索すれば見つかり、PDF形式やWORD形式で無料ダウンロードできる。
#include "winioctl.h"
#include "atlstr.h"
//
// ATA/ATAPIデバイス情報取得用クラス
//
//以下の情報を参照しています。
//
//・ATA/ATAPI-8コマンドセット(ドラフト案)
// http://www.t13.org/
// 上のHPのトップページから「ATAPI」で検索。検索結果の「ATA8-ACS」から「1699Dr0-ATA8-ACS.pdf」
//
//・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,
};
#pragma pack(push,1)
struct IDENTIFY_DEVICE_OUTDATA
{
SENDCMDOUTPARAMS sSendCmdOutParam;
BYTE pData[IDENTIFY_BUFFER_SIZE - 1];
};
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 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 i;
//PCに接続されているHDDドライブのうち最初の4つの情報を取得&表示する
for(i = 0; i < 4; i++)
{
bool ret;
CDnpATAPI cIDE;
CDnpATAPI::CModelInfo cInfo;
CDnpATAPI::IDENTIFY_DEVICE sInfo;
ret = cIDE.GetIdentifyDevice(i,&sInfo,&cInfo);
if(ret == false)
continue;
CAtlString strMessage;
strMessage = _T("型番:");
strMessage += cInfo._strModel;
strMessage += _T("\n");
strMessage += _T("シリアル番号:");
strMessage += cInfo._strSerialNo;
strMessage += _T("\n");
strMessage += _T("ファームウエア:");
strMessage += cInfo._strFirmware;
strMessage += _T("\n");
strMessage += _T("\n");
if(sInfo.wGeneralConfiguration & 0x8000)
strMessage += _T("NOT ATA Device\n");
else
strMessage += _T("ATA Device\n");
if(sInfo.wGeneralConfiguration & 0x0008)
strMessage += _T("Removable Media Device\n");
if(sInfo.wCapabilities1 & 0x0100)
strMessage += _T("DMA対応\n");
if(sInfo.wCapabilities1 & 0x0200)
strMessage += _T("LBA対応\n");
if(sInfo.wCapabilities1 & 0x0800)
strMessage += _T("IORDY対応\n");
if(sInfo.wMultiWordDMA & 0x0400)
strMessage += _T("Multiword DMA mode 2利用中\n");
else if(sInfo.wMultiWordDMA & 0x0200)
strMessage += _T("Multiword DMA mode 1利用中\n");
else if(sInfo.wMultiWordDMA & 0x0100)
strMessage += _T("Multiword DMA mode 0利用中\n");
if(sInfo.wMultiWordDMA & 0x0004)
strMessage += _T("Multiword DMA mode 2対応\n");
else if(sInfo.wMultiWordDMA & 0x0002)
strMessage += _T("Multiword DMA mode 1対応\n");
else if(sInfo.wMultiWordDMA & 0x0001)
strMessage += _T("Multiword DMA mode 0対応\n");
if(sInfo.wMajorVersion & 0x0080)
strMessage += _T("ATA/ATAPI-7対応\n");
else if(sInfo.wMajorVersion & 0x0040)
strMessage += _T("ATA/ATAPI-6対応\n");
else if(sInfo.wMajorVersion & 0x0020)
strMessage += _T("ATA/ATAPI-5対応\n");
else if(sInfo.wMajorVersion & 0x0010)
strMessage += _T("ATA/ATAPI-4対応\n");
if(sInfo.wCommandSetEnable1 & 0x0001)
strMessage += _T("S.M.A.R.T.利用可能\n");
if(sInfo.wCommandSetEnable1 & 0x0004)
strMessage += _T("Removable Media機能利用可能\n");
if(sInfo.wCommandSetEnable1 & 0x0020)
strMessage += _T("ライトキャッシュ利用可能\n");
if(sInfo.wUltraDMAMode & 0x4000)
strMessage += _T("Ultra DMA mode 6利用中\n");
else if(sInfo.wUltraDMAMode & 0x2000)
strMessage += _T("Ultra DMA mode 5利用中\n");
else if(sInfo.wUltraDMAMode & 0x1000)
strMessage += _T("Ultra DMA mode 4利用中\n");
else if(sInfo.wUltraDMAMode & 0x0800)
strMessage += _T("Ultra DMA mode 3利用中\n");
else if(sInfo.wUltraDMAMode & 0x0400)
strMessage += _T("Ultra DMA mode 2利用中\n");
else if(sInfo.wUltraDMAMode & 0x0200)
strMessage += _T("Ultra DMA mode 1利用中\n");
else if(sInfo.wUltraDMAMode & 0x0100)
strMessage += _T("Ultra DMA mode 0利用中\n");
if(sInfo.wUltraDMAMode & 0x0040)
strMessage += _T("Ultra DMA mode 6対応\n");
else if(sInfo.wUltraDMAMode & 0x0020)
strMessage += _T("Ultra DMA mode 5対応\n");
else if(sInfo.wUltraDMAMode & 0x0010)
strMessage += _T("Ultra DMA mode 4対応\n");
else if(sInfo.wUltraDMAMode & 0x0008)
strMessage += _T("Ultra DMA mode 3対応\n");
else if(sInfo.wUltraDMAMode & 0x0004)
strMessage += _T("Ultra DMA mode 2対応\n");
else if(sInfo.wUltraDMAMode & 0x0002)
strMessage += _T("Ultra DMA mode 1対応\n");
else if(sInfo.wUltraDMAMode & 0x0001)
strMessage += _T("Ultra DMA mode 0対応\n");
::MessageBox(NULL,strMessage,_T(""),MB_OK);
}
return true;
}
