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

输出效果;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/151742.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 Redis 构建轻量的向量数据库应用:图片搜索引擎(二)

本篇文章我们来继续聊聊轻量的向量数据库方案&#xff1a;Redis&#xff0c;如何完成整个图片搜索引擎功能。 写在前面 在上一篇文章《使用 Redis 构建轻量的向量数据库应用&#xff1a;图片搜索引擎&#xff08;一&#xff09;》中&#xff0c;我们聊过了构建图片搜索引擎的…

深度学习入门(第二天)——走进深度学习的世界 神经网络模型

反向传播计算方法 简单的例子&#xff1a; 如何让 f 值更小&#xff0c;就是改变x、y、z&#xff0c;而损失函数也是这样&#xff0c;那么我们分别求偏导&#xff0c;则能得出每个值对结果的影响 链式法则 梯度是一步一步传的 复杂的例子&#xff1a; 神经网络整体架构 类生…

浪涌防护器件要选对,布局布线更重要!|深圳比创达电子EMC(上)

浪涌测试&#xff0c;作为最常见的EMC抗干扰测试项目之一&#xff0c;基本上是家用消费电子必测的项目&#xff1b;其测试目的是为了验证产品在承受外部的浪涌冲击时能否正常工作。 一、浪涌冲击产生机理及其防护设计 浪涌冲击主要包括雷击浪涌冲击、电力系统内部的开关噪声冲…

假如我是AI Agent专家,你会问什么来测试我的水平

1. 假如我是AI Agent专家&#xff0c;你会问什么来测试我的水平 作为AI Agent专家&#xff0c;您可能需要回答一系列关于AI代理的设计、实现和优化方面的问题。以下是一些可能的问题&#xff1a; AI代理的基本原理&#xff1a;AI代理的基本工作原理是什么&#xff1f;它们如何…

requests库进行HTTP请求时,有时需要传递cookies参数

在使用requests库进行HTTP请求时&#xff0c;有时需要传递cookies参数。但是&#xff0c;requests库的cookies参数只能接受CookieJar对象&#xff0c;而不能接受字典等其他类型的cookies。 在requests库中增加对字典类型的cookies支持&#xff0c;使其能够接受字典类型的cooki…

linux高级篇基础理论二(详细文档、LAMP、SHELL、sed正则表达式)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xff1a;云计算技…

Coder OSS Enterprise 2.3.3 Crack

Coder OSS Enterprise是一个开源开发平台&#xff0c;旨在简化开发人员的编码流程。该平台专为企业级组织设计&#xff0c;具有针对大规模软件开发运营量身定制的功能。 首先&#xff0c;该软件提供了一个云环境&#xff0c;允许开发人员在任何地方使用任何设备处理他们的代码。…

Vue中el与data的两种写法

想必大家对Vue中的el与data并不陌生&#xff0c;接下来&#xff0c;让我为大家介绍一下el与data的两种写法吧&#xff01; 一、el的两种写法 1.new Vue时候配置e1属性。 2.先创建Vue实例&#xff0c;随后再通过vm.$mount(#root)指定el的值 <!DOCTYPE html> <html l…

结构工程师软件 Naviate Core MEP for Revit 3.4 Crk

Naviate Fabrication - 先进的建模和制造命令&#xff0c;可提高 VDC 设计师、细节设计师和承包商的生产力和收入。 Naviate MEP - 通过 MEP 工程师和设计师的建模和参数提高效率 导航架构 Naviate Architecture 完全集成到 Revit 平台中&#xff0c;增强了 BIM 提供的协作可能…

工业除尘器笔记

工业除尘器用于对工业生产产生的有害气体和粉尘进行吸附。相关标准的制定最早可以追溯到1960年代以前。注意&#xff0c;本文的附录包含一起完整的工业除尘器事故的分析和定责过程。相关事故分析定责文档源头摘自上海市政府网站。 在产品设计行业和关联下游行业&#xff0c;在…

java--俄罗斯方块

一、先看一下游戏运行时的画面 二、代码部分 1. Cell.java Cell.java&#xff1a; package demo1;import java.awt.image.BufferedImage; import java.util.Objects;/* 编写小方块类属性&#xff1a;行、列、每个小方格的图片方法&#xff1a;左移一格、右移一格、下落一格 …

【 云原生 | K8S 】kubeadm 部署Kubernetes集群

目录 1 环境准备 2 所有节点安装docker 3 所有节点安装kubeadm&#xff0c;kubelet和kubectl 4 部署K8S集群 4.1 查看初始化需要的镜像 4.2 初始化kubeadm 4.3 设定kubectl 4.4 所有节点部署网络插件flannel master&#xff08;2C/4G&#xff0c;cpu核心数要求大于2&am…

第一讲之递归与递推下篇

第一讲之递归与递推下篇 带分数费解的开关飞行员兄弟翻硬币 带分数 用暴力将所有全排列的情况都算出来 > 有三个数&#xff0c;a,b,c 每种排列情况&#xff0c;可以用两层for循环&#xff0c;暴力分为三个部分&#xff0c;每个部分一个数 当然注意这里&#xff0c;第一层fo…

Linux常用命令——bzdiff命令

在线Linux命令查询工具 bzdiff 直接比较两个.bz2压缩包中文件的不同 补充说明 bzdiff命令用于直接比较两个“.bz2”压缩包中文件的不同&#xff0c;省去了解压缩后再调用diff命令的过程。 语法 bzdiff(参数)参数 文件1&#xff1a;指定要比较的第一个.bz2压缩包&#xf…

《洛谷深入浅出基础篇》P1536 村村通——并查集

上链接&#xff1a;P1536 村村通 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1536 上题干&#xff1a; 题目描述 某市调查城镇交通状况&#xff0c;得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府 "村村通工程…

全民运动时代,气膜建筑备受瞩目

气膜体育场馆&#xff0c;作为当今新型的临时建筑运动场馆&#xff0c;在满足大型体育赛事需求方面展现出显著的优势。相较于传统体育场馆&#xff0c;气膜建筑不仅拥有更宽敞的空间&#xff0c;而且造价成本更为经济&#xff0c;成为体育场馆领域备受关注的建筑形式。 气膜建筑…

郑州市管城区工信局局长任华民一行莅临中创算力调研指导工作

2023年11月15日&#xff0c;为深入了解企业生产经营情况&#xff0c;解决发展诉求。郑州市管城区工信局局长任华民等领导一行莅临中创算力&#xff0c;中创副总经理杨光、技术总监刘朝阳、行政主管生田等人员陪同调研。 调研期间&#xff0c;双方就生产经营、“算力数据中心”…

基于SSM的校园二手物品交易市场设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

界面组件DevExpress Reporting v23.1亮点 - 全新升级报表查看器

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表 界面组件DevExpress Reporting v23.1已经发布一段…

如何快速找到华为手机中下载的文档

手机的目录设置比较繁杂&#xff0c;尤其是查找刚刚下载的文件&#xff0c;有时候需要捣鼓半天&#xff0c;如何快速找到这些文件呢&#xff1f;以下提供了几种方法&#xff1a; 方法一&#xff1a; 文件管理-》搜索文档 方法二&#xff1a; 文件管理-》最近 方法三&#xf…