VC++ MFC如何获取CPU ID及硬盘的序列号

VC++ MFC如何获取CPU ID及硬盘的序列号,第1张

// “获得Intel CPU ID”按钮消息处理函数

void CIntelCPUIDDlg::OnBtnCPUID()

{

unsigned long s1,s2;

unsigned char vendor_id[]="------------";//CPU提供商ID

CString str1,str2,str3;

// 以下为获得CPU ID的汇编语言指令

_asm // 得到CPU提供商信息

{

xor eax,eax // 将eax清0

cpuid // 获取CPUID的指令

mov dword ptr vendor_id,ebx

mov dword ptr vendor_id[+4],edx

mov dword ptr vendor_id[+8],ecx

}

str1Format("%s",vendor_id);

_asm // 得到CPU ID的高32位

{

mov eax,01h

xor edx,edx

cpuid

mov s2,eax

}

str2Format("%08X-",s2);

_asm // 得到CPU ID的低64位

{

mov eax,03h

xor ecx,ecx

xor edx,edx

cpuid

mov s1,edx

mov s2,ecx

}

str3Format("%08X-%08X\n",s1,s2);

str2=str2+str3;

m_editVendorSetWindowText(str1);

m_editCPUIDSetWindowText(str2);

}

// GetHDSerialcpp: implementation of the CGetHDSerial class

//

//////////////////////////////////////////////////////////////////////

#include "stdafxh"

#include "GetHDSerialh"

char m_buffer[256];

WORD m_serial[256];

DWORD m_OldInterruptAddress;

DWORDLONG m_IDTR;

// 等待硬盘空闲

static unsigned int WaitHardDiskIdle()

{

BYTE byTemp;

Waiting:

_asm

{

mov dx, 0x1f7

in al, dx

cmp al, 0x80

jb Endwaiting

jmp Waiting

}

Endwaiting:

_asm

{

mov byTemp, al

}

return byTemp;

}

//中断服务程序

void _declspec( naked )InterruptProcess(void)

{

int byTemp;

int i;

WORD temp;

//保存寄存器值

_asm

{

push eax

push ebx

push ecx

push edx

push esi

}

WaitHardDiskIdle();//等待硬盘空闲状态

_asm

{

mov dx, 0x1f6

mov al, 0xa0

out dx, al

}

byTemp = WaitHardDiskIdle(); //若直接在Ring3级执行等待命令,会进入死循环

if ((byTemp&0x50)!=0x50)

{

_asm // 恢复中断现场并退出中断服务程序

{

pop esi

pop edx

pop ecx

pop ebx

pop eax

iretd

}

}

_asm

{

mov dx, 0x1f6 //命令端口1f6,选择驱动器0

mov al, 0xa0

out dx, al

inc dx

mov al, 0xec

out dx, al //发送读驱动器参数命令

}

byTemp = WaitHardDiskIdle();

if ((byTemp&0x58)!=0x58)

{

_asm // 恢复中断现场并退出中断服务程序

{

pop esi

pop edx

pop ecx

pop ebx

pop eax

iretd

}

}

//读取硬盘控制器的全部信息

for (i=0;i<256;i++)

{

_asm

{

mov dx, 0x1f0

in ax, dx

mov temp, ax

}

m_serial[i] = temp;

}

_asm

{

pop esi

pop edx

pop ecx

pop ebx

pop eax

iretd

}

}

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

CGetHDSerial::CGetHDSerial()

{

}

CGetHDSerial::~CGetHDSerial()

{

}

// 读取硬盘序列号函数

char CGetHDSerial::GetHDSerial()

{

m_buffer[0]='\n';

// 得到当前 *** 作系统版本

OSVERSIONINFO OSVersionInfo;

OSVersionInfodwOSVersionInfoSize = sizeof(OSVERSIONINFO);

GetVersionEx( &OSVersionInfo);

if (OSVersionInfodwPlatformId != VER_PLATFORM_WIN32_NT)

{

// Windows 9x/ME下读取硬盘序列号

WORD m_wWin9xHDSerial[256];

Win9xReadHDSerial(m_wWin9xHDSerial);

strcpy (m_buffer, WORDToChar (m_wWin9xHDSerial, 10, 19));

}

else

{

// Windows NT/2000/XP下读取硬盘序列号

DWORD m_wWinNTHDSerial[256];

// 判断是否有SCSI硬盘

if ( ! WinNTReadIDEHDSerial(m_wWinNTHDSerial))

WinNTReadSCSIHDSerial(m_wWinNTHDSerial);

strcpy (m_buffer, DWORDToChar (m_wWinNTHDSerial, 10, 19));

}

return m_buffer;

}

