作业要求
/*
用Visual Studio 编写一个控制台程序,功能如下:
一、使用SMBIOS读取本机的MEMORY信息,并打印一下信息
[MEMORY]
NUM = 2
SIZE=32GB
[0]
LOCATOR=DIMM1
SIZE=16GB
TYPE=DDR4
SPEED=2666MHZ
MANUFACTURER=Micron
[1]
LOCATOR=DIMM1
SIZE=16GB
TYPE=DDR4
SPEED=2666MHZ
MANUFACTURER=Micron
注:可以参考RW上SMBIOS信息对照
*/
头文件
#pragma once //只编译一次,节省时间
/*包含的头文件*/
#include<stdio.h>
#include<string>
#include<iostream>
#include<windows.h>
#include <SDKDDKVer.h>
#include <tchar.h>
/*使用命名空间*/
using namespace std;
//保存之前的结构体对齐方式
#pragma pack(push)
//使用新的结构体对齐方式
#pragma pack(1)
声明结构体
/*存储SMBIOS信息的长度和尾部地址*/
typedef struct _RawSMBIOSData
{
DWORD Length;
PBYTE* SMBIOSTableData;
} RawSMBIOSData, * PRawSMBIOSData;
/*存储各TYPE的三类信息*/
typedef struct _SMBIOSHEADER_
{
BYTE Type;
BYTE Length;
WORD Handle;
} SMBIOSHEADER, * PSMBIOSHEADER;
/*存储TYPE16信息*/
typedef struct _TYPE_16_ {
SMBIOSHEADER Header;
UCHAR Location;
UCHAR Use;
UCHAR MemoryErrorCorrection;
ULONG32 MaximumCapacity;
UINT16 MemoryErrorHandle;
UINT16 NumberofMemoryDevices;
ULONG32 ExtendedMaximumCapacity;
} PhysicalMemoryArray, * PPhysicalMemoryArray;
/*存储TYPE17信息*/
typedef struct _TYPE_17_ {
SMBIOSHEADER Header;
UINT16 PhysicalArrayHandle;
UINT16 ErrorInformationHandle;
UINT16 TotalWidth;
UINT16 DataWidth;
UINT16 Size;
UCHAR FormFactor;
UCHAR DeviceSet;
UCHAR DeviceLocator;
UCHAR BankLocator;
UCHAR MemoryType;
UINT16 TypeDetail;
UINT16 Speed;
UCHAR Manufacturer;
UCHAR SN;
UCHAR AssetTag;
UCHAR PN;
UCHAR Attributes;
} MemoryDevice, * PMemoryDevice;
枚举Memory type
enum _MemoryType_
{
Other = 1, Un_known, DRAM, EDRAM,
VRAM, SRAM, RAM, ROM, FLASH,
EEPROM, FEPROM, EPROM, CDRAM,
RAM_3D, SDRAM, SGRAM, RDRAM,
DDR, DDR2, DDR2_FB_DIMM, Reserved_1,
Reserved_2, Reserved_3,DDR3, FBD2, DDR4,
LPDDR, LPDDR2, LPDDR3,LPDDR4,
Logicalnonvolatiledevice,HBM, HBM2, DDR5, LPDDR5
};
//自定义对齐方式结束
#pragma pack(pop)
字符编码
/*根据编码选择字符解析方式*/
#ifdef UNICODE
#define LocateString LocateStringW
#else
#define LocateString LocateStringA
#endif
几个函数
/*返回信息尾部地址*/
const char* toPointString(void* p)
{
return (char*)p + ((PSMBIOSHEADER)p)->Length;
}
/*解析字符串*/
const char* LocateStringA(const char* str, UINT i)
{
static const char strNull[] = "Null String";
if (0 == i || 0 == *str) return strNull;
while (--i)
{
str += strlen((char*)str) + 1;
}
return str;
}
/*解析字符串*/
const wchar_t* LocateStringW(const char* str, UINT i)
{
static wchar_t buff[2048];
const char* pStr = LocateStringA(str, i);
SecureZeroMemory(buff, sizeof(buff));
MultiByteToWideChar(CP_OEMCP, 0, pStr, (int)strlen(pStr), buff, sizeof(buff));
return buff;
}
/*输出TYPE16信息*/
bool ProcPhysicalMemoryArray(void* p)
{
PPhysicalMemoryArray pMAMA = (PPhysicalMemoryArray)p;
const char* str = toPointString(p);
_tprintf(TEXT("NUM = %d\n"), pMAMA->NumberofMemoryDevices);
_tprintf(TEXT("SIZE=%dGB\n"), pMAMA->MaximumCapacity / 1024 / 1024);
return true;
}
/*输出TYPE17信息*/
bool ProcMemoryDevice(void* p)
{
PMemoryDevice pMD = (PMemoryDevice)p;
const char* str = toPointString(p);
_tprintf(TEXT("LOCATOR=%s\n"), LocateString(str, pMD->DeviceLocator));
_tprintf(TEXT("SIZE=%dGB\n"), pMD->Size / 1024);
switch (pMD->MemoryType)
{
case Other:_tprintf(TEXT("TYPE=0x%02X Other\n"),pMD->MemoryType); break;
case Un_known:_tprintf(TEXT("TYPE=0x%02X Unknown\n"), pMD->MemoryType); break;
case DDR3:_tprintf(TEXT("TYPE=0x%02X DDR3\n"), pMD->MemoryType); break;
case DDR4:_tprintf(TEXT("TYPE=0x%02X DDR4\n"), pMD->MemoryType); break;
}
if (pMD->Header.Length > 0x15)
{
_tprintf(TEXT("SPEED=%dMHZ\n"), pMD->Speed);
_tprintf(TEXT("MANUFACTURER=%s\n"), LocateString(str, pMD->Manufacturer));
}
return true;
}
/*根据需求调用bool函数*/
bool DispatchStructType(PSMBIOSHEADER hdr)
{
typedef struct {
BYTE t;
bool(*Proc)(void* p);
} TPFUNC;
const TPFUNC tpfunc[] = {
{ 16, ProcPhysicalMemoryArray},
{ 17, ProcMemoryDevice },
};
for (UINT i = 0; i < sizeof(tpfunc) / sizeof(TPFUNC); i++)
{
if (tpfunc[i].t == hdr->Type)
{
tpfunc[i].Proc((void*)hdr);
return true;
}
}
return false;
}
/*选择要打印的SMBIOS信息*/
void DumpSMBIOSStruct(void* Addr, UINT Len)
{
int i = 0;
LPBYTE p = (LPBYTE)(Addr);
const LPBYTE lastAddress = p + Len;
PSMBIOSHEADER pHeader;
for (;;)
{
pHeader = (PSMBIOSHEADER)p;
if (pHeader->Type == 16)
{
_tprintf(TEXT("[Memory]\n"));
DispatchStructType(pHeader);
_tprintf(TEXT("\n"));
}
if (pHeader->Type == 17)
{
_tprintf(TEXT("[%d]\n"), i);
i++;
DispatchStructType(pHeader);
_tprintf(TEXT("\n"));
}
if ((pHeader->Type == 127) && (pHeader->Length == 4))
{
break;
}
LPBYTE nt = p + pHeader->Length;
while (0 != (*nt | *(nt + 1))) nt++;
nt += 2;
if (nt >= lastAddress)
break;
p = nt;
}
}
主函数
/*主函数*/
int _tmain(int nAgrv,char* argv[])
{
/*_MemoryType_ zzz;
zzz = _MemoryType_(18);
printf("%d\n", zzz);*/
DWORD needBufferSize = 0;
const BYTE byteSignature[] = { 'B','M','S','R' };
const DWORD Signature = *((DWORD*)byteSignature);
LPBYTE pBuff = NULL;
/*调用接口获取信息长度*/
needBufferSize = GetSystemFirmwareTable(Signature, 0, NULL, 0);
/*根据信息长度开辟内存空间*/
pBuff = (LPBYTE)malloc(needBufferSize);
if (pBuff)
{
//再次调用接口获取信息
GetSystemFirmwareTable(Signature, 0, pBuff, needBufferSize);
const PRawSMBIOSData pDMIData = (PRawSMBIOSData)pBuff;
DumpSMBIOSStruct(&(pDMIData->SMBIOSTableData), pDMIData->Length);
}
}
总结
是根据一篇从网上找到的现有代码,经过一定删减,并根据Type17结构体写法设计出Type16的结构体,最终筛选出所需信息,然而觉得硬件还是相当难搞。