温故而知新,可以为师矣
在检查自己过往代码的时候,又找到了一篇可以拿得出手的文章,今天就讲讲“如何获取Windows CPU”!
使用C++获取CPU信息的方式不止一种,目前我知识面可以覆盖到的方法有三种?
- 使用WMI查询
- 使用Win32提供的API查询
- 使用注册表查询
这篇文章不分重点,只讲方式,说一下这三种方式。
使用WMI
查询
不知道WMI的可以看这个百度百科👉WMI(系统插件)_百度百科
这里提供我整理的两种WMI
查询接口:
- 单个信息查询
/*
* @fn GetSingleItemInfo
* @brief 根据查询语句获得一个类成员
* @param[in] ClassName:库名如:“Win32_Processor”
ClassMember:项目名如:“SerialNumber”
* @param[out]
* @return
* @author Fuel_Ming
*/
BOOL GetSingleItemInfo( __in const wstring &ClassName,__in const wstring &ClassMember,__out wstring &RetValue )
{
USES_CONVERSION;
CComBSTR query("SELECT * FROM ");
CString CstrRetValue;
VARIANT vtProp;
ULONG uReturn;
HRESULT hr;
BOOL bRet = FALSE;
InitWmi();
if (NULL != m_pWbemSvc)
{
//查询类ClassName中的所有字段,保存到m_pEnumClsObj中
query+=CComBSTR(ClassName.c_str());
hr=m_pWbemSvc->ExecQuery(CComBSTR("WQL"), query, WBEM_FLAG_FORWARD_ONLY|WBEM_FLAG_RETURN_IMMEDIATELY,
0,&m_pEnumClsObj);
if( m_pEnumClsObj == NULL )
{
WriteError(_T("m_pEnumClsObj == NULL : %x"), hr);
goto END;
}
if (SUCCEEDED(hr))
{
//初始化vtProp值
VariantInit(&vtProp);
uReturn = 0;
//返回从当前位置起的第一个对象到m_pWbemClsObj中
hr=m_pEnumClsObj->Next( WBEM_INFINITE, 1, &m_pWbemClsObj, &uReturn);
if( m_pWbemClsObj == NULL )
{
WriteError(_T("m_pWbemClsObj == NULL : %x"), hr);
goto END;
}
if(SUCCEEDED(hr)&&uReturn>0)
{
//从m_pWbemClsObj中找出ClassMember标识的成员属性值,并保存到vtProp变量中
hr=m_pWbemClsObj->Get(CComBSTR(ClassMember.c_str()),0,&vtProp,0,0);
if (SUCCEEDED(hr))
{
VariantToString(&vtProp,CstrRetValue);
RetValue = CstrRetValue.GetString();
VariantClear(&vtProp);//清空vtProp
bRet = TRUE;
}
}
}
}
END:
ReleaseWmi();
return bRet;
}
- 按组查询
/*
* @fn GetGroupItemInfo
* @brief 根据查询语句获得一个类的多个成员
* @param[in] ClassName: 库名如:“Win32_Processor”
ClassMember:项目名如:“SerialNumber”
n: 成员个数
* @param[out] chRetValue: 返回获得的成员
* @return
*
* @detail Example:
CString strRetValue;
CString [] strClassMem =
{_T("Caption"),_T("CurrentClockSpeed"),_T("DeviceID"),_T("Manufacturer"),_T("Manufacturer")};
GetGroupItemInfo(_T("Win32_Processor"),strClassMem,5,strRetValue);
* @author Fuel_Ming
*/
BOOL CWmiIface::GetGroupItemInfo(__in const wstring &ClassName, __in const vector<wstring> &vectClassMember, __out std::vector<wstring> &vecRetValue)
{
USES_CONVERSION;
CComBSTR query("SELECT * FROM ");
CString result,info;
VARIANT vtProp;
ULONG uReturn;
HRESULT hr;
int i;
int n = vectClassMember.size();
BOOL bRet = FALSE;
InitWmi();
if (NULL != m_pWbemSvc)
{
query+=CComBSTR(ClassName.c_str());
hr=m_pWbemSvc->ExecQuery(CComBSTR("WQL"),query,WBEM_FLAG_FORWARD_ONLY|WBEM_FLAG_RETURN_IMMEDIATELY,0,&m_pEnumClsObj);
if (SUCCEEDED(hr))
{
VariantInit(&vtProp); //初始化vtProp变量
if(m_pEnumClsObj)
{
Sleep(10);
uReturn=0;
hr=m_pEnumClsObj->Next(WBEM_INFINITE,1,&m_pWbemClsObj,&uReturn);
if( m_pWbemClsObj == NULL )
{
WriteError(_T("m_pServer == NULL : %x"), hr);
goto END;
}
if (SUCCEEDED(hr) &&uReturn>0)
{
for(i = 0; i < n; ++i)
{
CString chTemp = TEXT("");
hr=m_pWbemClsObj->Get(CComBSTR(vectClassMember[i].c_str()),0,&vtProp,0,0);
if (SUCCEEDED(hr))
{
VariantToString(&vtProp,info);
chTemp = info;
VariantClear(&vtProp);
bRet = TRUE;
}
vecRetValue.push_back(chTemp.GetString());
}
}
}
}
}
END:
ReleaseWmi();
return bRet;
}
要使用WMI得先初始化接口:
HRESULT InitWmi()
{
HRESULT hr;
// 1、初始化COM组件
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
if (SUCCEEDED(hr) || RPC_E_CHANGED_MODE == hr)
{
m_bInitialize = TRUE;
hr = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
hr = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &m_pWbemLoc);
hr = m_pWbemLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"),
NULL,
NULL,
0,
NULL,
0,
0,
&m_pWbemSvc
);
if (FAILED(hr))
{
WriteError(_T("IWbemLocator::ConnectServer is failed. hr=%x"), hr);
goto END;
}
hr = CoSetProxyBlanket(
m_pWbemSvc,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE
);
if (FAILED(hr))
{
WriteError(_T("CoSetProxyBlanket is failed. hr=%x"), hr);
goto END;
}
}
return(hr);
END:
if(FAILED(hr))
{
ReleaseWmi();
}
return(hr);
}
用完记得释放:
HRESULT ReleaseWmi()
{
HRESULT hr;
if (NULL != m_pWbemSvc)
{
hr = m_pWbemSvc->Release();
m_pWbemSvc = NULL;
}
if (NULL != m_pWbemLoc)
{
hr = m_pWbemLoc->Release();
m_pWbemLoc = NULL;
}
if (NULL != m_pWbemClsObj)
{
hr = m_pWbemClsObj->Release();
m_pWbemClsObj = NULL;
}
if (NULL != m_pEnumClsObj)
{
hr = m_pEnumClsObj->Release();
m_pEnumClsObj = NULL;
}
if(m_bInitialize)
{
::CoUninitialize();
m_bInitialize = FALSE;
}
return(hr);
}
上述接口使用到的辅助函数:
- 变量转字符串:
void CWmiIface::VariantToString(__in const LPVARIANT pVar,__out CString &chRetValue) const
{
USES_CONVERSION;
CComBSTR HUGEP* pBstr;
BYTE HUGEP* pBuf;
LONG low,high,i;
HRESULT hr;
switch(pVar->vt)
{
case VT_BSTR:
{
chRetValue=W2T(pVar->bstrVal);
}
break;
case VT_BOOL:
{
if(VARIANT_TRUE==pVar->boolVal)
chRetValue="1";
else
chRetValue="0";
}
break;
case VT_I4:
{
chRetValue.Format(_T("%d"),pVar->lVal);
}
break;
case VT_UI1:
{
chRetValue.Format(_T("%d"),pVar->bVal);
}
break;
case VT_UI4:
{
chRetValue.Format(_T("%d"),pVar->ulVal);
}
break;
case VT_BSTR|VT_ARRAY:
{
hr=SafeArrayAccessData(pVar->parray,(void HUGEP**)&pBstr);
hr=SafeArrayUnaccessData(pVar->parray);
chRetValue=W2T(pBstr->m_str);
}
break;
case VT_I4|VT_ARRAY:
{
SafeArrayGetLBound(pVar->parray,1,&low);
SafeArrayGetUBound(pVar->parray,1,&high);
hr=SafeArrayAccessData(pVar->parray,(void HUGEP**)&pBuf);
hr=SafeArrayUnaccessData(pVar->parray);
CString strTmp;
high=min(high,MAX_PATH*2-1);
for(i=low;i<=high;++i)
{
strTmp.Format(_T("%02X"),pBuf[i]);
chRetValue+=strTmp;
}
}
break;
default:
break;
}
}
通过Wmi查询CPU信息
以下仅作为示例,查询信息的子段可以去这里查看👉Win32_Processor class - Win32 apps | Microsoft Docs
// 5. 获取CPU信息|CPU频率
vecstrRet.clear();
vectQueryClassKey.push_back(_T("Description"));
vectQueryClassKey.push_back(_T("MaxClockSpeed"));
bRet = cwmi.GetGroupItemInfo(_T("Win32_Processor"), vectQueryClassKey, vecstrRet);
if(bRet)
{
CString csMaxClockSpeed;
csMaxClockSpeed.Format(_T("%s MHz"), vecstrRet[1].c_str());
_tcsncpy_s(stuDetect.strCPU, ArraySize(stuDetect.strCPU), vecstrRet[0].c_str(), ArraySize(stuDetect.strCPU) - 1);
_tcsncpy_s(stuDetect.strCPUFreq,ArraySize(stuDetect.strCPUFreq),csMaxClockSpeed.GetString(),ArraySize(stuDetect.strCPUFreq) - 1);
}
使用Win32提供的API查询
直接查询Win32文档可以找到相关接口:
以获取CPU数量为例:
int getCPUNum()
{
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwNumberOfProcessors;
}
其中SYSTEM_INFO
结构体如下所示,包含了CPU的各项信息:
typedef struct _SYSTEM_INFO {
union {
DWORD dwOemId;
struct {
WORD wProcessorArchitecture;
WORD wReserved;
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;
DWORD dwPageSize;
LPVOID lpMinimumApplicationAddress;
LPVOID lpMaximumApplicationAddress;
DWORD_PTR dwActiveProcessorMask;
DWORD dwNumberOfProcessors;
DWORD dwProcessorType;
DWORD dwAllocationGranularity;
WORD wProcessorLevel;
WORD wProcessorRevision;
} SYSTEM_INFO, *LPSYSTEM_INFO;
使用注册表查询(CPU)
查看注册表
HKLM\HARDWARE\DESCRIPTION\
路径,可以看到微软的相关解释是:The System subkey stores data collected by the Windows 2000 hardware recognizer. It includes information about the BIOS, processors, and bus architecture. The System subkey is recreated each time the system starts.
在该注册表路径下,存在ProcessorNameString
项,即CPU信息。
下述代码实现了通过该注册表获取该CPU信息
的功能:
void getCpuInfo(__out CString &chProcessorName)
{
CString strPath=_T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"); //注册表子键路径
CRegKey regkey; //定义注册表类对象
LONG lResult; //LONG型变量-反应结果
WCHAR chCPUName[MAX_KEY_LENGTH] = {0};
DWORD dwSize = MAX_KEY_LENGTH;
lResult=regkey.Open(HKEY_LOCAL_MACHINE,LPCTSTR(strPath),KEY_ALL_ACCESS); //打开注册表键
if (lResult!=ERROR_SUCCESS)
{
WriteError(_T("Open Reg Key Failed, Key=%s"), strPath.GetString());
return;
}
//获取ProcessorNameString字段值
if (ERROR_SUCCESS == regkey.QueryStringValue(_T("ProcessorNameString"),chCPUName,&dwSize))
{
chProcessorName = chCPUName;
}
}