windows平台c++获取硬盘序列号(msys环境)
vmware虚拟机环境有时候获取不到硬盘序列号,设置后可以,参见:https://jingyan.baidu.com/article/cbcede07d345db43f40b4d88.html
本文参考:https://blog.csdn.net/yanchenyu365/article/details/85061879
1.makefile文件
app : HardDrive.cpp HardDriveSerialNumer.cpp g++ -w -o $@ $^
2.main函数文件:HardDrive.cpp
#include "HardDriveSerialNumer.hpp" #include <iostream> #include <string.h> int main() { char SerialNumber[1024] = {""}; memset(&SerialNumber, 0, sizeof(SerialNumber)); MasterHardDiskSerial a; int ret = a.GetSerialNo(SerialNumber); if (ret == 0) { std::cout << "SN " << SerialNumber << std::endl; } else { std::cout << "can't get sn" << std::endl; } }
3.头文件:HardDriveSerialNumer.hpp
#ifndef _HDD_SERIAL_INFO_H_ #define _HDD_SERIAL_INFO_H_ #include <stdio.h> #include <string.h> #include <tchar.h> #include <vector> #include <windows.h> #include <winioctl.h> #pragma pack(1) #define IDENTIFY_BUFFER_SIZE 512 // IOCTL commands #define DFP_GET_VERSION 0x00074080 #define DFP_SEND_DRIVE_COMMAND 0x0007c084 #define DFP_RECEIVE_DRIVE_DATA 0x0007c088 #define FILE_DEVICE_SCSI 0x0000001b #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501) #define IOCTL_SCSI_MINIPORT 0x0004D008 // see NTDDSCSI.H for definition #define SMART_GET_VERSION CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) #define SMART_SEND_DRIVE_COMMAND CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define SMART_RCV_DRIVE_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) // GETVERSIONOUTPARAMS contains the data returned from the // Get Driver Version function. typedef struct _GETVERSIONOUTPARAMS { BYTE bVersion; // Binary driver version. BYTE bRevision; // Binary driver revision. BYTE bReserved; // Not used. BYTE bIDEDeviceMap; // Bit map of IDE devices. DWORD fCapabilities; // Bit mask of driver capabilities. DWORD dwReserved[4]; // For future use. } GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS; // Bits returned in the fCapabilities member of GETVERSIONOUTPARAMS #define CAP_IDE_ID_FUNCTION 1 // ATA ID command supported #define CAP_IDE_ATAPI_ID 2 // ATAPI ID command supported #define CAP_IDE_EXECUTE_SMART_FUNCTION 4 // SMART commannds supported // Valid values for the bCommandReg member of IDEREGS. #define IDE_ATAPI_IDENTIFY 0xA1 // Returns ID sector for ATAPI. #define IDE_ATA_IDENTIFY 0xEC // Returns ID sector for ATA. // The following struct defines the interesting part of the IDENTIFY // buffer: typedef struct _IDSECTOR { USHORT wGenConfig; USHORT wNumCyls; USHORT wReserved; USHORT wNumHeads; USHORT wBytesPerTrack; USHORT wBytesPerSector; USHORT wSectorsPerTrack; USHORT wVendorUnique[3]; CHAR sSerialNumber[20]; USHORT wBufferType; USHORT wBufferSize; USHORT wECCSize; CHAR sFirmwareRev[8]; CHAR sModelNumber[40]; USHORT wMoreVendorUnique; USHORT wDoubleWordIO; USHORT wCapabilities; USHORT wReserved1; USHORT wPIOTiming; USHORT wDMATiming; USHORT wBS; USHORT wNumCurrentCyls; USHORT wNumCurrentHeads; USHORT wNumCurrentSectorsPerTrack; ULONG ulCurrentSectorCapacity; USHORT wMultSectorStuff; ULONG ulTotalAddressableSectors; USHORT wSingleWordDMA; USHORT wMultiWordDMA; BYTE bReserved[128]; } IDSECTOR, *PIDSECTOR; typedef struct _SRB_IO_CONTROL { ULONG HeaderLength; UCHAR Signature[8]; ULONG Timeout; ULONG ControlCode; ULONG ReturnCode; ULONG Length; } SRB_IO_CONTROL, *PSRB_IO_CONTROL; // Max number of drives assuming primary/secondary, master/slave topology // Modified to read only the master serial #define MAX_IDE_DRIVES 1 // // IDENTIFY data (from ATAPI driver source) // #pragma pack(1) typedef struct _IDENTIFY_DATA { USHORT GeneralConfiguration; // 00 00 USHORT NumberOfCylinders; // 02 1 USHORT Reserved1; // 04 2 USHORT NumberOfHeads; // 06 3 USHORT UnformattedBytesPerTrack; // 08 4 USHORT UnformattedBytesPerSector; // 0A 5 USHORT SectorsPerTrack; // 0C 6 USHORT VendorUnique1[3]; // 0E 7-9 USHORT SerialNumber[10]; // 14 10-19 USHORT BufferType; // 28 20 USHORT BufferSectorSize; // 2A 21 USHORT NumberOfEccBytes; // 2C 22 USHORT FirmwareRevision[4]; // 2E 23-26 USHORT ModelNumber[20]; // 36 27-46 UCHAR MaximumBlockTransfer; // 5E 47 UCHAR VendorUnique2; // 5F USHORT DoubleWordIo; // 60 48 USHORT Capabilities; // 62 49 USHORT Reserved2; // 64 50 UCHAR VendorUnique3; // 66 51 UCHAR PioCycleTimingMode; // 67 UCHAR VendorUnique4; // 68 52 UCHAR DmaCycleTimingMode; // 69 USHORT TranslationFieldsValid : 1; // 6A 53 USHORT Reserved3 : 15; USHORT NumberOfCurrentCylinders; // 6C 54 USHORT NumberOfCurrentHeads; // 6E 55 USHORT CurrentSectorsPerTrack; // 70 56 ULONG CurrentSectorCapacity; // 72 57-58 USHORT CurrentMultiSectorSetting; // 59 ULONG UserAddressableSectors; // 60-61 USHORT SingleWordDMASupport : 8; // 62 USHORT SingleWordDMAActive : 8; USHORT MultiWordDMASupport : 8; // 63 USHORT MultiWordDMAActive : 8; USHORT AdvancedPIOModes : 8; // 64 USHORT Reserved4 : 8; USHORT MinimumMWXferCycleTime; // 65 USHORT RecommendedMWXferCycleTime; // 66 USHORT MinimumPIOCycleTime; // 67 USHORT MinimumPIOCycleTimeIORDY; // 68 USHORT Reserved5[2]; // 69-70 USHORT ReleaseTimeOverlapped; // 71 USHORT ReleaseTimeServiceCommand; // 72 USHORT MajorRevision; // 73 USHORT MinorRevision; // 74 USHORT Reserved6[50]; // 75-126 USHORT SpecialFunctionsEnabled; // 127 USHORT Reserved7[128]; // 128-255 } IDENTIFY_DATA, *PIDENTIFY_DATA; #pragma pack() // Required to ensure correct PhysicalDrive IOCTL structure setup #pragma pack(4) // // IOCTL_STORAGE_QUERY_PROPERTY // // Input Buffer: // a STORAGE_PROPERTY_QUERY structure which describes what type of query // is being done, what property is being queried for, and any additional // parameters which a particular property query requires. // // Output Buffer: // Contains a buffer to place the results of the query into. Since all // property descriptors can be cast into a STORAGE_DESCRIPTOR_HEADER, // the IOCTL can be called once with a small buffer then again using // a buffer as large as the header reports is necessary. // // // Types of queries // // // define some initial property id's // // // Query structure - additional parameters for specific queries can follow // the header // #define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) // // Device property descriptor - this is really just a rehash of the inquiry // data retrieved from a scsi device // // This may only be retrieved from a target device. Sending this to the bus // will result in an error // #pragma pack(4) // (* Output Bbuffer for the VxD (rt_IdeDinfo record) *) typedef struct _rt_IdeDInfo_ { BYTE IDEExists[4]; BYTE DiskExists[8]; WORD DisksRawInfo[8 * 256]; } rt_IdeDInfo, *pt_IdeDInfo; // (* IdeDinfo "data fields" *) typedef struct _rt_DiskInfo_ { BOOL DiskExists; BOOL ATAdevice; BOOL RemovableDevice; WORD TotLogCyl; WORD TotLogHeads; WORD TotLogSPT; char SerialNumber[20]; char FirmwareRevision[8]; char ModelNumber[40]; WORD CurLogCyl; WORD CurLogHeads; WORD CurLogSPT; } rt_DiskInfo; #define SENDIDLENGTH sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE #define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) class MasterHardDiskSerial { public: MasterHardDiskSerial(); ~MasterHardDiskSerial(); //int GetSerialNo(std::vector<char> &serialNumber); int GetSerialNo(char *SerialNumber); int GetErrorMessage(TCHAR *_ptszErrorMessage = NULL); private: char *ConvertToString(DWORD dwDiskdata[256], int iFirstIndex, int iLastIndex, char *pcBuf = NULL); BOOL DoIDENTIFY(HANDLE, PSENDCMDINPARAMS, PSENDCMDOUTPARAMS, BYTE, BYTE, PDWORD); int ReadPhysicalDriveInNTWithAdminRights(void); int ReadPhysicalDriveInNTUsingSmart(void); int ReadPhysicalDriveInNTWithZeroRights(void); int ReadIdeDriveAsScsiDriveInNT(void); char *flipAndCodeBytes(int iPos, int iFlip, const char *pcStr = NULL, char *pcBuf = NULL); void PrintIdeInfo(int iDrive, DWORD dwDiskdata[256]); long getHardDriveComputerID(); private: char m_cszHardDriveSerialNumber[1024]; char m_cszHardDriveModelNumber[1024]; char m_cszErrorMessage[256]; BYTE byIdOutCmd[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1]; }; #endif // _HDD_SERIAL_INFO_H_
4.实现文件:HardDriveSerialNumer.hpp
//#include "pch.h" //vs控制台项目自动生成 #include "HardDriveSerialNumer.hpp" #include <iostream> int MasterHardDiskSerial::ReadPhysicalDriveInNTWithAdminRights(void) { int iDone = FALSE; int iDrive = 0; for (iDrive = 0; iDrive < MAX_IDE_DRIVES; iDrive++) { HANDLE hPhysicalDriveIOCTL = 0; // Try to get a handle to PhysicalDrive IOCTL, report failure // and exit if can't. char cszDriveName[256]; sprintf_s(cszDriveName, 256, "\\.\PhysicalDrive%d", iDrive); // Windows NT, Windows 2000, must have admin rights hPhysicalDriveIOCTL = CreateFileA(cszDriveName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE) { SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage)); sprintf_s(m_cszErrorMessage, 256, "%d ReadPhysicalDriveInNTWithAdminRights ERROR ,CreateFileA(%s) returned INVALID_HANDLE_VALUE", __LINE__, cszDriveName); } else { GETVERSIONOUTPARAMS VersionParams; DWORD dwBytesReturned = 0; // Get the version, etc of PhysicalDrive IOCTL memset((void *)&VersionParams, 0, sizeof(VersionParams)); if (!DeviceIoControl(hPhysicalDriveIOCTL, DFP_GET_VERSION, NULL, 0, &VersionParams, sizeof(VersionParams), &dwBytesReturned, NULL)) { DWORD dwErr = GetLastError(); SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage)); sprintf_s(m_cszErrorMessage, 256, "%d ReadPhysicalDriveInNTWithAdminRights ERROR DeviceIoControl() %ld, DFP_GET_VERSION) returned 0, error is %d ", __LINE__, (long long)hPhysicalDriveIOCTL, (int)dwErr); } // If there is a IDE device at number "iI" issue commands // to the device if (VersionParams.bIDEDeviceMap <= 0) { SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage)); sprintf_s(m_cszErrorMessage, 256, "%d ReadPhysicalDriveInNTWithAdminRights ERROR No device found at iPosition %d (%d)", __LINE__, (int)iDrive, (int)VersionParams.bIDEDeviceMap); } else { BYTE bIDCmd = 0; // IDE or ATAPI IDENTIFY cmd SENDCMDINPARAMS scip; //SENDCMDOUTPARAMS OutCmd; // Now, get the ID sector for all IDE devices in the system. // If the device is ATAPI use the IDE_ATAPI_IDENTIFY command, // otherwise use the IDE_ATA_IDENTIFY command bIDCmd = (VersionParams.bIDEDeviceMap >> iDrive & 0x10) ? IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY; memset(&scip, 0, sizeof(scip)); memset(byIdOutCmd, 0, sizeof(byIdOutCmd)); if (DoIDENTIFY(hPhysicalDriveIOCTL, &scip, (PSENDCMDOUTPARAMS)&byIdOutCmd, (BYTE)bIDCmd, (BYTE)iDrive, &dwBytesReturned)) { DWORD dwDiskData[256]; int iIjk = 0; USHORT *punIdSector = (USHORT *)((PSENDCMDOUTPARAMS)byIdOutCmd)->bBuffer; for (iIjk = 0; iIjk < 256; iIjk++) dwDiskData[iIjk] = punIdSector[iIjk]; PrintIdeInfo(iDrive, dwDiskData); iDone = TRUE; } } CloseHandle(hPhysicalDriveIOCTL); } } return iDone; } int MasterHardDiskSerial::ReadPhysicalDriveInNTUsingSmart(void) { int iDone = FALSE; int iDrive = 0; for (iDrive = 0; iDrive < MAX_IDE_DRIVES; iDrive++) { HANDLE hPhysicalDriveIOCTL = 0; // Try to get a handle to PhysicalDrive IOCTL, report failure // and exit if can't. char cszDriveName[256]; sprintf_s(cszDriveName, 256, "\\.\PhysicalDrive%d", iDrive); // Windows NT, Windows 2000, Windows Server 2003, Vista hPhysicalDriveIOCTL = CreateFileA(cszDriveName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); // if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE) // printf ("Unable to open physical iDrive %d, error code: 0x%lX ", // iDrive, GetLastError ()); if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE) { SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage)); sprintf_s(m_cszErrorMessage, 256, "%d ReadPhysicalDriveInNTUsingSmart ERROR, CreateFileA(%s) returned INVALID_HANDLE_VALUE Error Code %d", __LINE__, cszDriveName, GetLastError()); } else { GETVERSIONINPARAMS GetVersionParams; DWORD dwBytesReturned = 0; // Get the version, etc of PhysicalDrive IOCTL memset((void *)&GetVersionParams, 0, sizeof(GetVersionParams)); if (!DeviceIoControl(hPhysicalDriveIOCTL, SMART_GET_VERSION, NULL, 0, &GetVersionParams, sizeof(GETVERSIONINPARAMS), &dwBytesReturned, NULL)) { DWORD dwErr = GetLastError(); SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage)); sprintf_s(m_cszErrorMessage, 256, " %d ReadPhysicalDriveInNTUsingSmart ERROR DeviceIoControl(%ld, SMART_GET_VERSION) returned 0, error is %d", __LINE__, (long long)hPhysicalDriveIOCTL, (int)dwErr); } else { // Print the SMART version // PrintVersion (& GetVersionParams); // Allocate the command cszBuffer ULONG CommandSize = sizeof(SENDCMDINPARAMS) + IDENTIFY_BUFFER_SIZE; PSENDCMDINPARAMS Command = (PSENDCMDINPARAMS)malloc(CommandSize); // Retrieve the IDENTIFY data // Prepare the command #define ID_CMD 0xEC // Returns ID sector for ATA Command->irDriveRegs.bCommandReg = ID_CMD; DWORD BytesReturned = 0; if (!DeviceIoControl(hPhysicalDriveIOCTL, SMART_RCV_DRIVE_DATA, Command, sizeof(SENDCMDINPARAMS), Command, CommandSize, &BytesReturned, NULL)) { SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage)); sprintf_s(m_cszErrorMessage, 256, "SMART_RCV_DRIVE_DATA IOCTL"); // Print the error //PrintError ("SMART_RCV_DRIVE_DATA IOCTL", GetLastError()); } else { // Print the IDENTIFY data DWORD dwDiskData[256]; USHORT *punIdSector = (USHORT *)(PIDENTIFY_DATA)((PSENDCMDOUTPARAMS)Command)->bBuffer; for (int iIjk = 0; iIjk < 256; iIjk++) dwDiskData[iIjk] = punIdSector[iIjk]; PrintIdeInfo(iDrive, dwDiskData); iDone = TRUE; } // Done CloseHandle(hPhysicalDriveIOCTL); free(Command); } } } return iDone; } char *MasterHardDiskSerial::flipAndCodeBytes(int iPos, int iFlip, const char *pcszStr, char *pcszBuf) { int iI; int iJ = 0; int iK = 0; pcszBuf[0] = '