Win32 API 获取机器 UUID

Posted

技术标签:

【中文标题】Win32 API 获取机器 UUID【英文标题】:Win32 API to get Machine UUID 【发布时间】:2020-06-27 05:32:28 【问题描述】:

我正在寻找一台机器的 UUID。

我想要等效的,但使用 Win32 API 代替:

wmic csproduct 获取“UUID”

我不想依赖 WMI。

【问题讨论】:

您介意分享一下您为什么不依赖 WMI 吗?也许您可以通过编程方式获取 UUID(取决于 wbemuuid 库)。 自己生成随机 uuid 并保存,而不是从您保存的地方取出 AFAIK,没有 Win32 API 来获取机器 UUID,除非你可以在注册表中的某个地方找到它。 WMI Win32_ComputerSystemProduct 文档说 UUID“来自 SMBios 信息中 System Information 结构的 UUID 成员”并且没有 Win32 API 来读取 BIOS 数据,但是有 WMI 类.不过,通用应用可以使用GetSystemFirmwareTable() @RemyLebeau GetSystemFirmwareTable 是一个 Win32 API(Win32 和 UWP 应用都可以使用)。 【参考方案1】:

这是代码示例:(使用GetSystemFirmwareTable)

GetSystemFirmwareTable:从中检索指定的固件表 固件表提供程序。

#include <Windows.h>
#include <string>
#include <tchar.h>


typedef struct _dmi_header

    BYTE type;
    BYTE length;
    WORD handle;
dmi_header;



typedef struct _RawSMBIOSData

    BYTE    Used20CallingMethod;
    BYTE    SMBIOSMajorVersion;
    BYTE    SMBIOSMinorVersion;
    BYTE    DmiRevision;
    DWORD   Length;
    BYTE    SMBIOSTableData[];
RawSMBIOSData;


static void dmi_system_uuid(const BYTE *p, short ver)

    int only0xFF = 1, only0x00 = 1;
    int i;

    for (i = 0; i < 16 && (only0x00 || only0xFF); i++)
    
        if (p[i] != 0x00) only0x00 = 0;
        if (p[i] != 0xFF) only0xFF = 0;
    



    if (only0xFF)
    
        printf("Not Present");
        return;
    

    if (only0x00)
    
        printf("Not Settable");
        return;
    


    if (ver >= 0x0206)
        printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
            p[3], p[2], p[1], p[0], p[5], p[4], p[7], p[6],
            p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
    else
        printf("-%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
            p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
            p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);



const char *dmi_string(const dmi_header *dm, BYTE s)

    char *bp = (char *)dm;
    size_t i, len;

    if (s == 0)
        return "Not Specified";

    bp += dm->length;

    while (s > 1 && *bp)
    
        bp += strlen(bp);
        bp++;
        s--;
    
    if (!*bp)
        return "BAD_INDEX";

    /* ASCII filtering */
    len = strlen(bp);
    for (i = 0; i < len; i++)
        if (bp[i] < 32 || bp[i] == 127)
            bp[i] = '.';
    return bp;




