• C/C++ 实现获取硬盘序列号


    获取硬盘的序列号、型号和固件版本号,此类功能通常用于做硬盘绑定或硬件验证操作,通过使用Windows APIDeviceIoControl函数与物理硬盘驱动程序进行通信,发送ATA命令来获取硬盘的信息。

    以下是该程序的主要功能和流程:

    定义常量 IDE_ATAPI_IDENTIFYIDE_ATA_IDENTIFY 分别表示读取 ATAPI 设备和 ATA 设备信息的命令。

    • 实现 Trim 函数,用于去除字符串首尾的空格。
    • 实现 ConvertToString 函数,用于将 DWORD 数组转换为字符串,并通过 Trim 函数去除首尾空格。
    • 实现 DoIdentify 函数,该函数通过 DeviceIoControl 发送 SMART 命令,获取硬盘的详细信息。
    • 实现 GetDiskInfo 函数,该函数打开物理硬盘设备,并调用 DoIdentify 获取硬盘序列号、型号和固件版本号。

    main 函数中,通过调用 GetDiskInfo 获取硬盘信息,并输出到控制台。

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    #include 
    #include 
    
    const WORD IDE_ATAPI_IDENTIFY = 0xA1;   // 读取ATAPI设备的命令
    const WORD IDE_ATA_IDENTIFY = 0xEC;     // 读取ATA设备的命令
    
    // 去除字符串首尾的空格
    BOOL Trim(char* szStr)
    {
      int i = 0, j = 0, iFirst = -1, iLast = -1;
      int iLen = strlen(szStr);
      char szTemp[256] = { 0 };
      
      // 从前往后遍历,获取第一个不为 空格 的下标
      for (i = 0; i < iLen; i++)
      {
        if (' ' != szStr[i])
        {
          iFirst = i;
          break;
        }
      }
      
      // 从后往前遍历,获取第一个不为 空格 的下标
      for (i = (iLen - 1); 0 <= i; i--)
      {
        if (' ' != szStr[i])
        {
          iLast = i;
          break;
        }
      }
      
      // 字符串全为 空格
      if (-1 == iFirst || -1 == iLast)
      {
        return FALSE;
      }
      
      // 获取去除 空格 部分
      for (i = iFirst; i <= iLast; i++)
      {
        szTemp[j] = szStr[i];
        j++;
      }
      szTemp[j] = '\0';
      strcpy(szStr, szTemp);
    
      return TRUE;
    }
    
    // 数据转换
    char* __fastcall ConvertToString(DWORD dwDiskData[256],int iFirstIndex,int iLastIndex)
    {
      static char szResBuf[256];
      int iIndex = 0;
      int iPosition = 0;
    
      for (iIndex = iFirstIndex; iIndex <= iLastIndex; iIndex++)
      {
        szResBuf[iPosition] = (char)(dwDiskData[iIndex] / 256);
        iPosition++;
        
        // Get low BYTE for 2nd character
        szResBuf[iPosition] = (char)(dwDiskData[iIndex] % 256);
        iPosition++;
      }
      szResBuf[iPosition] = '\0';
    
      // 删除首尾的空格
      Trim(szResBuf);
      return szResBuf;
    }
    
    BOOL __fastcall DoIdentify(HANDLE hPhysicalDriveIOCTL,PSENDCMDINPARAMS pSCIP,PSENDCMDOUTPARAMS pSCOP,BYTE btIDCmd,BYTE btDriveNum,PDWORD pdwBytesReturned)
    {
      pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE;
      pSCIP->irDriveRegs.bFeaturesReg = 0;
      pSCIP->irDriveRegs.bSectorCountReg = 1;
      pSCIP->irDriveRegs.bSectorNumberReg = 1;
      pSCIP->irDriveRegs.bCylLowReg = 0;
      pSCIP->irDriveRegs.bCylHighReg = 0;
      pSCIP->irDriveRegs.bDriveHeadReg = (btDriveNum & 1) ? 0xB0 : 0xA0;
      pSCIP->irDriveRegs.bCommandReg = btIDCmd;
      pSCIP->bDriveNumber = btDriveNum;
    
      return DeviceIoControl(hPhysicalDriveIOCTL,SMART_RCV_DRIVE_DATA,(LPVOID)pSCIP,sizeof(SENDCMDINPARAMS) - 1,
        (LPVOID)pSCOP,sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,pdwBytesReturned,NULL);
      return FALSE;
    }
    
    int GetDiskInfo(int iDriver, char* szSerialNumber, char* szModelNumber, char* szFirmwareNumber)
    {
      char szFilePath[64] = { 0 };
      sprintf(szFilePath, "\\\\.\\PHYSICALDRIVE%d", iDriver);
    
      // 打开设备
      HANDLE hFile = CreateFileA(szFilePath,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
      if (INVALID_HANDLE_VALUE == hFile)
      {
        return -1;
      }
    
      // 发送控制代码到指定设备驱动程序
      DWORD dwBytesReturned = 0;
      GETVERSIONINPARAMS gvopVersionParam;
      DeviceIoControl(hFile,SMART_GET_VERSION,NULL,0,&gvopVersionParam,sizeof(gvopVersionParam),&dwBytesReturned,NULL);
      if (0 >= gvopVersionParam.bIDEDeviceMap)
      {
        return -2;
      }
    
      // IDE or ATAPI IDENTIFY cmd
      unsigned int uiIDCmd = 0;
      SENDCMDINPARAMS InParams;
      unsigned int uiDrive = 0;
      uiIDCmd = (gvopVersionParam.bIDEDeviceMap >> uiDrive & 0x10) ? IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;
    
      // 输出参数
      BYTE btOutCmd[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];
      if (FALSE == DoIdentify(hFile,&InParams,(SENDCMDOUTPARAMS*)btOutCmd,(BYTE)uiIDCmd,(BYTE)uiDrive,&dwBytesReturned))
      {
        return -3;
      }
    
      // 关闭设备
      CloseHandle(hFile);
    
      DWORD dwDiskData[256];
      USHORT* pIDSector = NULL;
      
      // 对应结构IDSECTOR 见头文件
      pIDSector = (USHORT*)((SENDCMDOUTPARAMS*)btOutCmd)->bBuffer;
      for (int i = 0; i < 256; i++)
      {
        dwDiskData[i] = pIDSector[i];
      }
    
      // 获取序列号
      strcpy(szSerialNumber, ConvertToString(dwDiskData, 10, 19));
    
      // 获取型号
      strcpy(szModelNumber, ConvertToString(dwDiskData, 27, 46));
    
      // 获取固件版本号
      strcpy(szFirmwareNumber, ConvertToString(dwDiskData, 23, 26));
    
      return 0;
    }
    
    int main(int argc,char *argv[])
    {
      char SerialNumber[64];          // 硬盘序列号
      char ModelNumber[64];           // 硬盘型号
      char FirmwareNumber[64];        // 硬盘固件版本号
    
      if (0 == GetDiskInfo(0, SerialNumber, ModelNumber, FirmwareNumber))
      {
        std::cout << "序列号: " << SerialNumber << std::endl;
        std::cout << "硬盘型号: " << ModelNumber << std::endl;
        std::cout << "固件版本:" << FirmwareNumber << std::endl;
      }
    
      system("pause");
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169

    输出效果;

  • 相关阅读:
    USB电路详细设计
    机房设备如何把关?学会这个技巧
    389.找不同
    Django REST Framework完整教程-认证与权限-JWT的使用
    Cat Online Judge 判题系统
    AWS攻略——一文看懂AWS IAM设计和使用
    【MUDUO 】Channel通道
    【LeetCode热题100】--215.数组中的第K个最大元素
    java毕业设计在线民宿预定系统Mybatis+系统+数据库+调试部署
    Linux驱动开发(九)---树莓派I2C设备驱动开发(BME280)
  • 原文地址:https://blog.csdn.net/lyshark_csdn/article/details/134437180