Win32 API无法获取计算机UUID



我想检索一台机器的UUID。

我想要类似的东西,但使用Win32 API:

wmic-cproduct获取"UUID">

我不希望依赖WMI。

下面是代码示例:(使用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%02Xn",
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%02Xn",
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 %dn", 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 errorn");
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 : %sn", dmi_string(h, p[0x4]));
printf("tBIOS Version: %sn", dmi_string(h, p[0x5]));
printf("tRelease Date: %sn", dmi_string(h, p[0x8]));
if (p[0x16] != 0xff && p[0x17] != 0xff)
printf("tEC version: %d.%dn", p[0x16], p[0x17]);
flag = 0;
}

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

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

尽管您可以使用GetSystemFirmwareTable((检索原始SMBIOS数据,但Windows SMBIOS驱动程序实际上会在HKLMHARDWAREDESCRIPTIONSystemBIOSComputerHardwareId下的注册表中写入大多数类型1定义的值。

只需读取注册表值就可以获得机器UUID,而无需查看原始SMBIOS数据。

下面是一个Win32函数的片段,它应该只检索机器的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;
}

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

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

基于Strive Sun的代码,我创建了一个头库,允许您将uuid放入提供的缓冲区:

#include <Windows.h>
#include <string.h>
#include <tchar.h>
#include <stdio.h>
#include "system-uuid.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 int format_system_uuid(const BYTE *p, int ver, char *buf, int size)
{
if (ver >= 0x0206){
return snprintf(buf, size,
"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
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{
return snprintf(buf, size,
"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
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]);
}
}

char* get_system_uuid(char *out_buf, int size){
int bufsize = 0;
BYTE bios_buf[65536] = { 0 };
RawSMBIOSData *Smbios = (RawSMBIOSData *)bios_buf;
bufsize = GetSystemFirmwareTable('RSMB', 0, 0, 0);
if (!bufsize)
{
return NULL;
}
if(!GetSystemFirmwareTable('RSMB', 0, Smbios, bufsize)){
return NULL;
}
if (Smbios->Length != bufsize - 8)
{
return NULL;
}
BYTE *raw_smbios_ptr = (BYTE *)Smbios->SMBIOSTableData;
for (unsigned int i = 0; i < Smbios->Length; i++){
dmi_header *header_ptr = (dmi_header *)raw_smbios_ptr;
if (header_ptr->type == 1){
int formatted_len = format_system_uuid(raw_smbios_ptr + 0x8,
Smbios->SMBIOSMajorVersion * 0x100 + Smbios->SMBIOSMinorVersion,
out_buf,
size);
return out_buf;
}
raw_smbios_ptr += header_ptr->length;
while (*(WORD *)raw_smbios_ptr != 0){
raw_smbios_ptr++;
}
raw_smbios_ptr += 2;
}
return NULL;
}

最新更新