// Windows9X/ME系统下读取硬盘序列号

void _stdcall CGetHDSerial::Win9xReadHDSerial(WORD buffer)

{

int i;

for(i=0;i<256;i++)

buffer[i]=0;

_asm

{

push eax

//获取修改的中断的中断描述符(中断门)地址

sidt m_IDTR

mov eax,dword ptr [m_IDTR+02h]

add eax,308h+04h

cli

//保存原先的中断入口地址

push ecx

mov ecx,dword ptr [eax]

mov cx,word ptr [eax-04h]

mov dword ptr m_OldInterruptAddress,ecx

pop ecx

//设置修改的中断入口地址为新的中断处理程序入口地址

push ebx

lea ebx,InterruptProcess

mov word ptr [eax-04h],bx

shr ebx,10h

mov word ptr [eax+02h],bx

pop ebx

//执行中断,转到Ring 0(类似CIH病毒原理)

int 3h

//恢复原先的中断入口地址

push ecx

mov ecx,dword ptr m_OldInterruptAddress

mov word ptr [eax-04h],cx

shr ecx,10h

mov word ptr [eax+02h],cx

pop ecx

sti

pop eax

}

for(i=0;i<256;i++)

buffer[i]=m_serial[i];

}

// Windows 9x/ME系统下,将字类型(WORD)的硬盘信息转换为字符类型(char)

char CGetHDSerial::WORDToChar (WORD diskdata [256], int firstIndex, int lastIndex)

{

static char string [1024];

int index = 0;

int position = 0;

// 按照高字节在前,低字节在后的顺序将字数组diskdata 中内容存入到字符串string中

for (index = firstIndex; index <= lastIndex; index++)

{

// 存入字中的高字节

string [position] = (char) (diskdata [index] / 256);

position++;

// 存入字中的低字节

string [position] = (char) (diskdata [index] % 256);

position++;

}

// 添加字符串结束标志

string [position] = '\0';

// 删除字符串中空格

for (index = position - 1; index > 0 && ' ' == string [index]; index--)

string [index] = '\0';

return string;

}

// Windows NT/2000/XP系统下,将双字类型(DWORD)的硬盘信息转换为字符类型(char)

char CGetHDSerial::DWORDToChar (DWORD diskdata [256], int firstIndex, int lastIndex)

{

static char string [1024];

int index = 0;

int position = 0;

// 按照高字节在前,低字节在后的顺序将双字中的低字存入到字符串string中

for (index = firstIndex; index <= lastIndex; index++)

{

// 存入低字中的高字节

string [position] = (char) (diskdata [index] / 256);

position++;

// 存入低字中的低字节

string [position] = (char) (diskdata [index] % 256);

position++;

}

// 添加字符串结束标志

string [position] = '\0';

// 删除字符串中空格

for (index = position - 1; index > 0 && ' ' == string [index]; index--)

string [index] = '\0';

return string;

}

// Windows NT/2000/XP下读取IDE硬盘序列号

BOOL CGetHDSerial::WinNTReadIDEHDSerial(DWORD buffer)

{

BYTE IdOutCmd [sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];

BOOL bFlag = FALSE;

int drive = 0;

char driveName [256];

HANDLE hPhysicalDriveIOCTL = 0;

sprintf (driveName, "\\\\\\PhysicalDrive%d", drive);

// Windows NT/2000/XP下创建文件需要管理员权限

hPhysicalDriveIOCTL = CreateFile (driveName,

GENERIC_READ | GENERIC_WRITE,

FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,

OPEN_EXISTING, 0, NULL);

if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)

{

GETVERSIONOUTPARAMS VersionParams;

DWORD cbBytesReturned = 0;

// 得到驱动器的IO控制器版本

memset ((void) &VersionParams, 0, sizeof(VersionParams));

if(DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_GET_VERSION,

NULL, 0, &VersionParams,

sizeof(VersionParams),

&cbBytesReturned, NULL) )

