从C#获取CPU ID代码并在C++中使用

4

我有这段用于获取处理器ID的C#代码,但我无法将其传递给C++,尽管我尝试了很多次,但我真的做不到。我刚刚开始接触C++,希望能够像以前在C#中获取CPU ID那样,在C++中获取它。

这是我在C#中拥有的代码:

public static string GetProcessorID()
{
  string sProcessorID = "";
  string sQuery = "SELECT ProcessorId FROM Win32_Processor";
  ManagementObjectSearcher oManagementObjectSearcher = new ManagementObjectSearcher(sQuery);
  ManagementObjectCollection oCollection = oManagementObjectSearcher.Get();
  foreach (ManagementObject oManagementObject in oCollection)
  {
    sProcessorID = (string)oManagementObject["ProcessorId"];
  }

  return (sProcessorID);
}

请查看此链接:https://dev59.com/z1bTa4cB1Zd3GeqP8jR2 - Lucian
我已经阅读了这篇文章,根据那篇文章,我需要访问以下网址:http://msdn.microsoft.com/en-us/library/hskdteyh%28v=vs.80%29.aspx。我确实访问了该网址,但其中包含了很多我不确定是否需要的信息。输出是各种类型CPU的十六进制值,我不理解它。 - Luiza Nunes
2个回答

6

在C++中可能会有点长!这是一个完整的工作示例,请注意,如果您更改查询,则需要相应地更改“query”字符串。

SELECT ProcessorId FROM Win32_Processor

to

SELECT * FROM Win32_Processor

然后您可以使用QueryValue函数查询任何属性值。
HRESULT GetCpuId(char* cpuId, int bufferLength)
{
    HRESULT result = InitializeCom();
    if (FAILED(result))
        return result;

    IWbemLocator* pLocator = NULL;
    IWbemServices* pService = NULL;
    result = GetWbemService(&pLocator, &pService);
    if (FAILED(result))
    {
        CoUninitialize();
        return result;
    }

    memset(cpuId, 0, bufferLength);
    result = QueryValue(pService, 
            L"SELECT ProcessorId FROM Win32_Processor", L"ProcessorId",
            cpuId, bufferLength);

    if (FAILED(result))
    {
        pService->Release();
        pLocator->Release();
        CoUninitialize();

        return result;
    }

    pService->Release();
    pLocator->Release();
    CoUninitialize();

    return NOERROR;
}

首先,您需要完成所有初始化工作,它们被封装在这两个函数中:

HRESULT InitializeCom()
{
    HRESULT result = CoInitializeEx(0, COINIT_APARTMENTTHREADED); 
    if (FAILED(result))
        return result;

    result = CoInitializeSecurity(
        NULL,                           // pSecDesc
        -1,                             // cAuthSvc (COM authentication)
        NULL,                           // asAuthSvc
        NULL,                           // pReserved1
        RPC_C_AUTHN_LEVEL_DEFAULT,      // dwAuthnLevel
        RPC_C_IMP_LEVEL_IMPERSONATE,    // dwImpLevel
        NULL,                           // pAuthList
        EOAC_NONE,                      // dwCapabilities
        NULL                            // Reserved
        );

    if (FAILED(result) && result != RPC_E_TOO_LATE)
    {
        CoUninitialize();

        return result;
    }

    return NOERROR;
}

HRESULT GetWbemService(IWbemLocator** pLocator, IWbemServices** pService)
{
    HRESULT result = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, 
        IID_IWbemLocator, reinterpret_cast<LPVOID*>(pLocator));

    if (FAILED(result))
    {
        return result;
    }

    result = (*pLocator)->ConnectServer(
        _bstr_t(L"ROOT\\CIMV2"),    // strNetworkResource
        NULL,                       // strUser  
        NULL,                       // strPassword
        NULL,                       // strLocale
        0,                          // lSecurityFlags
        NULL,                       // strAuthority
        NULL,                       // pCtx
        pService                    // ppNamespace
        );

    if (FAILED(result))
    {
        (*pLocator)->Release();     

        return result;
    }

    result = CoSetProxyBlanket(
        *pService,                      // pProxy
        RPC_C_AUTHN_WINNT,              // dwAuthnSvc
        RPC_C_AUTHZ_NONE,               // dwAuthzSvc
        NULL,                           // pServerPrincName
        RPC_C_AUTHN_LEVEL_CALL,         // dwAuthnLevel
        RPC_C_IMP_LEVEL_IMPERSONATE,    // dwImpLevel
        NULL,                           // pAuthInfo
        EOAC_NONE                       // dwCapabilities
        );

    if (FAILED(result))
    {
        (*pService)->Release();
        (*pLocator)->Release();     

        return result;
    }

    return NOERROR;
}

