C++ で CPU情報を取得

(1/1)
C++でCPU情報を取得
PHPでサーバCPUを判定する」で作ったCPU取得プログラムをC++に移植する。ご利用のCPUが脆弱性が公表されているものかどうか確認するのに役立つだろう。
CPU情報は GetSystemInfo 関数によって取得するが、ベンダ名やアーキテクチャは外部ファイル "processorList.xml" にあるテキストから取り出す。そこで、C++でXML解釈を行うために、Boost C++ ライブラリ を活用する。

(2024年7月14日)CPUリスト更新,使用ライブラリ更新
(2024年2月17日)CPUリスト更新,使用ライブラリ等を更新
(2023年10月8日)使用ライブラリ等を更新,アプリケーション・ウィンドウの位置を保存

目次

サンプル・プログラム

圧縮ファイルの内容
cpuid.msiインストーラ
bin/cpuid.exe実行プログラム本体
bin/processorList.xmlCPU情報リスト
bin/etc/help.chmヘルプ・ファイル
sour/cpuid.cppソース・プログラム
sour/resource.hリソース・ヘッダ
sour/resource.rcリソース・ファイル
sour/application.icoアプリケーション・アイコン
sour/makefileビルド
cpuid.cpp 更新履歴
バージョン 更新日 内容
1.3.5 2024/07/14 CPUリスト更新,使用ライブラリ更新
1.3.5 2024/02/17 CPUリストを更新,使用ライブラリ等を更新
1.3.4 2023/10/08 使用ライブラリをバージョンアップ,アプリケーション・ウィンドウの位置を保存
1.3.3 2023/05/28 使用ライブラリをバージョンアップ
1.3.2 2023/02/26 使用ライブラリをバージョンアップ

リソースの準備

Eclipse を起動し、新規プロジェクト cpuid を用意する。
ResEdit を起動し、resource.rc を用意する。
Eclipse に戻り、ソース・プログラム "cpuid.cpp" を追加する。
リンカー・フラグを -mwindows -static -lstdc++ -lgcc -lwinpthread" に設定する。

MSYS2 コマンドラインからビルドするのであれば、"makefile" を利用してほしい。

使用ライブラリ

今回は、オープンソースのライブラリ Boost C++ライブラリを使用する。導入方法等については、「C++ 開発環境の準備」をご覧いただきたい。

解説:初期値


/** cpuid.cpp
 * CPUの情報を表示する
 *
 * @copyright	(c)studio pahoo
 * @author		パパぱふぅ
 * @動作環境	MinGW C++ + Boost C++ Libraries
 * @参考URL		https://www.pahoo.org/e-soul/webtech/cpp01/cpp01-06-01.shtm
*/

// 初期化処理 ==============================================================
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "resource.h"

using namespace std;
using namespace boost;
using namespace boost::property_tree;

#define MAKER		"pahoo.org"			//作成者
#define APPNAME		"cpuid"				//アプリケーション名
#define APPNAMEJP	"CPU情報"			//アプリケーション名(日本語)
#define APPVERSION	"1.3.6"				//バージョン
#define APPYEAR		"2020-2024"			//作成年
#define REFERENCE	"/e-soul/webtech/cpp01/cpp01-06-01.shtm"	// 参考サイト

//char*バッファサイズ
#define SIZE_BUFF		512

//現在のインターフェイス
static HINSTANCE hInst;

//親ウィンドウ
static HWND hParent;

//アプリケーション・ウィンドウ位置
unsigned hParent_X, hParent_Y;

//エラー・メッセージ格納用
string ErrorMessage;

//ヘルプ・ファイル
#define HELPFILE	".\\etc\\help.chm"

//デフォルト保存ファイル名
#define SAVEFILE	"cpuid.txt"

//ProcessorListファイル名
#define FNAME	"processorList.xml"

#define SIZE_PROCESSORINFO	500		//格納上限
cstdlibbluememory は、後述するスマートポインタを扱うために必要。定数は自由に変更して構わない。

解説:クラスとスマートポインタ

//ProcessorListファイル名
#define FNAME	"processorList.xml"

#define SIZE_PROCESSORINFO	500		//格納上限

//ProcessorInfoクラス
class ProcessorInfo {
public:
	unsigned int level = 0;
	unsigned int type = 0;
	unsigned int number = 0;
	unsigned int model = 0;
	unsigned int family = 0;
	unsigned int stepping = 0;
	string vendor = "";
	string architecture = "";
};

