【注意】本文代码可以在XP系统下成功,但在 WIN7 系统中不行,因为 WIN7 对直接打开磁盘驱动器做了限制,必须要管理员授权。否则以普通用户身份运行会在 CreateFile 时返回 INVALID_HANDLE_VALUE(5:没有权限),从而无法获取硬盘序列号。如何在 WIN7 下面不需要以管理员身份运行就可以得到硬盘序列号呢,因为涉及一些软件保护的敏感信息,故暂不在此处发表。
在代码开头,有一些宏定义了比如 _WIN32_WINNT 的版本,它们是来自 win32 程序的 stdafx.h 里,出现在包含 windows.h 等头文件之前,因为 console 程序 IDE 不会自动添加这些内容,而没有这些宏,代码中的一些结构体的定义就不会被编译到。所以我们必须手工加上这些宏定义。
序列号开头可能有空格补充,所以我又用 TrimStart 这个辅助函数,可以去掉字符串开头的空格。 硬件厂商应该保证,ModelNumber + SerialNumber 组合在一起是唯一标识,不会重复。 上面的代码产生如下输出:
#include "stdafx.h"
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <windows.h>
#include <winioctl.h>
//
BOOL GetPhyDriveSerial(LPTSTR pModelNo, LPTSTR pSerialNo);
void ToLittleEndian(PUSHORT pWords, int nFirstIndex, int nLastIndex, LPTSTR pBuf);
void TrimStart(LPTSTR pBuf);
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR szModelNo[48], szSerialNo[24];
if(GetPhyDriveSerial(szModelNo, szSerialNo))
{
_tprintf(_T(" : 0 1 2\n"));
_tprintf(_T(" : 012345678901234567890123456789\n"));
_tprintf(_T("Model No: %s\n"), szModelNo);
_tprintf(_T("Serial No: %s\n"), szSerialNo);
TrimStart(szSerialNo);
_tprintf(_T("Serial No: %s\n"), szSerialNo);
}
else
{
_tprintf(_T("Failed.\n"));
}
getchar();
return 0;
}
//
// Model Number: 40 ASCII Chars
// SerialNumber: 20 ASCII Chars
//
BOOL GetPhyDriveSerial(LPTSTR pModelNo, LPTSTR pSerialNo)
{
//-1是因为 SENDCMDOUTPARAMS 的结尾是 BYTE bBuffer[1];
BYTE IdentifyResult[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];
DWORD dwBytesReturned;
GETVERSIONINPARAMS get_version;
SENDCMDINPARAMS send_cmd = { 0 };
HANDLE hFile = CreateFile(_T("\\\\.\\PHYSICALDRIVE0"), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)
return FALSE;
//get version
DeviceIoControl(hFile, SMART_GET_VERSION, NULL, 0,
&get_version, sizeof(get_version), &dwBytesReturned, NULL);
//identify device
send_cmd.irDriveRegs.bCommandReg = (get_version.bIDEDeviceMap & 0x10)? ATAPI_ID_CMD : ID_CMD;
DeviceIoControl(hFile, SMART_RCV_DRIVE_DATA, &send_cmd, sizeof(SENDCMDINPARAMS) - 1,
IdentifyResult, sizeof(IdentifyResult), &dwBytesReturned, NULL);
CloseHandle(hFile);
//adjust the byte order
PUSHORT pWords = (USHORT*)(((SENDCMDOUTPARAMS*)IdentifyResult)->bBuffer);
ToLittleEndian(pWords, 27, 46, pModelNo);
ToLittleEndian(pWords, 10, 19, pSerialNo);
return TRUE;
}
//把WORD数组调整字节序为little-endian,并滤除字符串结尾的空格。
void ToLittleEndian(PUSHORT pWords, int nFirstIndex, int nLastIndex, LPTSTR pBuf)
{
int index;
LPTSTR pDest = pBuf;
for(index = nFirstIndex; index <= nLastIndex; ++index)
{
pDest[0] = pWords[index] >> 8;
pDest[1] = pWords[index] & 0xFF;
pDest += 2;
}
*pDest = 0;
//trim space at the endof string; 0x20: _T(' ')
--pDest;
while(*pDest == 0x20)
{
*pDest = 0;
--pDest;
}
}
//滤除字符串起始位置的空格
void TrimStart(LPTSTR pBuf)
{
if(*pBuf != 0x20)
return;
LPTSTR pDest = pBuf;
LPTSTR pSrc = pBuf + 1;
while(*pSrc == 0x20)
++pSrc;
while(*pSrc)
{
*pDest = *pSrc;
++pDest;
++pSrc;
}
*pDest = 0;
}在代码开头,有一些宏定义了比如 _WIN32_WINNT 的版本,它们是来自 win32 程序的 stdafx.h 里,出现在包含 windows.h 等头文件之前,因为 console 程序 IDE 不会自动添加这些内容,而没有这些宏,代码中的一些结构体的定义就不会被编译到。所以我们必须手工加上这些宏定义。
序列号开头可能有空格补充,所以我又用 TrimStart 这个辅助函数,可以去掉字符串开头的空格。 硬件厂商应该保证,ModelNumber + SerialNumber 组合在一起是唯一标识,不会重复。 上面的代码产生如下输出:
: 0 1 2
: 012345678901234567890123456789
Model No: WDC WD1600AAJS-60M0A0
Serial No: WD-WCAV30353688
Serial No: WD-WCAV30353688 收藏的用户(0) X
正在加载信息~
推荐阅读
最新回复 (1)
-
amirassari2002 2016-12-27引用 2楼//把WORD数组调整字节序为little-endian,并滤除字符串结尾的空格。 void ToLittleEndian(PUSHORT pWords, int nFirstIndex, int nLastIndex, LPTSTR pBuf) { int index; LPTSTR pDest = pBuf; for(index = nFirstIndex; index <= nLastIndex; ++index) { pDest[0] = pWords[index] >> 8; pDest[1] = pWords[index] & 0xFF; pDest += 2; } *pDest = 0; //trim space at the endof string; 0x20: _T(' ') --pDest; while(*pDest == 0x20) { *pDest = 0; --pDest; } } //滤除字符串起始位置的空格 void TrimStart(LPTSTR pBuf) { if(*pBuf != 0x20) return; LPTSTR pDest = pBuf; LPTSTR pSrc = pBuf + 1; while(*pSrc == 0x20) ++pSrc; while(*pSrc) { *pDest = *pSrc; ++pDest; ++pSrc; } *pDest = 0; } string GetPhyDriveSerial() { //-1是因为 SENDCMDOUTPARAMS 的结尾是 BYTE bBuffer[1]; BYTE IdentifyResult[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1]; DWORD dwBytesReturned; GETVERSIONINPARAMS get_version; SENDCMDINPARAMS send_cmd = { 0 }; HANDLE hFile = CreateFile(_T("\\\\.\\PHYSICALDRIVE0"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(hFile == INVALID_HANDLE_VALUE) return FALSE; //get version DeviceIoControl(hFile, SMART_GET_VERSION, NULL, 0, &get_version, sizeof(get_version), &dwBytesReturned, NULL); //identify device send_cmd.irDriveRegs.bCommandReg = (get_version.bIDEDeviceMap & 0x10)? ATAPI_ID_CMD : ID_CMD; DeviceIoControl(hFile, SMART_RCV_DRIVE_DATA, &send_cmd, sizeof(SENDCMDINPARAMS) - 1, IdentifyResult, sizeof(IdentifyResult), &dwBytesReturned, NULL); CloseHandle(hFile); //adjust the byte order PUSHORT pWords = (USHORT*)(((SENDCMDOUTPARAMS*)IdentifyResult)->bBuffer); TCHAR szModelNo[48], szSerialNo[24]; ToLittleEndian(pWords, 27, 46, szModelNo); ToLittleEndian(pWords, 10, 19, szSerialNo); TrimStart(szModelNo); return string(szModelNo)+string(szSerialNo); }简单一点的。
站点信息
- 文章2314
- 用户1336
- 访客11774206
每日一句
Don't judge by looks.
别以貌取人。
别以貌取人。
HSV颜色检测
Android开源库-仿360手机助手底部动画菜单布局
Android studio3.3如何创建一个Native工程
微信小程序F2图表——Cannot read property 'source' of null
Java开发人员的7种最佳测试框架
微信小程序自定义组件的使用以及调用自定义组件中的方法
Python下载文件的简单示例
请启用虚拟机平台 windows 功能并确保在 bios 中启用虚拟化
程序员必看的最佳科技电影
windows10 1809关闭烦人的自动更新
在Google Play商店中展示Android应用的八大技巧
imencode和imdecode使用
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is
新会员