在UWP开发中可以使用如下代码,通过C++/CX调用系统相关接口获取一些基本的硬件信息。
获取CPU型号和架构
原理是利用x86/x64处理器的__cpuid
指令[1]获得CPU的型号字符串(故无法在ARM平台运行),然后通过GetSystemInfo
[2]获取CPU架构信息:
void GetCpuInfo(String^* name, int* archId)
{
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
*archId = (int)systemInfo.wProcessorArchitecture;
#ifndef _M_ARM
const int ARRAY_SIZE = 0x40;
int cpuInfo[4] = { -1 };
char cpuBrandStr[ARRAY_SIZE];
__cpuid(cpuInfo, 0x80000000);
unsigned int nExIdCount = cpuInfo[0];
for (unsigned int i = 0x80000000; i <= nExIdCount; ++i)
{
__cpuid(cpuInfo, i);
if (i == 0x80000002)
{
memcpy(cpuBrandStr, cpuInfo, sizeof(cpuInfo));
}
else if (i == 0x80000003)
{
memcpy(cpuBrandStr + 16, cpuInfo, sizeof(cpuInfo));
}
else if (i == 0x80000004)
{
memcpy(cpuBrandStr + 32, cpuInfo, sizeof(cpuInfo));
}
}
cpuBrandStr[ARRAY_SIZE - 1] = 0;
size_t oldSize = strlen(cpuBrandStr) + 1;
const size_t newsize = ARRAY_SIZE * sizeof(wchar_t);
size_t convertedCharCount = 0;
wchar_t newStr[newsize];
mbstowcs_s(&convertedCharCount, newStr, oldSize, cpuBrandStr, _TRUNCATE);
*name = ref new String(newStr);
#endif
}
{
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
*archId = (int)systemInfo.wProcessorArchitecture;
#ifndef _M_ARM
const int ARRAY_SIZE = 0x40;
int cpuInfo[4] = { -1 };
char cpuBrandStr[ARRAY_SIZE];
__cpuid(cpuInfo, 0x80000000);
unsigned int nExIdCount = cpuInfo[0];
for (unsigned int i = 0x80000000; i <= nExIdCount; ++i)
{
__cpuid(cpuInfo, i);
if (i == 0x80000002)
{
memcpy(cpuBrandStr, cpuInfo, sizeof(cpuInfo));
}
else if (i == 0x80000003)
{
memcpy(cpuBrandStr + 16, cpuInfo, sizeof(cpuInfo));
}
else if (i == 0x80000004)
{
memcpy(cpuBrandStr + 32, cpuInfo, sizeof(cpuInfo));
}
}
cpuBrandStr[ARRAY_SIZE - 1] = 0;
size_t oldSize = strlen(cpuBrandStr) + 1;
const size_t newsize = ARRAY_SIZE * sizeof(wchar_t);
size_t convertedCharCount = 0;
wchar_t newStr[newsize];
mbstowcs_s(&convertedCharCount, newStr, oldSize, cpuBrandStr, _TRUNCATE);
*name = ref new String(newStr);
#endif
}
获取物理内存容量[3]
void GetTotalPhysicalMemorySize(DWORDLONG* sizeInByte)
{
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
*sizeInByte = status.ullTotalPhys;
}
{
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
*sizeInByte = status.ullTotalPhys;
}
获取所有显卡名称和显存容量
原理是利用DirectX相关的接口获取:
#include <d3d11.h>
#include <dxgi.h>
bool GetGraphicAdapterInfo(Array<String^>^* nameArray, Array<UINT64>^* memoryArray)
{
D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_9_1 };
ID3D11Device* pDevice = nullptr;
HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, &pDevice, nullptr, nullptr);
if (FAILED(hr))
{
return false;
}
IDXGIDevice* pDxgiDevice = nullptr;
hr = pDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&pDxgiDevice));
if (FAILED(hr))
{
return false;
}
IDXGIAdapter* pDxgiAdapter = nullptr;
hr = pDxgiDevice->GetAdapter(&pDxgiAdapter);
if (FAILED(hr))
{
return false;
}
IDXGIFactory* pIDxgiFactory = nullptr;
hr = pDxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&pIDxgiFactory));
if (FAILED(hr))
{
return false;
}
UINT count = 0;
std::vector<IDXGIAdapter*> vAdapters;
IDXGIAdapter* pAdapter;
while (pIDxgiFactory->EnumAdapters(count, &pAdapter) != DXGI_ERROR_NOT_FOUND)
{
vAdapters.push_back(pAdapter);
count++;
}
if (count > 0)
{
*nameArray = ref new Array<String^>(count);
*memoryArray = ref new Array<UINT64>(count);
auto i = 0;
for (auto iterator = vAdapters.begin(); iterator != vAdapters.end(); ++iterator)
{
DXGI_ADAPTER_DESC desc;
(*iterator)->GetDesc(&desc);
(*nameArray)[i] = ref new String(desc.Description);
(*memoryArray)[i] = desc.DedicatedVideoMemory;
i++;
}
}
return true;
}
#include <dxgi.h>
bool GetGraphicAdapterInfo(Array<String^>^* nameArray, Array<UINT64>^* memoryArray)
{
D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_9_1 };
ID3D11Device* pDevice = nullptr;
HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, &pDevice, nullptr, nullptr);
if (FAILED(hr))
{
return false;
}
IDXGIDevice* pDxgiDevice = nullptr;
hr = pDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&pDxgiDevice));
if (FAILED(hr))
{
return false;
}
IDXGIAdapter* pDxgiAdapter = nullptr;
hr = pDxgiDevice->GetAdapter(&pDxgiAdapter);
if (FAILED(hr))
{
return false;
}
IDXGIFactory* pIDxgiFactory = nullptr;
hr = pDxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&pIDxgiFactory));
if (FAILED(hr))
{
return false;
}
UINT count = 0;
std::vector<IDXGIAdapter*> vAdapters;
IDXGIAdapter* pAdapter;
while (pIDxgiFactory->EnumAdapters(count, &pAdapter) != DXGI_ERROR_NOT_FOUND)
{
vAdapters.push_back(pAdapter);
count++;
}
if (count > 0)
{
*nameArray = ref new Array<String^>(count);
*memoryArray = ref new Array<UINT64>(count);
auto i = 0;
for (auto iterator = vAdapters.begin(); iterator != vAdapters.end(); ++iterator)
{
DXGI_ADAPTER_DESC desc;
(*iterator)->GetDesc(&desc);
(*nameArray)[i] = ref new String(desc.Description);
(*memoryArray)[i] = desc.DedicatedVideoMemory;
i++;
}
}
return true;
}
其实还可以用一个黑科技拿到更多的硬件信息,比如主板型号之类的,但是作为UWP上商店的话需要一个restricted capability,所以基本上就GG了……
参考资料:
[1] __cpuid, __cpuidex
[2] GetSystemInfo function
[3] GlobalMemoryStatusEx function
» 转载请注明来源及链接:未来代码研究所
ARM EL0 读不了 MIDR 所以获取 CPU 信息基本上没啥戏了(
https://github.com/google/cpu_features 可能更直接一点。
它用的不也是_cpuid(__cpuidex)吗,有啥区别……
区别是不用管跨平台的东西。。