VC6获取硬盘序列号、型号、修订版本号

因为要做个读取硬盘参数信息的控件,所以在网上找了不少代码,但是自己作为一个初学者在使用别人代码时,总会发现有各种各样的问题:

1. 需要的头文件未写明

2. 有些定义未给出

3. 代码的开发环境未明,导致编译时出现“XXXX“未定义

3. 添加的代码写在哪里不明确

以上这些情况对于初学者是很容易遇到的,所以这里整理了下。

以下是“读取硬盘序列号、型号、修订版本号”的完整代码(win32 C++控制台程序),开发环境:win XP SP2 + VC6.0

头文件:Struct_Def.h

// 其实以下的定义多数是来自高版本VC(我机器上是VS2010)的头文件:C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include\WinIoCtl.h
typedef struct _DRIVERSTATUS {
BYTE     bDriverError;           // Error code from driver,
// or 0 if no error.
BYTE     bIDEError;                      // Contents of IDE Error register.
// Only valid when bDriverError
// is SMART_IDE_ERROR.
BYTE     bReserved[2];           // Reserved for future expansion.
DWORD   dwReserved[2];          // Reserved for future expansion.
} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;
typedef struct _IDEREGS {
BYTE     bFeaturesReg;           // Used for specifying SMART "commands".
BYTE     bSectorCountReg;        // IDE sector count register
BYTE     bSectorNumberReg;       // IDE sector number register
BYTE     bCylLowReg;             // IDE low order cylinder value
BYTE     bCylHighReg;            // IDE high order cylinder value
BYTE     bDriveHeadReg;          // IDE drive/head register
BYTE     bCommandReg;            // Actual IDE command.
BYTE     bReserved;              // reserved for future use.  Must be zero.
} IDEREGS, *PIDEREGS, *LPIDEREGS;
typedef struct _SENDCMDOUTPARAMS {
DWORD                   cBufferSize;            // Size of bBuffer in bytes
DRIVERSTATUS            DriverStatus;           // Driver status structure.
BYTE                    bBuffer[1];             // Buffer of arbitrary length in which to store the data read from the                                                                                  // drive.
} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;
typedef struct _SENDCMDINPARAMS {
DWORD   cBufferSize;            // Buffer size in bytes
IDEREGS irDriveRegs;            // Structure with drive register values.
BYTE     bDriveNumber;           // Physical drive number to send
// command to (0,1,2,3).
BYTE     bReserved[3];           // Reserved for future expansion.
DWORD   dwReserved[4];          // For future use.
BYTE     bBuffer[1];                     // Input buffer.
} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;
typedef struct _GETVERSIONINPARAMS {
BYTE     bVersion;               // Binary driver version.
BYTE     bRevision;              // Binary driver revision.
BYTE     bReserved;              // Not used.
BYTE     bIDEDeviceMap;          // Bit map of IDE devices.
DWORD   fCapabilities;          // Bit mask of driver capabilities.
DWORD   dwReserved[4];          // For future use.
} GETVERSIONINPARAMS, *PGETVERSIONINPARAMS, *LPGETVERSIONINPARAMS;
#define SMART_GET_VERSION               CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
#define SMART_RCV_DRIVE_DATA            CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define DFP_SEND_DRIVE_COMMAND SMART_SEND_DRIVE_COMMAND
#define GETVERSIONOUTPARAMS GETVERSIONINPARAMS
#define DFP_RCV_DRIVE_DATA SMART_RCV_DRIVE_DATA
#define DFP_GET_VERSION SMART_GET_VERSION
#define IDENTIFY_BUFFER_SIZE        512


主程序:m.cpp