{

if (VersionParamsbIDEDeviceMap > 0)

{

BYTE bIDCmd = 0; // IDE或者ATAPI识别命令

SENDCMDINPARAMS scip;

// 如果驱动器是光驱,采用命令IDE_ATAPI_IDENTIFY, command,

// 否则采用命令IDE_ATA_IDENTIFY读取驱动器信息

bIDCmd = (VersionParamsbIDEDeviceMap >> drive & 0x10)

IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;

memset (&scip, 0, sizeof(scip));

memset (IdOutCmd, 0, sizeof(IdOutCmd));

// 获取驱动器信息

if (WinNTGetIDEHDInfo (hPhysicalDriveIOCTL,

&scip,

(PSENDCMDOUTPARAMS)&IdOutCmd,

(BYTE) bIDCmd,

(BYTE) drive,

&cbBytesReturned))

{

int m = 0;

USHORT pIdSector = (USHORT )

((PSENDCMDOUTPARAMS) IdOutCmd) -> bBuffer;

for (m = 0; m < 256; m++)

buffer[m] = pIdSector [m];

bFlag = TRUE; // 读取硬盘信息成功

}

}

}

CloseHandle (hPhysicalDriveIOCTL); // 关闭句柄

}

return bFlag;

}

// WindowsNT/2000/XP系统下读取SCSI硬盘序列号

BOOL CGetHDSerial::WinNTReadSCSIHDSerial (DWORD buffer)

{

buffer[0]='\n';

int controller = 0;

HANDLE hScsiDriveIOCTL = 0;

char driveName [256];

sprintf (driveName, "\\\\\\Scsi%d:", controller);

// Windows NT/2000/XP下任何权限都可以进行

hScsiDriveIOCTL = CreateFile (driveName,

GENERIC_READ | GENERIC_WRITE,

FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,

OPEN_EXISTING, 0, NULL);

if (hScsiDriveIOCTL != INVALID_HANDLE_VALUE)

{

int drive = 0;

DWORD dummy;

for (drive = 0; drive < 2; drive++)

{

char buffer [sizeof (SRB_IO_CONTROL) + SENDIDLENGTH];

SRB_IO_CONTROL p = (SRB_IO_CONTROL ) buffer;

SENDCMDINPARAMS pin =

(SENDCMDINPARAMS ) (buffer + sizeof (SRB_IO_CONTROL));

// 准备参数

memset (buffer, 0, sizeof (buffer));

p -> HeaderLength = sizeof (SRB_IO_CONTROL);

p -> Timeout = 10000;

p -> Length = SENDIDLENGTH;

p -> ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;

strncpy ((char ) p -> Signature, "SCSIDISK", 8);

pin -> irDriveRegsbCommandReg = IDE_ATA_IDENTIFY;

pin -> bDriveNumber = drive;

// 得到SCSI硬盘信息

if (DeviceIoControl (hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT,

buffer,

sizeof (SRB_IO_CONTROL) +

sizeof (SENDCMDINPARAMS) - 1,

buffer,

sizeof (SRB_IO_CONTROL) + SENDIDLENGTH,

&dummy, NULL))

{

SENDCMDOUTPARAMS pOut =

(SENDCMDOUTPARAMS ) (buffer + sizeof (SRB_IO_CONTROL));

IDSECTOR pId = (IDSECTOR ) (pOut -> bBuffer);

if (pId -> sModelNumber [0])

{

int n = 0;

USHORT pIdSector = (USHORT ) pId;

for (n = 0; n < 256; n++)

buffer[n] =pIdSector [n];

return TRUE; // 读取成功

}

}

}

CloseHandle (hScsiDriveIOCTL); // 关闭句柄

}

return FALSE; // 读取失败

}

// Windows NT/2000/XP下读取IDE设备信息

BOOL CGetHDSerial::WinNTGetIDEHDInfo (HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP,

PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum,

PDWORD lpcbBytesReturned)

{

// 为读取设备信息准备参数

pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;

pSCIP -> irDriveRegsbFeaturesReg = 0;

pSCIP -> irDriveRegsbSectorCountReg = 1;

pSCIP -> irDriveRegsbSectorNumberReg = 1;

pSCIP -> irDriveRegsbCylLowReg = 0;

pSCIP -> irDriveRegsbCylHighReg = 0;

// 计算驱动器位置

pSCIP -> irDriveRegsbDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4);

// 设置读取命令

pSCIP -> irDriveRegsbCommandReg = bIDCmd;

pSCIP -> bDriveNumber = bDriveNum;

pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;

