在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
}

获取物理内存容量[3]

void GetTotalPhysicalMemorySize(DWORDLONG* sizeInByte)
{
    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;
}

其实还可以用一个黑科技拿到更多的硬件信息,比如主板型号之类的,但是作为UWP上商店的话需要一个restricted capability,所以基本上就GG了……

参考资料:
[1] __cpuid, __cpuidex
[2] GetSystemInfo function
[3] GlobalMemoryStatusEx function

» 转载请注明来源及链接:未来代码研究所

Related Posts:

4 Responses to “在C++/CX中获取基本硬件信息”

Leave a Reply

World Line
Time Machine
Online Tools