C++ で CPU情報を取得

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

(2020 年 9 月 5 日)インストーラー,ヘルプファイル,メニュー追加
(2020 年 8 月 22 日)XML解釈を Boost ライブラリに変更。

目次

サンプル・プログラム

圧縮ファイルの内容
cpuid.msiインストーラ
bin/cpuid.exe実行プログラム本体
bin/processorList.xmlCPU情報リスト
bin/etc/help.chmヘルプ・ファイル
sour/cpuid.cppソース・プログラム
sour/resource.hリソース・ヘッダ
sour/resource.rcリソース・ファイル
sour/application.icoアプリケーション・アイコン

リソースの準備

Eclipse を起動し、新規プロジェクト cpuid を用意する。
ResEdit を起動し、resource.rc を用意する。

Eclipse に戻り、ソース・プログラム "cpuid.cpp" を追加する。
リンカー・フラグを -mwindows -static -lstdc++ -lgcc -lwinpthread" に設定する。

使用ライブラリ

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

解説:ヘッダファイル等

0010: // 初期化処理 ==============================================================
0011: #include <iostream>
0012: #include <stdio.h>
0013: #include <stdlib.h>
0014: #include <tchar.h>
0015: #include <sstream>
0016: #include <string>
0017: #include <fstream>
0018: #include <windows.h>
0019: #include <commctrl.h>
0020: #include <boost/format.hpp>
0021: #include <boost/property_tree/xml_parser.hpp>
0022: #include "resource.h"
0023: 
0024: using namespace std;
0025: using namespace boost;
0026: using namespace boost::property_tree;
0027: 
0028: #define APPNAME     "CPU情報"            //アプリケーション名
0029: #define APPVERSION "1.2"                //バージョン
0030: #define APPYEAR     "2020"                //作成年
0031: #define REFERENCE "https://www.pahoo.org/e-soul/webtech/cpp01/cpp01-06-01.shtm"  // 参考サイト
0032: 
0033: //char*バッファサイズ
0034: #define SIZE_BUFF     512
0035: 
0036: //現在のインターフェイス
0037: static HINSTANCE hInst;
0038: 
0039: //親ウィンドウ
0040: static HWND hParent;
0041: 
0042: //エラー・メッセージ格納用
0043: string ErrorMessage;
0044: 
0045: //ヘルプ・ファイル
0046: #define HELPFILE ".\\etc\\help.chm"
0047: 
0048: //デフォルト保存ファイル名
0049: #define SAVEFILE "cpuid.txt"
0050: 
0051: //ProcessorListファイル名
0052: #define FNAME "processorList.xml"
0053: 
0054: #define SIZE_PROCESSORINFO 500        //格納上限

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

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

0051: //ProcessorListファイル名
0052: #define FNAME "processorList.xml"
0053: 
0054: #define SIZE_PROCESSORINFO 500        //格納上限
0055: 
0056: //ProcessorInfoクラス
0057: class ProcessorInfo {
0058: public:
0059:     unsigned int level = 0;
0060:     unsigned int type = 0;
0061:     unsigned int number = 0;
0062:     unsigned int model = 0;
0063:     unsigned int family = 0;
0064:     unsigned int stepping = 0;
0065:     string vendor = "";
0066:     string architecture = "";
0067: };
0068: 
0069: //検索結果格納用
0070: unique_ptr<ProcessorInfoProcessorList[SIZE_PROCESSORINFO] = {};

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

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

0233: /**
0234:  * CPU情報リストを取得する
0235:  * @param  char *fname CPU情報リストファイル名
0236:  * @return int 取得した情報数/(-1):取得失敗
0237: */
0238: int getProcessorList(const char *fnamechar *date) {
0239:     int cnt = -1;
0240: 
0241:     try {
0242:         //XMLファイル読み込み
0243:         boost::property_tree::ptree pt;
0244:         boost::property_tree::xml_parser::read_xml(fnamept);
0245: 
0246:         //XML解釈
0247:         boost::optional<std::stringstr = pt.get_optional<std::string>("processorList.date");
0248:         strncpy(datestr->c_str(), SIZE_BUFF);
0249: 
0250:         for (auto it : pt.get_child("processorList")) {
0251:             cnt++;
0252:             ProcessorList[cnt] = make_unique<ProcessorInfo>();
0253:             //ベンダ
0254:             if (optional<stringvendor = it.second.get_optional<string>("vendor")) {
0255:                 ProcessorList[cnt]->vendor = vendor.value();
0256:             }
0257:             //ファミリー
0258:             if (optional<stringfamily = it.second.get_optional<string>("family")) {
0259:                 ProcessorList[cnt]->family = strtol(family->c_str(), NULL, 16);
0260:             }
0261:             //モデル
0262:             if (optional<stringmodel = it.second.get_optional<string>("model")) {
0263:                 ProcessorList[cnt]->model = strtol(model->c_str(), NULL, 16);
0264:             }
0265:             //アーキテクチャ
0266:             if (optional<stringarchitecture = it.second.get_optional<string>("architecture")) {
0267:                 ProcessorList[cnt]->architecture = architecture.value();
0268:             }
0269:         }
0270:     //エラー処理
0271:     } catch (boost::property_tree::xml_parser_errore) {
0272:         ErrorMessage = "エラー:" + (string)e.what();
0273:     }
0274: 
0275:     return cnt;
0276: }

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

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

解説:CPU情報を取得

0278: /**
0279:  * SystemInfoの結果とCPU情報リストをマッチングしCPU情報を取得
0280:  * @param   ProcessorInfo cpuinfo 結果を格納
0281:  * @return  bool TRUE:取得成功/FALSE:取得失敗
0282: */
0283: bool getProcessorInfo(ProcessorInfo &cpuinfo) {
0284:     //CPU情報取得
0285:     SYSTEM_INFO systemInfo;
0286:     GetSystemInfo(&systemInfo);
0287:     cpuinfo.level  = (unsigned int)systemInfo.wProcessorLevel;
0288:     cpuinfo.type   = (unsigned int)systemInfo.dwProcessorType;
0289:     cpuinfo.number = (unsigned int)systemInfo.dwNumberOfProcessors;
0290:     cpuinfo.model  = (unsigned int)(systemInfo.wProcessorRevision >> 8);
0291:     cpuinfo.stepping = (unsigned int)(systemInfo.wProcessorRevision & 0x00FF);
0292:     cpuinfo.vendor = "unknown";
0293:     cpuinfo.architecture = "unknown";
0294: 
0295:     //CPU情報リストとマッチング
0296:     bool res = false;
0297:     for (int i = 0; i < SIZE_PROCESSORINFOi++) {
0298:         if (ProcessorList[i] == nullptr)  break;
0299:         if ((ProcessorList[i]->family == cpuinfo.level) && (ProcessorList[i]->model == cpuinfo.model)) {
0300:             cpuinfo.vendor = ProcessorList[i]->vendor;
0301:             cpuinfo.architecture = ProcessorList[i]->architecture;
0302:             res = true;
0303:             break;
0304:         }
0305:     }
0306:     return res;
0307: }

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

参考サイト

(この項おわり)
header