完成这个步骤后,你可以运行WQL查询,然后枚举返回的属性以找到你需要的那个属性(尽管可能有更简单的方法,但通过这种方式可以查询多个值)。请注意,如果你从Win32_Processor查询所有值,则会得到大量数据。在某些系统上,我曾经看到它需要2秒钟才能完成查询和枚举属性(因此请过滤查询,仅包括你需要的数据)。

HRESULT QueryValue(IWbemServices* pService, const wchar_t* query, const wchar_t* propertyName, char* propertyValue, int maximumPropertyValueLength)
{
    USES_CONVERSION;

    IEnumWbemClassObject* pEnumerator = NULL;
    HRESULT result = pService->ExecQuery(
        bstr_t(L"WQL"),                                         // strQueryLanguage
        bstr_t(query),                                          // strQuery
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,  // lFlags
        NULL,                                                   // pCtx
        &pEnumerator                                            // ppEnum
        );

    if (FAILED(result))
        return result;

    IWbemClassObject *pQueryObject = NULL;
    while (pEnumerator)
    {
        try
        {
            ULONG returnedObjectCount = 0;
            result = pEnumerator->Next(WBEM_INFINITE, 1, &pQueryObject, &returnedObjectCount);

            if (returnedObjectCount == 0)
                break;

            VARIANT objectProperty;
            result = pQueryObject->Get(propertyName, 0, &objectProperty, 0, 0);
            if (FAILED(result))
            {
                if (pEnumerator != NULL)
                    pEnumerator->Release();

                if (pQueryObject != NULL)
                    pQueryObject->Release();

                return result;
            }

            if ((objectProperty.vt & VT_BSTR) == VT_BSTR)
            {
                strcpy_s(propertyValue, maximumPropertyValueLength, OLE2A(objectProperty.bstrVal));
                break;
            }

            VariantClear(&objectProperty);
        }
        catch (...)
        {
            if (pEnumerator != NULL)
                pEnumerator->Release();

            if (pQueryObject != NULL)
                pQueryObject->Release();

            return NOERROR;
        }
    } 

    if (pEnumerator != NULL)
        pEnumerator->Release();

    if (pQueryObject != NULL)
        pQueryObject->Release();

    return NOERROR;
}

注意: 如果您需要收集比CPU的简单ID更多的信息,则此代码很有用。这是一个通用示例,可从WQL查询(与C#中所做的一样)获取一个(或多个)属性。如果您不需要获取任何其他信息(并且您不打算在C++程序中使用WMI),则可以使用如评论中发布的__cpuid()内置函数。

__cpuid()

来自WMI的ProcessorId属性具有以下描述:

描述处理器功能的处理器信息。对于x86类CPU,字段格式取决于CPUID指令的处理器支持情况。如果支持该指令,则属性包含两个DWORD格式的值。第一个是08h-0Bh的偏移量,它是在将输入EAX设置为1时CPUID指令返回的EAX值。第二个是0Ch-0Fh的偏移量,它是指令返回的EDX值。属性的前两个字节是显著的,并包含CPU重置时DX寄存器的内容-所有其他字节都设置为0(零),并且内容以DWORD格式表示。

一个良好的实现应该检查更多关于奇怪的情况,但是一个天真的实现可能是:

std::string GetProcessorId()
{
 int info[4] = { -1 };

 __cpuid(info, 0);
 if (info[0] < 1)
  return ""; // Not supported?!

 // Up to you...you do not need to mask results and you may use
 // features bits "as is".    
 __cpuid(info, 1);
 int family = info[0];
 int features = info[3];

 std::stringstream id;
 id << std::hex << std::setw(4) << std::setfill('0') << family << features;

 return id.str();
}

此外,这篇帖子提供了一种更好的C++实现方法。


嗯,非常感谢Adriano,您能否发布一个使用__cpuid()获取ID的小例子吗?因为我需要获取CPU识别的唯一数字以成为std::string,这样我就可以将其存储在数据库中。谢谢! - Luiza Nunes
“GetProcessorId”函数返回的值与Win32_Processor不同? - user1633272
@user 是的,稍微有些不同,但你可以调整掩码(并查看更新的文档!)以获得相同的值。 - Adriano Repetti
非常不同:ProcessId=BFEBFBFF000306A9,而GetProcessorId()返回“0600f000”。 - user1633272
更改或删除掩码,但我不知道额外的字节来自哪里(现在应该真正比较Cupid返回的内容)。 - Adriano Repetti

0
  1. 如果只是将获取的字符串类型(托管代码)ProcessorID发送到非托管代码(C++)的问题,那么您可以尝试各种选项,例如使用COM接口或通过一些中间CLR CLI接口或使用普通本机dll编写自己的编组代码。

  2. 另一种方法是创建一个C# COM接口,并从C++访问它,通过调用函数GetProcessorID()来获取sProcessorID。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接