C/C++ 实现获取硬盘序列号
获取硬盘的序列号、型号和固件版本号,此类功能通常用于做硬盘绑定或硬件验证操作,通过使用Windows API的DeviceIoControl函数与物理硬盘驱动程序进行通信,发送ATA命令来获取硬盘的信息。
以下是该程序的主要功能和流程:
定义常量 IDE_ATAPI_IDENTIFY 和 IDE_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++ 实现获取硬盘序列号的更多相关文章
- java通过jni方式获取硬盘序列号(windows,linux)
linux系统java通过jni方式获取硬盘序列号 http://blog.csdn.net/starter110/article/details/8186788 使用jni在windows下读取硬盘 ...
- delphi 获取硬盘序列号、cpu号、bios号、网卡号
delphi 获取硬盘 序列号 function GetIdeNum: String; type TSrbIoControl = packed record HeaderLength : ULONG; ...
- 获取硬盘序列号的Fortran程序
以前写了个获取硬盘序列号的fortran程序,但未经实证 program FortranDemo Use Kernel32 Implicit None Interface SUBROUTINE Get ...
- vc 获取 硬盘序列号 和 cpu
vc 获取 硬盘序列号 和 cpu 唯一iD的方法?如题---------网上找来很多资料 也没找到, 要支持xp win7 32/64 系统下都能获取 硬盘序列号 和cpu ID 哪位朋友帮帮忙: ...
- c/c++获取硬盘序列号
最近在接触软件注册模块,需要获取硬盘序列号来生成注册码. 硬盘序列号,英文名:Hard Disk Serial Number,该号是硬盘厂家为区别产品而设置的,是唯一的.网上搜索一下,发现获取硬盘序列 ...
- Windows 下获取硬盘序列号
只获取序列号 以下任意一条命令都可以: wmic diskdrive get serialnumber wmic path win32_physicalmedia get SerialNumber w ...
- 在windows下获取硬盘序列号(win7 32位,Windows Server 64位测试,希望在其他平台测试,遇到问题的网友留言分享)
#include <Windows.h> #include <stdio.h> // IOCTL控制码 // #define DFP_SEND_DRIVE_COMMAND CT ...
- C#获取硬盘序列号
//创建ManagementObjectSearcher对象 ManagementObjectSearcher searcher = new ManagementObjectSearcher(&quo ...
- DOS 获取硬盘序列号
DOS命令行操作: 使用diskpart命令,Win+R键运行cmd,进入命令行界面: 1.diskpart 2.list disk 查看有几块硬盘 3.selec ...
- C#获取硬盘序列号的问题求助
具体问题是这样的:我用下面这段获取硬盘型信息的代码做成的exe文件,在机子上测试的时候,出现直接双击运行和用管理员身份运行结果不一样的情况,这个问题该怎么解决? public static Strin ...
随机推荐
- (error) MOVED 12706 10.176.246.204:9736
使用redis-cli连接上redis后,执行get命令报错: (error) MOVED 12706 10.176.246.204:9736 百度到原因是未以集群模式连接,在连接时加上-c参数就可以 ...
- confiparse遇到特殊字符的解析处理
一.背景:confiparse类解析mysql密码时发现包含特殊字符时出现报错的情况:配置文件如下: 代码如下: import configparser import os #读取配置 conf=co ...
- ASIC 功能验证VTB
目标 设计流程 验证设计文档和RTL code之间的关系 RTL code(DUT) - 可以当作是一个黑盒,DUT内部是完全不可见的 白盒验证 - DUT内部RTL完全可见 灰盒验证 - DUT内部 ...
- 03-Shell环境变量深入
1. 自定义系统环境变量 1.1 全局配置文件/etc/profile应用场景 当前用户进入Shell环境初始化的时候会加载全局配置文件/etc/profile里面的环境变量, 供给所有Shell程序 ...
- 【MMC子系统】 二、EMMC协议
[MMC子系统] 二.EMMC协议 1.前言 在上一节,我们知道EMMC.SD.SDIO三种规范都是在MMC规范之上发展而来,协议相差不大,所以Linux Kernel才能使用MMC子系统来统一管理! ...
- 【面试题精讲】你知道MySQL中有哪些隔离级别吗
有时博客内容会有变动,首发博客是最新的,其他博客地址可能未同步,请认准https://blog.zysicyj.top 首发博客地址 系列文章地址 脏读(Dirty Read)是指一个事务读取到了另一 ...
- Oracle 专用模式与共享模式的学习与思考
Oracle 专用模式与共享模式的学习与思考 说明 Oracle数据库中的专用模式和共享模式是两种不同的数据库运行模式,它们在应用场景和权限管理上有所不同. 专用模式(Dedicated Mode): ...
- Tidb 使用minio 进行br备份数据库的过程
Tidb 使用minio 进行br备份数据库的过程 背景 br 备份恢复时一般需要共享存储. 前段时间一直使用的是nfs 进行共享文件备份. 这样需要所有的机器在 相同的目录下面挂载相同的nfs. 并 ...
- [转帖]金仓数据库KingbaseES表空间(tablespace)知多少
金仓数据库KingbaseES表空间定义 金仓数据库KingbaseES中的表空间允许在文件系统里定义那些代表数据库对象的文件存放位置,比如表和索引等.一旦表空间被创建,那么就可以在创建数据库对象时通 ...
- [转帖]py_innodb_page_info.py工具使用
目录 一.Linux安装Python3 1. 解压包 2. 安装环境 3. 生成编译脚本 4. 检查python3.10的编译器 5. 建立Python3和pip3的软链 6. 添加到PATH 7. ...