C/C++实现获取硬盘序列号的示例代码

 更新时间:2023年11月17日 08:59:27   作者:lyshark  
获取硬盘的序列号、型号和固件版本号,此类功能通常用于做硬盘绑定或硬件验证操作,下面我们就来学习一下如何使用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 <windows.h>
#include <iostream>
#include <winioctl.h>
#include <string>

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;
}

输出效果:

到此这篇关于C/C++实现获取硬盘序列号的示例代码的文章就介绍到这了,更多相关C++获取硬盘序列号内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言图书管理系统课程设计

    C语言图书管理系统课程设计

    这篇文章主要为大家详细介绍了C语言图书管理系统课程设计,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • c语言实现含递归清场版扫雷游戏

    c语言实现含递归清场版扫雷游戏

    扫雷大家应该都玩过,这是一个十分经典的游戏,下面这篇文章主要给大家介绍了关于c语言实现含递归清场版扫雷游戏的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-11-11
  • C语言实现扫雷游戏详细代码

    C语言实现扫雷游戏详细代码

    这篇文章主要为大家详细介绍了C语言实现扫雷游戏的具体步骤和详细代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • C++模板实现顺序栈

    C++模板实现顺序栈

    这篇文章主要为大家详细介绍了C++模板实现顺序栈,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • C语言实现数独游戏的求解

    C语言实现数独游戏的求解

    这篇文章主要为大家详细介绍了C语言实现数独游戏的求解,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • Qt正则表达式使用举例

    Qt正则表达式使用举例

    这篇文章主要给大家介绍了关于Qt正则表达式使用的相关资料,Qt中的正则表达式模式匹配功能由QRegExp类实现,它完全支持Unicode,并可以应用于字符串验证、搜索、查找替换和分割等场景,需要的朋友可以参考下
    2024-02-02
  • C++11 并发指南之多线程初探

    C++11 并发指南之多线程初探

    这篇文章主要介绍了C++11 并发指南之多线程初探,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • C++中按引用传递参数的好处有哪些

    C++中按引用传递参数的好处有哪些

    这篇文章主要介绍了C++中按引用传递参数的好处有哪些,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • C++中指针函数与函数指针的使用

    C++中指针函数与函数指针的使用

    今天小编就为大家分享一篇关于C++中指针函数与函数指针的使用,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • C语言详解float类型在内存中的存储方式

    C语言详解float类型在内存中的存储方式

    在c语言中float函数是单精度的。它在内存中以二进制的形式存储。分为符号位,阶码与尾数三部分,下面我们详细来了解一下
    2022-04-04

最新评论