
@ 126 / blog / static / 62332277227
[注意]本文中的代码在XP系统中可以成功,但在WIN7系统中则不能成功,因为WIN7限制了磁盘驱动器的直接打开,必须由管理员授权。否则,以普通用户身份运行时,CreateFile时将返回INVALID_HANDLE_VALUE(5:无权限),因此无法获取硬盘序列号。如何在不以管理员身份在WIN7下运行的情况下获取硬盘序列号,因为它涉及一些受软件保护的敏感信息,因此我不会在此处临时发布它。
有关此问题的许多答案以及有关Internet的博客和帖子。但令我更加不满意的是,许没有说他们的代码是引用,引用还是原始的。我发现他们被怀疑抄袭他人的代码。例如,用于检出序列号字符串的辅助函数(似乎称为ConvertToString),实际上,此实现主要用于反转字节顺序,但是它的实现合理吗?有效率吗?代码很漂亮是吗?我认为,以获得相关信息。现在您知道这些索引值都是ATA,什么是ATAPI?英文大概是带有数据包接口的AT附件,我们不在乎。
以下是我在Internet上修改这些代码后得到的代码。这是一个win32控制台程序。废话,可读性和可用性没有比Internet上的代码更好的了(您可以看到我编译的代码很短)。当然,如果我们在分发软件时使用硬盘序列号作为对物理硬件的绑定,则实际上不需要调整字节顺序步骤,因为您不是用于打印和显示它们,而是仅用于与硬件相关的数据
--------
#include“ stdafx.h”
#ifndef_WIN32_WINNT
#define_WIN32_WINNT 0x0501
#endif
#include
#include
//
BOOL GetPhyDriveSerial(LPTSTR pModelNo,LPTSTR pSerialNo);
voidToLittleEndian(PUSHORT pWords,intnFirstIndex,intnLastIndex,LPTSTR pBuf);
voidTrimStart(LPTSTR pBuf);
int_tmain(intargc,_TCHAR * argv [])
{
TCHAR szModelNo [48],szSerialNo [24];
if(GetPhyDriveSerial(szModelNo,szSerialNo))
{

_tprintf(_T(“:0 1 2 \ n”));
_tprintf(_T(“:23456789 \ n”));
_tprintf(_T(“ Model No:%s \ n”),szModelNo);
_tprintf(_T(“序列号:%s \ n”),szSerialNo);
TrimStart(szSerialNo);
_tprintf(_T(“序列号:%s \ n”),szSerialNo);
}
其他
{
_tprintf(_T(“失败。\ n”));
}
getchar();
返回0;
}
//
//型号:40个ASCII字符
//序列号:20个ASCII字符
//
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)
returnFALSE;
//获取版本
DeviceIoControl(hFile,SMART_GET_VERSION,NULL,0,
&get_version,sizeof(get_version),&dwBytesReturned,NULL);
//识别设备
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);
//调整字节顺序
PUSHORT pWords =(USHORT *)((((SENDCMDOUTPARAMS *)IdentifyResult)-> bBuffer);
ToLittleEndian(pWords,27,46,pModelNo);
ToLittleEndian(pWords,10,19,pSerialNo);
returnTRUE;
}
///将WORD数组的字节顺序调整为little-endian,并过滤掉字符串末尾的空格。

voidToLittleEndian(PUSHORT pWords,intnFirstIndex,intnLastIndex,LPTSTR pBuf)
{
intindex;
LPTSTR pDest = pBuf;
for(index = nFirstIndex; index> 8;
pDest [1] = pWords [index]&0xFF;
pDest + = 2;
}
* pDest = 0;
//在字符串末尾修剪空格; 0x20:_T('')
-pDest;
while(* pDest == 0x20)
{
* pDest = 0;
-pDest;
}
}
//过滤字符串开头的空格
voidTrimStart(LPTSTR pBuf)
{
if(* pBuf!= 0x20)
返回;

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之类的头文件之前,因为控制台程序IDE不会自动添加这些内容,如果没有这些宏,则代码中的某些结构定义将无法编译。因此,我们必须手动添加这些宏定义。
序列号开头可能有空格,因此我使用辅助功能TrimStart删除了字符串开头的空格。
硬件制造商应确保ModelNumber + SerialNumber的组合是唯一的标识符,并且不会重复。
上面的代码产生以下输出:
:0 1 2
:23456789
型号:WDC WD1600AAJS-60M0A0
序列号:WD-WCAV30353688
序列号:WD-WCAV30353688
参考资料:
信息技术-带包接口7的AT附件(ATA / ATAPI-7)等。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/dianqi/article-331893-1.html
我也是
舰多不算本事
不喜欢舒淇
真正打海战是不行的