MSDN.WhiteKnight - Stack Overflow answers
Ответ на "Получение серийного номера и типа шины диска"
Answer 1099919
Не знаю насчет универсального способа, но для любого жесткого диска, поддерживающего набор команд ATA-2, должна работать команда IDENTIFY DEVICE, которая возвращает серийный номер. Разная интерпретация байт тут невозможна, так как там просто ANSI-символы по сути. Хотя конечно, команда возвращает только то, что зашито в устройство. Там может быть просто мусор вместо уникального номера, как со знаменитыми "to be filled by O.E.M." в таблице SMBIOS. По некорректным результатам для одного устройства нельзя сделать вывод, что способ нерабочий. Нужно иметь несколько разных устройств и с ними экспериментировать.
Вот пример кода для получения серийного номера (требуются права администратора):
#include <windows.h> #include <stdio.h> typedef struct { WORD wGenConfig; WORD wNumCyls; WORD wReserved; WORD wNumHeads; WORD wBytesPerTrack; WORD wBytesPerSector; WORD wSectorsPerTrack; WORD wVendorUnique[3]; BYTE sSerialNumber[20]; WORD wBufferType; WORD wBufferSize; WORD wECCSize; BYTE sFirmwareRev[8]; BYTE sModelNumber[39]; WORD wMoreVendorUnique; WORD wDoubleWordIO; WORD wCapabilities; WORD wReserved1; WORD wPIOTiming; WORD wDMATiming; WORD wBS; WORD wNumCurrentCycles; WORD wNumCurrentHeads; WORD wNumCurrentSectorsPerTrack; WORD ulCurrentSectorCapacity; WORD wMultiSectorStuff; DWORD ulTotalAddressableSectors; WORD wSingleWordDMA; WORD wMultiWordDMA; BYTE bReserved[127]; }ST_IDSECTOR; //ATA 7.17.7.1 - IDENTIFY DEVICE data typedef struct { BYTE m_ucAttribIndex; DWORD m_dwAttribValue; BYTE m_ucValue; BYTE m_ucWorst; DWORD m_dwThreshold; }ST_SMART_INFO; typedef struct { GETVERSIONINPARAMS m_stGVIP; ST_IDSECTOR m_stInfo; ST_SMART_INFO m_stSmartInfo[256]; BYTE m_ucSmartValues; BYTE m_ucDriveIndex; char m_csErrorString[1000]; }ST_DRIVE_INFO; #define DRIVE_HEAD_REG 0xA0 #define OUT_BUFFER_SIZE IDENTIFY_BUFFER_SIZE+16 void SwapBytes(char* p, size_t len) { if (len % 2 != 0)len--; char t; for (int i = 0; i < len - 1; i += 2) { t = p[i]; p[i] = p[i + 1]; p[i + 1] = t; } } BOOL CollectDriveInfo(HANDLE hDevice, UCHAR ucDriveIndex, ST_IDSECTOR* pInfo) { BOOL bRet = FALSE; SENDCMDINPARAMS stCIP = { 0 }; DWORD dwRet = 0; char szOutput[OUT_BUFFER_SIZE] = { 0 }; stCIP.cBufferSize = IDENTIFY_BUFFER_SIZE; stCIP.bDriveNumber = ucDriveIndex; stCIP.irDriveRegs.bFeaturesReg = 0; stCIP.irDriveRegs.bSectorCountReg = 1; stCIP.irDriveRegs.bSectorNumberReg = 1; stCIP.irDriveRegs.bCylLowReg = 0; stCIP.irDriveRegs.bCylHighReg = 0; stCIP.irDriveRegs.bDriveHeadReg = DRIVE_HEAD_REG; stCIP.irDriveRegs.bCommandReg = ID_CMD; //ATA 7.17 - IDENTIFY DEVICE bRet = DeviceIoControl(hDevice, SMART_RCV_DRIVE_DATA, &stCIP, sizeof(stCIP), szOutput, OUT_BUFFER_SIZE, &dwRet, NULL); if (bRet) { CopyMemory(pInfo, szOutput + 16, sizeof(ST_IDSECTOR)); } else dwRet = GetLastError(); return bRet; } BOOL GetDriveInfo(BYTE ucDriveIndex, ST_DRIVE_INFO* pInfo) { HANDLE hDevice = NULL; char szT1[MAX_PATH] = { 0 }; BOOL bRet = FALSE; DWORD dwRet = 0; sprintf_s(szT1, sizeof(szT1), "\\\\.\\PHYSICALDRIVE%d", ucDriveIndex); hDevice = CreateFileA(szT1, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL); if (hDevice != INVALID_HANDLE_VALUE) { bRet = DeviceIoControl(hDevice, SMART_GET_VERSION, NULL, 0, &pInfo->m_stGVIP, sizeof(GETVERSIONINPARAMS), &dwRet, NULL); if (bRet) { if ((pInfo->m_stGVIP.fCapabilities & CAP_ATA_ID_CMD) == CAP_ATA_ID_CMD) { bRet = CollectDriveInfo(hDevice, ucDriveIndex,&pInfo->m_stInfo); } else printf("ATA IDENTIFY DEVICE command is not supported"); } else printf("S.M.A.R.T error"); CloseHandle(hDevice); } else printf("CreateFile error %d\n",GetLastError()); return bRet; } int main() { ST_DRIVE_INFO info; BOOL res = GetDriveInfo(0,&info); if (res == FALSE) { printf("GetDriveInfo Error\n"); getchar(); return 1; } char sbuf[50] = ""; char* pch = NULL; ZeroMemory(sbuf, sizeof(sbuf)); strncpy_s(sbuf, sizeof(sbuf), (char*)info.m_stInfo.sSerialNumber, 20); SwapBytes(sbuf, 20); pch = &(sbuf[0]); while (true) { if (*pch != ' ')break; if (pch >= &(sbuf[18]))break; pch++; } printf("Serial number: %s\n", pch); getchar(); return 0; }
У дисков NVM Express драйвер может работать в режиме эмуляции ATA, тогда устройство может отвечать на команду IDENTIFY DEVICE, на при этом не возвращать флаг CAP_ATA_ID_CMD при проверке возможностей. (У NVM Express есть своя система команд, в которой тоже есть команда IDENTIFY, но другого формата.) Если нужно обрабатывать такие случаи, лучше без предварительной проверки сразу слать команду и смотреть на коды ошибок.
Источники
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.