int _tmain(int argc, _TCHAR* argv[])

    DWORD bufsize = 0;
    BYTE buf[65536] =  0 ;
    int ret = 0;
    RawSMBIOSData *Smbios;
    dmi_header *h = NULL;
    int flag = 1;

    ret = GetSystemFirmwareTable('RSMB', 0, 0, 0);
    if (!ret)
    
        printf("Function failed!\n");
        return 1;
    

    printf("get buffer size is %d\n", ret);
    bufsize = ret;

    ret = GetSystemFirmwareTable('RSMB', 0, buf, bufsize);

    if (!ret)
    
        printf("Function failed!\n");
        return 1;
    



    Smbios = (RawSMBIOSData *)buf;
    BYTE *p = Smbios->SMBIOSTableData;

    if (Smbios->Length != bufsize - 8)
    
        printf("Smbios length error\n");
        return 1;
    

    for (int i = 0; i < Smbios->Length; i++) 
        h = (dmi_header *)p;

        if (h->type == 0 && flag) 
            printf("\nType %02d - [BIOS]\n", h->type);
            printf("\tBIOS Vendor : %s\n", dmi_string(h, p[0x4]));
            printf("\tBIOS Version: %s\n", dmi_string(h, p[0x5]));
            printf("\tRelease Date: %s\n", dmi_string(h, p[0x8]));

            if (p[0x16] != 0xff && p[0x17] != 0xff)
                printf("\tEC version: %d.%d\n", p[0x16], p[0x17]);
            flag = 0;
        



        else if (h->type == 1) 
            printf("\nType %02d - [System Information]\n", h->type);
            printf("\tManufacturer: %s\n", dmi_string(h, p[0x4]));
            printf("\tProduct Name: %s\n", dmi_string(h, p[0x5]));
            printf("\tVersion: %s\n", dmi_string(h, p[0x6]));
            printf("\tSerial Number: %s\n", dmi_string(h, p[0x7]));
            printf("\tUUID: "); dmi_system_uuid(p + 0x8, Smbios->SMBIOSMajorVersion * 0x100 + Smbios->SMBIOSMinorVersion);
            printf("\tSKU Number: %s\n", dmi_string(h, p[0x19]));
            printf("\tFamily: %s\n", dmi_string(h, p[0x1a]));
        
        p += h->length;
        while ((*(WORD *)p) != 0) p++;
        p += 2;
    

    getchar();
    return 0;


【讨论】:

【参考方案2】:

机器 UUID 由系统信息(类型 1)结构中的 SMBIOS v2.1+(系统管理 BIOS (SMBIOS))定义。

虽然您可以使用GetSystemFirmwareTable() 检索原始 SMBIOS 数据,但 Windows SMBIOS 驱动程序实际上将大部分类型 1 定义的值写入注册表中的HKLM\HARDWARE\DESCRIPTION\System\BIOS\ComputerHardwareId 下。

只需读取注册表值即可为您提供机器 UUID,而无需查看原始 SMBIOS 数据。

这是一个 Win32 函数的 sn-p,它应该只检索机器的 UUID。 (未经测试)

#include <windows.h>
#include <winerror.h>
static HRESULT GetMachineUUID(
        /* [out] */ WCHAR **ppszMachineUUID)

    HRESULT hr = S_OK;
    LPWSTR pszMachineUUID = NULL;
    DWORD cbMachineUUID = 0;
    DWORD cchMachineUUID = 0;
    LONG lResult = ERROR_SUCCESS;

    lResult = RegGetValue(HKEY_LOCAL_MACHINE,
                L"HARDWARE\\DESCRIPTION\\System\\BIOS",
                L"ComputerHardwareId",
                RRF_RT_REG_SZ, NULL,
                pszMachineUUID,
                &cbMachineUUID);

    if (ERROR_MORE_DATA == lResult || ERROR_SUCCESS == lResult)
    
        cchMachineUUID = (cbMachineUUID / sizeof(WCHAR));

        pszMachineUUID = SysAllocStringLen(NULL, cchMachineUUID);

        if (pszMachineUUID == NULL)
        
            hr = E_OUTOFMEMORY;
            goto Error;
        

        lResult = RegGetValue(HKEY_CLASSES_ROOT,
                    bstrNodeName,
                    sc_szV2CSPNodePathRegValueName,
                    RRF_RT_REG_SZ,
                    NULL,
                    pszMachineUUID,
                    &cbMachineUUID);

        hr = HRESULT_FROM_WIN32(lResult);

        if (FAILED(hr))
        
            goto Error;
        
    
    else
    
        hr = HRESULT_FROM_WIN32(lResult);

        if (FAILED(hr))
        
            goto Error;
        
    

    *ppszMachineUUID = pszMachineUUID;
    pszMachineUUID = NULL;

Error:
    SysFreeString(pszMachineUUID);
    return hr;

我还没有测试过上面的代码,但它应该可以工作。

请参阅https://www.dmtf.org/standards/smbios 上发布的最新 SMBIOS 参考规范

【讨论】:

以上是关于Win32 API 获取机器 UUID的主要内容,如果未能解决你的问题,请参考以下文章

转 python通过win32api轻松获取控件的属性值

如何使用 win32 api 获取域用户帐户列表?

python --获取本机屏幕分辨率

如何从 Win32 API 中的总线关系中获取设备实例路径

<Win32 API> 获取系统文件夹路径

<Win32 API> 获取系统文件夹路径