/*
功能:VC6获取硬盘序列号、型号、修订版本号
*/
#include <iostream>
#include <windows.h>
#include <winioctl.h>
#include "Struct_Def.h"
using namespace std;
const WORD IDE_ATAPI_IDENTIFY = 0xA1;		//读取ATAPI设备的命令
const WORD IDE_ATA_IDENTIFY = 0xEC;			//读取ATA设备的命令
const int MAX_IDE_DRIVES = 1;				//最多IDE设备数
string Trim(string str)				// cut off leading and tailing blanks
{
string::size_type pos = str.find_last_not_of(' ');
if(pos != string::npos)
{
str.erase(pos + 1);
pos = str.find_first_not_of(' ');
if(pos != string::npos) 
str.erase(0, pos);
}
else 
str.erase(str.begin(), str.end());
return str;
}
// fetch characters what we need from DiskData[FirstIndex ... LastIndex]
string __fastcall ConvertToString(DWORD DiskData[256], int FirstIndex, int LastIndex)
{
int i = 0;
char ResBuf[1024] = {0};
for(char *p = (char*)(DiskData + FirstIndex); p <= (char*)(DiskData + LastIndex); p += sizeof(DiskData))
{
ResBuf[i++] = *(p+1);
ResBuf[i++] = *p;
}
return Trim(ResBuf);			// cut off leading and tailing blanks
}
BOOL __fastcall DoIdentify(HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP, PSENDCMDOUTPARAMS pSCOP, byte bIDCmd, byte bDriveNum, PDWORD lpcbBytesReturned)
{
// Set up data structures for IDENTIFY command.
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;
//Compute the drive number.(主盘和从盘所对应的值是不一样的)
pSCIP->irDriveRegs.bDriveHeadReg = (bDriveNum & 1) ? 0xB0 : 0xA0;
// The command can either be IDE identify or ATAPI identify.
pSCIP->irDriveRegs.bCommandReg = bIDCmd;
pSCIP->bDriveNumber = bDriveNum;
pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE;
return DeviceIoControl(hPhysicalDriveIOCTL, DFP_RCV_DRIVE_DATA, (LPVOID)pSCIP, sizeof(SENDCMDINPARAMS) - 1, 
(LPVOID)pSCOP, sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1, lpcbBytesReturned, NULL);
}
// 获取硬盘型号、序列号、修订版本号
void __fastcall ReadPhysicalDriveOnNT()
{
//IDENTIFY_BUFFER_SIZE = 512
byte IdOutCmd[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];
char serialNo[21], modelNo[21], revisionNo[21];
for(int Drive=0; Drive < 4; Drive++)
{
HANDLE hPhysicalDriveIOCTL;
char DriveName[32];
sprintf(DriveName, "\\\\.\\PhysicalDrive%d", Drive);
hPhysicalDriveIOCTL = CreateFile(DriveName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if(hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
{
DWORD cbBytesReturned = 0;
GETVERSIONOUTPARAMS VersionParams;
// Get the version, etc of PhysicalDrive IOCTL
ZeroMemory(&VersionParams, sizeof(GETVERSIONOUTPARAMS));
if(!DeviceIoControl(hPhysicalDriveIOCTL, DFP_GET_VERSION, NULL, 0, &VersionParams, sizeof(VersionParams), &cbBytesReturned, NULL))
{
continue;
}
if(VersionParams.bIDEDeviceMap > 0)
{
// IDE or ATAPI IDENTIFY cmd
byte bIDCmd = 0;
SENDCMDINPARAMS InParams;
// Now, get the ID sector for all IDE devices in the system.
// If the device is ATAPI use the IDE_ATAPI_IDENTIFY command,
// otherwise use the IDE_ATA_IDENTIFY command
// 具体所得结果请参考上面的说明
bIDCmd = (VersionParams.bIDEDeviceMap >> Drive & 0x10) ? IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;
ZeroMemory(&InParams, sizeof(SENDCMDINPARAMS));
ZeroMemory(IdOutCmd, sizeof(IdOutCmd));
if(DoIdentify(hPhysicalDriveIOCTL, &InParams, (PSENDCMDOUTPARAMS)IdOutCmd, (BYTE)bIDCmd,(BYTE)Drive, &cbBytesReturned))
{
DWORD DiskData[256];
USHORT *pIDSector;												// 对应结构IDSECTOR,见头文件
pIDSector = (USHORT*)((SENDCMDOUTPARAMS*)IdOutCmd)->bBuffer;
for(int i=0; i < 256; i++)
DiskData[i] = pIDSector[i];
FILE *fp = NULL;
if(NULL != (fp = fopen("a.log", "w")))
{
fwrite(DiskData, sizeof(DiskData), 1, fp);
fclose(fp);
cout<<"Write file successful"<<endl;
}
strcpy(serialNo, ConvertToString(DiskData, 10, 19).c_str());	// get serial number
strcpy(modelNo, ConvertToString(DiskData, 27, 46).c_str());		// get model type
strcpy(revisionNo, ConvertToString (DiskData, 23, 26).c_str());	// 获取修订版本号
printf("SerialNo=%s\nModelNo=%s\nRevisionNo=%s\n", serialNo, modelNo, revisionNo);
}
}
CloseHandle(hPhysicalDriveIOCTL);
}
}
}
int main()
{
ReadPhysicalDriveOnNT();
return 0;
}


运行结果:

Write file successful
SerialNo=6VMSHFW9
ModelNo=ST3500418AS
RevisionNo=CC68
Press any key to continue


 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android系统服务-WindowManager

WindowManager是Android中一个重要的服务 &#xff08;Service &#xff09;。WindowManager Service 是全局的&#xff0c;是唯一的。它将用户的操作&#xff0c;翻译成为指令&#xff0c;发送给呈现在界面上的各个Window。Activity会将顶级的控件注册到 Window Manager 中&am…

Linux:关于头文件的位置

十足的菜鸟问题&#xff0c;今天终于想通了一点点。 引子&#xff1a;通常在写代码时先要包含一通头文件&#xff0c;这些头文件们在什么地方呢&#xff1f;这个问题起源于课题中需要操作OK6410的PWM寄存器&#xff0c;查了许多文献说需要ioremap()映射&#xff0c;需要包含 a…

理解AES加密解密的使用方法

很多人对于AES加密并不是很了解&#xff0c;导致互相之间进行加密解密困难。 本文用简单的方式来介绍AES在使用上需要的知识&#xff0c;而不涉及内部算法。最后给出例子来帮助理解AES加密解密的使用方法。 AES的麻烦 相比于其他加密&#xff0c;AES加密似乎模式很多&#xf…

C++中,引用作为函数参数

引用作为函数参数 C之所以增加引用类型&#xff0c; 主要是把它作为函数参数&#xff0c;以扩充函数传递数据的功能。 ———————————————————— c&#xff0c;函数传参&#xff1a;(1)将变量名作为实参和形参。这时传给形参的是变量的值&#xff0c;传递是单向…

全排列算法原理和实现

From: http://www.cnblogs.com/nokiaguy/archive/2008/05/11/1191914.html 全排列是将一组数按一定顺序进行排列&#xff0c;如果这组数有n个&#xff0c;那么全排列数为n!个。现以{1, 2, 3, 4, 5}为例说明如何编写全排列的递归算法。1、首先看最后两个数4, 5。 它们的全排列为…

ext笔记

如何创建对象实例:var app function() { var privVar11; return {p1:11, p2:22,init:function(){}};}(); js创建对象的原理:实际上创建了一个匿名函数&#xff08;没有名字的函数&#xff09;&#xff0c;经过解释之后让它立刻运行&#xff08;注意函数后面的()&#xff09;。…

Linux:建立内核代码树

为什么建立内核代码树&#xff1f;菜鸟简单的以为&#xff0c;好比为某户型的房子&#xff08;某个版本的Linux&#xff09;设计门窗&#xff0c;那么当然需要根据该户型房子的具体参数进行设计了&#xff0c;或者说内核模块要基于内核版本或者该版本的内核代码。那么内核的编译…

输出一个等边三角形(由*拼接),实心或空心,连长为n

开发环境&#xff1a;VC6 /*功能&#xff1a;输出一个等边三角形(由*拼接)&#xff0c;实心或空心&#xff0c;连长为n*/#include <stdio.h>/*将str重复输出len遍*/void Print(char str[], int len){while(len-- > 0)printf("%s", str);}/*功能&#xff1a…

年底了,总结一下大型网站的入侵经验[t00ls转载]

事先声明&#xff1a;1、拒绝跨省。2、拒绝人肉&#xff0c;猪肉&#xff0c;牛肉。本文并不涉及内网。纯属经验谈&#xff0c;以前oldjun有写过类似的。俺这里挑不重复的补充&#xff1a;0x00大型某类别门户世界排名top100以内&#xff1a;- 低调求发展1、一个点&#xff0c;特…

File System Auditor 安装全程截图

最近在家里用h-v做了一下&#xff26;&#xff33;&#xff21;的一些测试&#xff0c;测试记录如下。 FSA安装需求: .net 2.0 SQL2000及更高版本数据库 FSA的组成: 三个部分: 1、FSA 服务器控制台&#xff1a;管理与配置 2、文件服务器&#xff1a;安装FSA agent&#x…

vue中使用cookies和crypto-js实现记住密码和加密

使用crypto-js加解密 第一步&#xff0c;安装 npm install crypto-js 第二步&#xff0c;在你需要的vue组件内import import CryptoJS from “crypto-js”; 第三步&#xff0c;使用 // Encrypt 加密 var cipherText CryptoJS.AES.encrypt("my message","secret…

Linux:编译生成内核模块(来自国嵌的视频教学)

内核模块的代码文件 文件 yyyy.c &#xff08;yyyy可以与模块xxxx同名也可以不同名&#xff09; &#xff08;类似模板的东西&#xff09; #ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE //直接添加到内核时去掉&#xff0c;生成模块时保留 #d…

iOS开发UI篇—实现一个私人通讯录小应用(二)

一、实现功能说明 &#xff08;1&#xff09;点击注销按钮&#xff0c;弹出一个对话框&#xff0c;点击确定后移除当前栈顶的控制器&#xff0c;返回开始界面&#xff0c;点击取消&#xff0c;不做任何操作。 注意&#xff1a;注销按钮的单击事件已经进行了连线。实现-(void)ac…

IIS内部错误:500之解决方案

将自己很早以前做的一个asp.net网站从自己的笔记本上迁移到公司电脑上&#xff0c;在作好相关配置后&#xff0c;打开网站首页&#xff0c;出现HTTP500错误&#xff0c;上网查了发现这是服务器内部错误。 接着我查看了下系统事件日志信息&#xff0c;发现了错误: 服务器无法加…

AGPM(高级组策略管理)3.0之二操作

续AGPM&#xff08;高级组策略管理 &#xff09;3.0之一部署。1、设置默认AGPM服务器打开组策略管理控制台&#xff08;GPMC.MSC&#xff09;&#xff0c;打开默认的Default Domain Policy进行编辑。打开用户配置、策略、管理模板、Windows 组件、AGPM&#xff0c;进行如下设置…

Linux:串口通信

以前跟着做过VxWorks的开发&#xff0c;主要通信方式是串口&#xff0c;因为底层BSP包已经做好了&#xff0c;串口通信非常简单。后来接触Linux&#xff0c;在一块OK6410上跑Linux串口通信&#xff0c;才发现原来天真的以为甚是简单的串口变得如此的不简单。 #include <ter…