获取硬盘的序列号、型号和固件版本号,此类功能通常用于做硬盘绑定或硬件验证操作,通过使用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++ 实现获取硬盘序列号的更多相关文章

  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. 100天搞定机器学习|Day59 主成分分析(PCA)原理及使用详解

    数学概念 方差:用来衡量随机变量与其数学期望(均值)之间的偏离程度.统计中的方差(样本方差)是各个数据分别与其平均数之差的平方的和的平均数. $$Var(X)=\frac{1}{n}\sum(x_i- ...

  2. 【每日一题】36. 小AA的数列 (二进制DP)

    补题链接:Here 算法涉及:位运算,DP 这道题想了很久但实在没想什么巧妙的解法,暴力的代码就不放,这里引用Kur1su 的思路 异或问题优先考虑二进制位,对于这个问题,我们需要考虑偶数长度的区间, ...

  3. 第九届蓝桥杯(2018)C/C++大学A组省赛题解

    第一题:分数 1/1 + 1/2 + 1/4 + 1/8 + 1/16 + - 每项是前一项的一半,如果一共有20项, 求这个和是多少,结果用分数表示出来. 类似:3/2 当然,这只是加了前2项而已. ...

  4. 图解 Promise 实现原理(二)—— Promise 链式调用

    本文首发于 vivo互联网技术 微信公众号 链接: https://mp.weixin.qq.com/s/Xz2bGaLxVL4xw1M2hb2nJQ作者:Morrain 很多同学在学习 Promis ...

  5. kafka集群三、增加密码验证

    系列导航 一.kafka搭建-单机版 二.kafka搭建-集群搭建 三.kafka集群增加密码验证 四.kafka集群权限增加ACL 五.kafka集群__consumer_offsets副本数修改 ...

  6. Object.defineProperty()实现双向数据绑定

    <div id="app"> <input type="text" name="txt" id="txt&quo ...

  7. Angular系列教程之组件

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  8. solr-es

    一.lucene 1.是什么 是apache提供的一套java写的用于全文检索工具包,该工具包提供了用于实现全文检索的api类,可用于实现搜索引擎功能. 2.搜索常用方法 顺序扫描法:应用于数据结构固 ...

  9. [转帖]ESX/ESXi 主机上的每个插槽中安装了多少内存

    https://www.cnblogs.com/reachos/p/11242302.html 要确定在 ESX/ESXi 主机上的每个插槽中安装了多少内存,请执行以下操作: 1. 启动ssh服务 2 ...

  10. Grafana监控minio的极简方法

    Grafana监控minio的极简方法 背景 想监控一下minio的部分信息. 使用过程中需要关注的内容挺多的. 只看简单的node感觉已经不够了. 所以想监控易一下. 方式和方法 minio其实集成 ...