//検索結果格納用
unique_ptr ProcessorList[SIZE_PROCESSORINFO] = {};
CPU情報ファイル(XMLファイル)から読み込む情報を格納するために、クラス ProcessorInfo を定義している。
ProcessorInfo クラスはポインタ配列として管理するが、オブジェクト生成時にポインタへ格納できるようにスマートポインタを利用する。
クラスやスマートポインタがあるおかげで、C++ではオブジェクト指向プログラミングを可能にしている。

解説:CPU情報リストを取得

/**
 * CPU情報リストを取得する
 * @param  char *fname CPU情報リストファイル名
 * @return int 取得した情報数/(-1):取得失敗
*/
int getProcessorList(const char *fname, char *date) {
	int cnt = -1;

	try {
		//XMLファイル読み込み
		boost::property_tree::ptree pt;
		boost::property_tree::xml_parser::read_xml(fname, pt);

		//XML解釈
		boost::optional str = pt.get_optional("processorList.date");
		strncpy(date, str->c_str(), SIZE_BUFF);

		for (auto it : pt.get_child("processorList")) {
			cnt++;
			ProcessorList[cnt] = make_unique();
			//ベンダ
			if (optional vendor = it.second.get_optional("vendor")) {
				ProcessorList[cnt]->vendor = vendor.value();
			}
			//ファミリー
			if (optional family = it.second.get_optional("family")) {
				ProcessorList[cnt]->family = strtol(family->c_str(), NULL, 16);
			}
			//モデル
			if (optional model = it.second.get_optional("model")) {
				ProcessorList[cnt]->model = strtol(model->c_str(), NULL, 16);
			}
			//アーキテクチャ
			if (optional architecture = it.second.get_optional("architecture")) {
				ProcessorList[cnt]->architecture = architecture.value();
			}
		}
	//エラー処理
	} catch (boost::property_tree::xml_parser_error& e) {
		ErrorMessage = "エラー:" + (string)e.what();
	}

	return cnt;
}
CPU情報ファイル(XMLファイル)から配列 ProcessorList へ情報を読み込むのがユーザー関数 getProcessorList である。boost/property_tree/xml_parser.hppスマートポインタ を利用している。
optional<string> で受け取ることで、指定したノードに値がない場合でも処理を進めることができる。値が入った場合は、value() メソッドを使って取り出す。

boost/property_tree/xml_parser.hpp でエラーが発生すると、例外処理として扱う。

解説:CPU情報を取得

/**
 * SystemInfoの結果とCPU情報リストをマッチングしCPU情報を取得
 * @param   ProcessorInfo cpuinfo 結果を格納
 * @return  bool TRUE:取得成功/FALSE:取得失敗
*/
bool getProcessorInfo(ProcessorInfo &cpuinfo) {
	//CPU情報取得
	SYSTEM_INFO systemInfo;
	GetSystemInfo(&systemInfo);
	cpuinfo.level  = (unsigned int)systemInfo.wProcessorLevel;
	cpuinfo.type   = (unsigned int)systemInfo.dwProcessorType;
	cpuinfo.number = (unsigned int)systemInfo.dwNumberOfProcessors;
	cpuinfo.model  = (unsigned int)(systemInfo.wProcessorRevision >> 8);
	cpuinfo.stepping = (unsigned int)(systemInfo.wProcessorRevision & 0x00FF);
	cpuinfo.vendor = "unknown";
	cpuinfo.architecture = "unknown";

	//CPU情報リストとマッチング
	bool res = false;
	for (int i = 0; i < SIZE_PROCESSORINFO; i++) {
		if (ProcessorList[i] == nullptr)	break;
		if ((ProcessorList[i]->family == cpuinfo.level) && (ProcessorList[i]->model == cpuinfo.model)) {
			cpuinfo.vendor = ProcessorList[i]->vendor;
			cpuinfo.architecture = ProcessorList[i]->architecture;
			res = true;
			break;
		}
	}
	return res;
}
GetSystemInfo を使って取得したCPU情報と、前述の getProcessorList を使って取得したCPU情報リストをマッチングし、CPU情報をテキストとして取り出すのがユーザー関数 getProcessorInfo である。

参考サイト

(この項おわり)
header