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

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

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

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

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

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

输出效果;

C/C++ 实现获取硬盘序列号的更多相关文章

  1. java通过jni方式获取硬盘序列号(windows,linux)

    linux系统java通过jni方式获取硬盘序列号 http://blog.csdn.net/starter110/article/details/8186788 使用jni在windows下读取硬盘 ...

  2. delphi 获取硬盘序列号、cpu号、bios号、网卡号

    delphi 获取硬盘 序列号 function GetIdeNum: String; type TSrbIoControl = packed record HeaderLength : ULONG; ...

  3. 获取硬盘序列号的Fortran程序

    以前写了个获取硬盘序列号的fortran程序,但未经实证 program FortranDemo Use Kernel32 Implicit None Interface SUBROUTINE Get ...

  4. vc 获取 硬盘序列号 和 cpu

    vc 获取 硬盘序列号 和 cpu 唯一iD的方法?如题---------网上找来很多资料 也没找到, 要支持xp win7 32/64 系统下都能获取 硬盘序列号 和cpu ID 哪位朋友帮帮忙: ...

  5. c/c++获取硬盘序列号

    最近在接触软件注册模块,需要获取硬盘序列号来生成注册码. 硬盘序列号,英文名:Hard Disk Serial Number,该号是硬盘厂家为区别产品而设置的,是唯一的.网上搜索一下,发现获取硬盘序列 ...

  6. Windows 下获取硬盘序列号

    只获取序列号 以下任意一条命令都可以: wmic diskdrive get serialnumber wmic path win32_physicalmedia get SerialNumber w ...

  7. 在windows下获取硬盘序列号(win7 32位,Windows Server 64位测试,希望在其他平台测试,遇到问题的网友留言分享)

    #include <Windows.h> #include <stdio.h> // IOCTL控制码 // #define DFP_SEND_DRIVE_COMMAND CT ...

  8. C#获取硬盘序列号

    //创建ManagementObjectSearcher对象 ManagementObjectSearcher searcher = new ManagementObjectSearcher(&quo ...

  9. DOS 获取硬盘序列号

    DOS命令行操作: 使用diskpart命令,Win+R键运行cmd,进入命令行界面:       1.diskpart       2.list disk 查看有几块硬盘       3.selec ...

  10. C#获取硬盘序列号的问题求助

    具体问题是这样的:我用下面这段获取硬盘型信息的代码做成的exe文件,在机子上测试的时候,出现直接双击运行和用管理员身份运行结果不一样的情况,这个问题该怎么解决? public static Strin ...

随机推荐

  1. OKR之剑·实战篇06:OKR致胜法宝-氛围&业绩双轮驱动(下)

    作者:vivo 互联网平台产品研发团队 本文是<OKR 之剑>系列之实战第 6 篇-- 本文介绍团队营造氛围的方法与实践.在业绩方面的探索与输出,在两方面分别总结了一些经验分享给大家. 一 ...

  2. 12、SpringBoot-mybatis-plus-ehcache

    系列导航 springBoot项目打jar包 1.springboot工程新建(单模块) 2.springboot创建多模块工程 3.springboot连接数据库 4.SpringBoot连接数据库 ...

  3. vue路由模块化

    https://www.bilibili.com/video/BV1Tg411u7oy?from=search&seid=5098139115981575542&spm_id_from ...

  4. 一套前后台全部开源的H5商城送给大家

    博主给大家推荐一套全部开源的H5电商项目waynboot-mall.由博主在2020年开发至今,已有三年之久.那时候网上很多的H5商城项目都是半开源版本,要么没有H5前端代码,要么需要加群咨询,属实恶 ...

  5. OpenShift image registry 访问镜像

    1. OpenShift 内部 image registry Openshift 自带内部 image registry,可通过 podman 实现 image 的 pull 和 push 操作. 对 ...

  6. Dubbo入门1:Spirngboot+Dubbo2.6.0整合

    整合springboot+dubbo2.6.0 demo 本文简要说明了springboot和dubbo整合的配置文件的写法 目录结构 整体目录 如下图所示:整体项目是一个父子工程,common作为一 ...

  7. [转帖]深度硬核文:Nginx的301重定向处理过程分析

    https://zhuanlan.zhihu.com/p/84539204 本文首发于公众号:js-mindmap 一,序言 "晚上九点,办公室里烟雾缭绕,工作进度依然没有什么进展.王二胖打 ...

  8. [转帖]PolarDB和Oceanbase的区别和联系

    PolarDB-X 和 OceanBase 都是阿里云提供的分布式关系型数据库产品,它们都具有高可用.高性能.分布式等特点.但是两者也存在一些差异. 数据库理论基础不同 PolarDB-X 基于传统的 ...

  9. [转帖]配置cri-docker使kubernetes1.24以docker作为运行时

    从kubernetes 1.24开始,dockershim已经从kubelet中移除,但因为历史问题docker却不支持kubernetes主推的CRI(容器运行时接口)标准,所以docker不能再作 ...

  10. Oracledb_exporter 获取表大小信息的简单方法

    Oracledb_exporter 获取表大小信息的简单方法 背景 用我儿子的现状作为背景: 我爱学习, 学习让我妈快乐. 下载exporter exporter 可以在github上面下载最新版本是 ...