// 读取驱动器信息

return ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_GET_DRIVE_INFO,

(LPVOID) pSCIP,

sizeof(SENDCMDINPARAMS) - 1,

(LPVOID) pSCOP,

sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,

lpcbBytesReturned, NULL) );

}

光SQL2005一个,就占超大资源。

建议最低用奔腾E5200,手里资金充足的话,可以选用E7系列,主板可以用G41,集成的是X4500显卡,编程足够用了,还提供了独立PCI-E,以后也能升级。

内存单条2G,配置足以运行你的这些要求的了。

酷睿i系列之前的intelCPU 由于没有集成内存控制器 CPU与内存的通讯受到FSB前端总线频率的限制 比如说1333Mhz的FSB 那么 最高的通讯频率就是1333Mhz 也就是 使用两个667Mhz的DDR2内存或者单通道的1333MhzDDR3内存正好满足需求 使用更高的频率内存不是不支持 而是没必要 因为会自动降频 以保证与CPU外频的一致性(DDR2,DDR3的标称频率不是实际频率 而是等效为DDR内存的频率 有2倍 4倍的关系 这里的与CPU外频一致 指的是实际频率与其一致)

而从i系列开始 Intel的CPU开始集成内存控制器 CPU与内存可以直接通讯了 取代FSB的是QPI总线 比如i7使用的QPI总线频率是64GT/s 非常高了 根本构不成瓶颈 所以对于目前市售的一般DDR3内存并不会有频率的限制 而且集成了内存控制器 内存访问的延迟大大降低 所以带来了内存访问速度的飞速提升

另外 AMD的U也集成内存控制器 对应的是HT总线

QPI和HT总线是可以超频的 以支援发烧级的内存

、推荐使用__cpuid、__cpuidex等Intrinsics函数

32位模式我使用内嵌汇编调用cpuid指令64位模式VC编译器支持内嵌汇编

于微软提供Intrinsics函数——编译器Intrinsics函数编译应机器指令且同支持32位64位

例CPUID指令应Intrinsics函数——

[cpp] view plain copy

//

void __cpuid(

int CPUInfo[4],

int InfoType

);

void __cpuidex(

int CPUInfo[4],

int InfoType,

int ECXValue

);

__cpuidex函数InfoType参数CPUID指令eax参数即功能IDECXValue参数CPUID指令ecx参数即功能IDCPUInfo参数用于接收输eax, ebx, ecx, edx四寄存器

早期CPUID功能需要功能ID参数(eax)使用__cpuid函数

CPUID功能越越强功能ID参数(eax)参数够用于加功能ID(ecx)参数应该采用__cpuidex

二、用条件编译判断VC编译器Intrinsics函数支持性(_MSC_VER)

__cpuid、__cpuidex等Intrinsics函数遇问题——

1低版本VC编译器没intrinh文件注:VC2005(或更高)才拥intrinh支持__cpuid

2低版本VC编译器支持__cpuidex注:VC2008部版本及VS2011(或更高)intrinh才__cpuidex

使用条件编译判断VC编译器版本

_MSC_VER微软C/C++编译器——clexe编译代码预定义宏值表示cl版本类型int例——

#if _MSC_VER >=1200 // VC++60

#if _MSC_VER >=1300 // VC2003

#if _MSC_VER >=1400 // VC2005

#if _MSC_VER >=1500 // VC2008

#if _MSC_VER >=1600 // VC2011

例发现_MSC_VER于等于1400我#include 再利用_MSC_VER进步判断__cpuid、__cpuidex支持性

三、用条件编译判断64位模式(_WIN64)

使用_WIN64预处理宏用判断目标平台64位

虽编译x64平台程序编译器自推导_WIN64Visual Studio语高亮清楚些能仍按32位代码做语高亮所建议手项目预处理宏增加_WIN64

四、32位用内嵌汇编实现__cpuidex函数

32位模式我使用内嵌汇编实现__cpuidex函数代码——

[cpp] view plain copy

void __cpuidex(INT32 CPUInfo[4], INT32 InfoType, INT32 ECXValue)

{

if (NULL==CPUInfo) return;

_asm{

// load 读取参数寄存器

mov edi, CPUInfo; // 准备用edi寻址CPUInfo

mov eax, InfoType;

mov ecx, ECXValue;

// CPUID

cpuid;

// save 寄存器保存CPUInfo

mov [edi], eax;

mov [edi+4], ebx;

mov [edi+8], ecx;

mov [edi+12], edx;

}

}

