C++ で CPU情報を取得

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

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

目次

サンプル・プログラム

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

リソースの準備

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

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

使用ライブラリ

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

解説:ヘッダファイル等

  10: // 初期化処理 ==============================================================
  11: #include <iostream>
  12: #include <stdio.h>
  13: #include <stdlib.h>
  14: #include <tchar.h>
  15: #include <sstream>
  16: #include <string>
  17: #include <fstream>
  18: #include <windows.h>
  19: #include <shlobj.h>
  20: #include <commctrl.h>
  21: #include <boost/format.hpp>
  22: #include <boost/property_tree/xml_parser.hpp>
  23: #include "resource.h"
  24: 
  25: using namespace std;
  26: using namespace boost;
  27: using namespace boost::property_tree;
  28: 
  29: #define MAKER       "pahoo.org"         //作成者
  30: #define APPNAME     "cpuid"             //アプリケーション名
  31: #define APPNAMEJP   "CPU情報"           //アプリケーション名(日本語)
  32: #define APPVERSION  "1.3.5"             //バージョン
  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 は、後述するスマートポインタを扱うために必要。定数は自由に変更して構わない。

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

  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情報リストを取得

 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情報を取得

 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