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