五、全部代码

全部代码——

[cpp] view plain copy

#include

#include

#include

#if _MSC_VER >=1400 // VC2005才支持intrinh

#include // 所Intrinsics函数

#endif

char szBuf[64];

INT32 dwBuf[4];

#if defined(_WIN64)

// 64位支持内联汇编 应使用__cpuid、__cpuidex等Intrinsics函数

#else

#if _MSC_VER < 1600 // VS2011 据说VC2008 SP1才支持__cpuidex

void __cpuidex(INT32 CPUInfo[4], INT32 InfoType, INT32 ECXValue)

{

if (NULL==CPUInfo) return;

_asm{

// load 读取参数寄存器

mov edi, CPUInfo; // 准备用edi寻址CPUInfo

mov eax, InfoType;

mov ecx, ECXValue;

// CPUID

cpuid;

// save 寄存器保存CPUInfo

mov [edi], eax;

mov [edi+4], ebx;

mov [edi+8], ecx;

mov [edi+12], edx;

}

}

#endif // #if _MSC_VER < 1600 // VS2011 据说VC2008 SP1才支持__cpuidex

#if _MSC_VER < 1400 // VC2005才支持__cpuid

void __cpuid(INT32 CPUInfo[4], INT32 InfoType)

{

__cpuidex(CPUInfo, InfoType, 0);

}

#endif // #if _MSC_VER < 1400 // VC2005才支持__cpuid

#endif // #if defined(_WIN64)

// 取CPU厂商(Vendor)

//

// result: 功返字符串度(般12)失败返0

// pvendor: 接收厂商信息字符串缓冲区至少13字节

int cpu_getvendor(char pvendor)

{

INT32 dwBuf[4];

if (NULL==pvendor) return 0;

// Function 0: Vendor-ID and Largest Standard Function

__cpuid(dwBuf, 0);

// save 保存pvendor

(INT32)&pvendor[0] = dwBuf[1]; // ebx: 前四字符

(INT32)&pvendor[4] = dwBuf[3]; // edx: 间四字符

(INT32)&pvendor[8] = dwBuf[2]; // ecx: 四字符

pvendor[12] = '\0';

return 12;

}

// 取CPU商标(Brand)

//

// result: 功返字符串度(般48)失败返0

// pbrand: 接收商标信息字符串缓冲区至少49字节

int cpu_getbrand(char pbrand)

{

INT32 dwBuf[4];

if (NULL==pbrand) return 0;

// Function 0x80000000: Largest Extended Function Number

__cpuid(dwBuf, 0x80000000);

if (dwBuf[0] < 0x80000004) return 0;

// Function 80000002h,80000003h,80000004h: Processor Brand String

__cpuid((INT32)&pbrand[0], 0x80000002); // 前16字符

__cpuid((INT32)&pbrand[16], 0x80000003); // 间16字符

__cpuid((INT32)&pbrand[32], 0x80000004); // 16字符

pbrand[48] = '\0';

return 48;

}

int _tmain(int argc, _TCHAR argv[])

{

//__cpuidex(dwBuf, 0,0);

//__cpuid(dwBuf, 0);

//printf("%8X\t%8X\t%8X\t%8X\n", dwBuf[0],dwBuf[1],dwBuf[2],dwBuf[3]);

cpu_getvendor(szBuf);

printf("CPU Vendor:\t%s\n", szBuf);

cpu_getbrand(szBuf);

printf("CPU Name:\t%s\n", szBuf);

return 0;

}

六、兼容性说明

VC编译器32/64位支持性——

32位:VC6早支持编译32位Intrinsics函数

64位:VC2005早支持编译64位Intrinsics函数

本文32位编译器兼容性——

__cpuid:兼容VC6(或更高)

__cpuidex:兼容VC6(或更高)

本文64位编译器兼容性——

__cpuid:兼容VC2005(或更高)

__cpuidex:兼容VC2011(或更高)

以上就是关于VC++ MFC如何获取CPU ID及硬盘的序列号全部的内容,包括:VC++ MFC如何获取CPU ID及硬盘的序列号、VC程序员标准电脑CPU配置、如何计算一个vc程序需要多大的内存和什么cpu等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/10628468.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-10
下一篇2023-05-10

发表评论

登录后才能评论

评论列表(0条)

    保存