4

我有这个 C# 代码来获取处理器 ID,但我无法将它传递给 C++,我尝试了很多但我真的做不到,我刚开始使用 C++,我希望能够获得 CPU ID就像我以前用 C# 得到的 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);
}
4

2 回答 2

6

在 C++ 中它有点长!这是一个完整的工作示例,请注意,如果您将查询从

SELECT ProcessorId FROM Win32_Processor

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 指令的处理器支持。如果支持该指令,则该属性包含 2(两个)DWORD 格式的值。第一个是偏移量 08h-0Bh,这是 CPUID 指令在输入 EAX 设置为 1 时返回的 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++-ish 实现。

于 2012-04-19T13:58:45.000 回答
0
  1. 如果只是将获得的字符串类型的处理器ID(托管代码)发送到非托管代码(c++)的问题,那么您可以尝试各种选项,例如使用COM接口或通过一些中间CLR CLI接口或使用正常的本机dll编写自己编组代码。

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

于 2012-04-19T14:07:43.767 回答