C++ で CPU情報を取得

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

(2024年11月3日)CPUリスト更新,使用ライブラリ更新
(2024年7月14日)CPUリスト更新,使用ライブラリ更新
(2024年2月17日)CPUリスト更新,使用ライブラリ等を更新

目次

サンプル・プログラム

圧縮ファイルの内容
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.7 2024/07/14 CPUリスト更新,使用ライブラリ更新
1.3.6 2024/07/14 CPUリスト更新,使用ライブラリ更新
1.3.5 2024/02/17 CPUリストを更新,使用ライブラリ等を更新
1.3.4 2023/10/08 使用ライブラリをバージョンアップ,アプリケーション・ウィンドウの位置を保存
1.3.3 2023/05/28 使用ライブラリをバージョンアップ

リソースの準備

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

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

使用ライブラリ

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

解説:初期値

cpuid.cpp

  29: #define MAKER       "pahoo.org"         //作成者
  30: #define APPNAME     "cpuid"             //アプリケーション名
  31: #define APPNAMEJP   "CPU情報"           //アプリケーション名(日本語)
  32: #define APPVERSION  "1.3.7"             //バージョン
  33: #define APPYEAR     "2020-2024"         //作成年
  34: #define REFERENCE   "https://www.pahoo.org/e-soul/webtech/cpp01/cpp01-06-01.shtm"   // 参考サイト
  35: 
  36: //char*バッファサイズ
  37: #define SIZE_BUFF       512
  38: 
  39: //現在のインターフェイス
  40: static HINSTANCE hInst;
  41: 
  42: //親ウィンドウ
  43: static HWND hParent;
  44: 
  45: //アプリケーション・ウィンドウ位置
  46: unsigned hParent_X, hParent_Y;
  47: 
  48: //エラー・メッセージ格納用
  49: string ErrorMessage;
  50: 
  51: //ヘルプ・ファイル
  52: #define HELPFILE    ".\\etc\\help.chm"
  53: 
  54: //デフォルト保存ファイル名
  55: #define SAVEFILE    "cpuid.txt"
  56: 
  57: //ProcessorListファイル名
  58: #define FNAME   "processorList.xml"
  59: 
  60: #define SIZE_PROCESSORINFO  500     //格納上限

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

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

cpuid.cpp

  57: //ProcessorListファイル名
  58: #define FNAME   "processorList.xml"
  59: 
  60: #define SIZE_PROCESSORINFO  500     //格納上限
  61: 
  62: //ProcessorInfoクラス
  63: class ProcessorInfo {
  64: public:
  65:     unsigned int level = 0;
  66:     unsigned int type = 0;
  67:     unsigned int number = 0;
  68:     unsigned int model = 0;
  69:     unsigned int family = 0;
  70:     unsigned int stepping = 0;
  71:     string vendor = "";
  72:     string architecture = "";
  73: };
  74: 
  75: //検索結果格納用
  76: unique_ptr<ProcessorInfo> ProcessorList[SIZE_PROCESSORINFO] = {};

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

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

cpuid.cpp

 364: /**
 365:  * CPU情報リストを取得する
 366:  * @param  char *fname CPU情報リストファイル名
 367:  * @return int 取得した情報数/(-1):取得失敗
 368: */
 369: int getProcessorList(const char *fname, char *date) {
 370:     int cnt = -1;
 371: 
 372:     try {
 373:         //XMLファイル読み込み
 374:         boost::property_tree::ptree pt;
 375:         boost::property_tree::xml_parser::read_xml(fname, pt);
 376: 
 377:         //XML解釈
 378:         boost::optional<std::string> str = pt.get_optional<std::string>("processorList.date");
 379:         strncpy(date, str->c_str(), SIZE_BUFF);
 380: 
 381:         for (auto it : pt.get_child("processorList")) {
 382:             cnt++;
 383:             ProcessorList[cnt] = make_unique<ProcessorInfo>();
 384:             //ベンダ
 385:             if (optional<string> vendor = it.second.get_optional<string>("vendor")) {
 386:                 ProcessorList[cnt]->vendor = vendor.value();
 387:             }
 388:             //ファミリー
 389:             if (optional<string> family = it.second.get_optional<string>("family")) {
 390:                 ProcessorList[cnt]->family = strtol(family->c_str(), NULL, 16);
 391:             }
 392:             //モデル
 393:             if (optional<string> model = it.second.get_optional<string>("model")) {
 394:                 ProcessorList[cnt]->model = strtol(model->c_str(), NULL, 16);
 395:             }
 396:             //アーキテクチャ
 397:             if (optional<string> architecture = it.second.get_optional<string>("architecture")) {
 398:                 ProcessorList[cnt]->architecture = architecture.value();
 399:             }
 400:         }
 401:     //エラー処理
 402:     } catch (boost::property_tree::xml_parser_error& e) {
 403:         ErrorMessage = "エラー:" + (string)e.what();
 404:     }
 405: 
 406:     return cnt;
 407: }

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

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

解説:CPU情報を取得

cpuid.cpp

 409: /**
 410:  * SystemInfoの結果とCPU情報リストをマッチングしCPU情報を取得
 411:  * @param   ProcessorInfo cpuinfo 結果を格納
 412:  * @return  bool TRUE:取得成功/FALSE:取得失敗
 413: */
 414: bool getProcessorInfo(ProcessorInfo &cpuinfo) {
 415:     //CPU情報取得
 416:     SYSTEM_INFO systemInfo;
 417:     GetSystemInfo(&systemInfo);
 418:     cpuinfo.level  = (unsigned int)systemInfo.wProcessorLevel;
 419:     cpuinfo.type   = (unsigned int)systemInfo.dwProcessorType;
 420:     cpuinfo.number = (unsigned int)systemInfo.dwNumberOfProcessors;
 421:     cpuinfo.model  = (unsigned int)(systemInfo.wProcessorRevision >> 8);
 422:     cpuinfo.stepping = (unsigned int)(systemInfo.wProcessorRevision & 0x00FF);
 423:     cpuinfo.vendor = "unknown";
 424:     cpuinfo.architecture = "unknown";
 425: 
 426:     //CPU情報リストとマッチング
 427:     bool res = false;
 428:     for (int i = 0i < SIZE_PROCESSORINFOi++) {
 429:         if (ProcessorList[i] == nullptr)    break;
 430:         if ((ProcessorList[i]->family == cpuinfo.level&& (ProcessorList[i]->model == cpuinfo.model)) {
 431:             cpuinfo.vendor = ProcessorList[i]->vendor;
 432:             cpuinfo.architecture = ProcessorList[i]->architecture;
 433:             res = true;
 434:             break;
 435:         }
 436:     }
 437:     return res;
 438: }

GetSystemInfo を使って取得したCPU情報と、前述の getProcessorList を使って取得したCPU情報リストをマッチングし、CPU情報をテキストとして取り出すのがユーザー関数 getProcessorInfo である。

参考サイト

(この項おわり)
header