├── .gitignore ├── images └── Snipaste_2020-05-17_23-04-37.jpg ├── src ├── config.cmake.in ├── main.cpp ├── CMakeLists.txt ├── wmic.h └── wmic.cpp ├── CMakeLists.txt ├── LICENSE ├── ReadMe.md └── .clang-format /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | .idea 3 | x64 4 | WMIC.vcxproj.user 5 | out 6 | cmake-build-* 7 | -------------------------------------------------------------------------------- /images/Snipaste_2020-05-17_23-04-37.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheungxiongwei/WMIC/HEAD/images/Snipaste_2020-05-17_23-04-37.jpg -------------------------------------------------------------------------------- /src/config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | # 包含导出的目标 4 | include("${CMAKE_CURRENT_LIST_DIR}/wmic-targets.cmake") 5 | 6 | # 检查所需的组件是否可用 7 | check_required_components(wmic) 8 | 9 | # 设置一些额外信息 10 | set(WMIC_LIBRARIES wmic::wmic_lib) 11 | set(WMIC_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@") 12 | set(WMIC_VERSION "@PROJECT_VERSION@") -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.30) 2 | project(WMIC 3 | VERSION 1.0.0.0 4 | DESCRIPTION "WMIC retrieves hardware info, generates fingerprints, and manages storage." 5 | HOMEPAGE_URL "https://github.com/cheungxiongwei/WMIC" 6 | LANGUAGES CXX) 7 | 8 | set(CMAKE_CXX_STANDARD 23) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | add_subdirectory(src) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 cheungxiongwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | Homepage: https://github.com/cheungxiongwei -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "wmic.h" 3 | 4 | int main() { 5 | system("COLOR 0A"); 6 | 7 | try { 8 | WMIC wmic; 9 | wmic.OperatingSystem(); // 系统 10 | wmic.VideoController(); // 显卡 11 | wmic.DiskDrive(); // 硬盘 12 | wmic.BaseBoard(); // 主板 13 | wmic.BIOS(); // 主板 BIOS 芯片 14 | wmic.PhysicalMemory(); // 内存条 15 | wmic.Processor(); // CPU处理器 16 | wmic.NetworkAdapter(); // 网卡 17 | 18 | // 以系统序列号为例,生成用户ID 19 | // 当然也可以任意特征组合形式进行用户ID生成 20 | auto meta = wmic.OperatingSystem().serialNumber; 21 | auto uid = ::uid(std::vector(meta.begin(), meta.end())); 22 | std::println("uid:{}", uid); 23 | 24 | // UEFI SDRAM 读写 25 | // 注意:此功能需要以管理员权限运行,否则会失败。 26 | uid_meta_t data = {}; 27 | 28 | // 读取硬件指纹 29 | std::println("{:s}", wmicUefiRead(uid, &data, sizeof(uid_meta_t))); 30 | std::println("UEFI SDRAM UID:{}", data.uid); 31 | 32 | // 存储硬件指纹信息 33 | // 填充数据 34 | data.uid = uid; 35 | std::println("{:s}", wmicUefiWrite(uid, &data, sizeof(uid_meta_t))); 36 | 37 | } catch(const WMICException &e) { 38 | std::println("{}", e.what()); 39 | } 40 | system("PAUSE"); 41 | return 0; 42 | } -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(WMIC_HEADERS wmic.h) 2 | set(WMIC_SOURCES wmic.cpp) 3 | 4 | # 添加静态库 5 | add_library(wmic_lib STATIC ${WMIC_HEADERS} ${WMIC_SOURCES}) 6 | target_include_directories(wmic_lib PUBLIC 7 | $ 8 | $ 9 | ) 10 | 11 | # 添加可执行文件 12 | if ("${CMAKE_CURRENT_LIST_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") 13 | add_executable(WMIC main.cpp) 14 | target_link_libraries(WMIC PRIVATE wmic_lib) 15 | endif () 16 | 17 | # 安装配置 18 | install(TARGETS wmic_lib 19 | EXPORT wmic_targets 20 | LIBRARY DESTINATION lib 21 | ARCHIVE DESTINATION lib 22 | RUNTIME DESTINATION bin 23 | INCLUDES DESTINATION include 24 | ) 25 | 26 | install(FILES ${WMIC_HEADERS} DESTINATION include/wmic) 27 | 28 | # 导出目标 29 | install(EXPORT wmic_targets 30 | FILE wmic-targets.cmake 31 | NAMESPACE wmic:: 32 | DESTINATION lib/cmake/wmic 33 | ) 34 | 35 | # 创建并安装配置文件 36 | include(CMakePackageConfigHelpers) 37 | configure_package_config_file( 38 | ${CMAKE_CURRENT_SOURCE_DIR}/config.cmake.in 39 | ${CMAKE_CURRENT_BINARY_DIR}/wmic-config.cmake 40 | INSTALL_DESTINATION lib/cmake/wmic 41 | ) 42 | 43 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/wmic-config.cmake 44 | DESTINATION lib/cmake/wmic 45 | ) -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # WMIC 2 | 3 | wmic 是一款获取PC电脑相关硬件信息的程序,使用 wmi com c++ 编写。 4 | 5 | 目前可以获取以下硬件信息: 6 | 7 | * 显卡 8 | * 硬盘 9 | * 主板 10 | * 主板 bios 芯片 11 | * 内存条 12 | * CPU处理器 13 | * 网卡 14 | 15 | 以及以下软件信息: 16 | 17 | * 电脑系统 18 | 19 | ### 使用示例 20 | 21 | ```c++ 22 | #include 23 | #include "WMIC.h" 24 | 25 | int main() { 26 | system("COLOR 0A"); 27 | try { 28 | WMIC wmic; 29 | wmic.OperatingSystem(); // 系统 30 | wmic.VideoController(); // 显卡 31 | wmic.DiskDrive(); // 硬盘 32 | wmic.BaseBoard(); // 主板 33 | wmic.BIOS(); // 主板 BIOS 芯片 34 | wmic.PhysicalMemory(); // 内存条 35 | wmic.Processor(); // CPU处理器 36 | wmic.NetworkAdapter(); // 网卡 37 | 38 | // 以系统序列号为例,生成用户ID 39 | // 当然也可以任意特征组合形式进行用户ID生成 40 | auto meta = wmic.OperatingSystem().serialNumber; 41 | std::println("uid:{}", uid(std::vector(meta.begin(), meta.end()))); 42 | 43 | } catch(const WMICException &e) { 44 | std::println("{}",e.what()); 45 | } 46 | return 0; 47 | } 48 | ``` 49 | 50 | ![](images/Snipaste_2020-05-17_23-04-37.jpg) 51 | 52 | ### 应用场景 53 | 54 | 硬件指纹(Hardware fingerprint) - 根据一系列的硬件特征信息生产一个唯一的指纹信息应用于 软件许可限制 55 | 56 | **获取用户电脑唯一ID** 57 | 58 | ```python 59 | # 例如使用网卡地址生成唯一ID 60 | mac_address = {0x00, 0xf1, 0xf3, 0x86, 0xc5, 0xaa} 61 | 62 | id = 0 63 | for v in mac_address: 64 | id = (id << 8) | v 65 | 66 | id = id & 0x1fffffff 67 | 68 | print("uid:", id) 69 | # uid: 331712171 70 | ``` 71 | 72 | **持久化** 73 | 74 | 通过 UEFI Non-Volatile Random-Access Memory(NVRAM) 进行存储,断电不丢失信息。 75 | 76 | 读取 uid 和 写入 uid,并写入用户自定义的 meta 信息(软件注册时间,软件到期时间)结构,实现 Software License。 77 | 78 | ```c++ 79 | // UEFI SDRAM 读写 80 | // 注意:此功能需要以管理员权限运行, 否则会失败. 81 | 82 | uid_meta_t data = {}; 83 | 84 | // 读取硬件指纹 85 | std::println("{:s}", wmicUefiRead(uid, &data, sizeof(uid_meta_t))); 86 | std::println("UEFI SDRAM UID:{}", data.uid); 87 | 88 | // 存储硬件指纹信息 89 | // 填充数据 90 | data.uid = uid; 91 | std::println("{:s}", wmicUefiWrite(uid, &data, sizeof(uid_meta_t))); 92 | ``` 93 | 94 | ### 原理 95 | 96 | https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-start-page 97 | 98 | ### 编译 99 | 100 | 仅支持 windows 版本,使用 C++23 or 更高即可编译。 101 | 102 | ### 其他工具 103 | 104 | window系统可以使用系统自带的工具(ComputerHardwareIds.exe)获取 硬件id 105 | 106 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | --- 3 | Language: Cpp 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | 7 | # struct 对齐 clang-format 13 8 | # AlignArrayOfStructures:Left 9 | 10 | # 对齐 11 | AlignConsecutiveAssignments: Consecutive 12 | AlignConsecutiveBitFields: Consecutive 13 | AlignConsecutiveDeclarations: None 14 | AlignConsecutiveMacros: Consecutive 15 | AlignEscapedNewlines: Left 16 | AlignOperands: DontAlign 17 | AlignTrailingComments: true 18 | AllowAllArgumentsOnNextLine: false 19 | AllowAllParametersOfDeclarationOnNextLine: false 20 | 21 | # 单行 22 | AllowShortBlocksOnASingleLine: Empty 23 | AllowShortCaseLabelsOnASingleLine: true 24 | AllowShortEnumsOnASingleLine: false 25 | AllowShortFunctionsOnASingleLine: Inline 26 | AllowShortIfStatementsOnASingleLine: WithoutElse 27 | AllowShortLambdasOnASingleLine: Inline 28 | AllowShortLoopsOnASingleLine: false 29 | AlwaysBreakAfterReturnType: None 30 | AlwaysBreakBeforeMultilineStrings: false 31 | AlwaysBreakTemplateDeclarations: Yes 32 | AttributeMacros: [ '__capability', '__output', '__ununsed' ] 33 | BinPackArguments: false 34 | BinPackParameters: false 35 | BitFieldColonSpacing: Both 36 | 37 | # 大括号样式设置 38 | BreakBeforeBraces: Custom 39 | BraceWrapping: 40 | AfterCaseLabel: false 41 | AfterClass: true 42 | AfterControlStatement: Never 43 | AfterEnum: false 44 | AfterFunction: false 45 | AfterNamespace: false 46 | AfterStruct: false 47 | AfterUnion: false 48 | AfterExternBlock: true 49 | BeforeCatch: false 50 | BeforeElse: false 51 | BeforeLambdaBody: false 52 | BeforeWhile: false 53 | IndentBraces: false 54 | SplitEmptyFunction: false 55 | SplitEmptyRecord: false 56 | SplitEmptyNamespace: false 57 | BreakBeforeBinaryOperators: None 58 | BreakBeforeConceptDeclarations: false 59 | BreakBeforeTernaryOperators: false 60 | BreakConstructorInitializers: BeforeComma 61 | BreakInheritanceList: AfterColon 62 | BreakStringLiterals: false 63 | ColumnLimit: 640 64 | CommentPragmas: '' 65 | CompactNamespaces: false 66 | ConstructorInitializerIndentWidth: 2 67 | ContinuationIndentWidth: 2 68 | Cpp11BracedListStyle: true 69 | DeriveLineEnding: true 70 | DerivePointerAlignment: true 71 | DisableFormat: false 72 | # clang-format 13 73 | # EmptyLineAfterAccessModifier: Never 74 | EmptyLineBeforeAccessModifier: Always 75 | FixNamespaceComments: true 76 | ForEachMacros: [ ] 77 | # clang-format 13 78 | # IfMacros: [] 79 | IncludeBlocks: Merge 80 | # 可使用 IncludeCategories 指定排序优先级 81 | # clang-format 13 82 | # IndentAccessModifiers: false 83 | IndentCaseBlocks: false 84 | IndentCaseLabels: true 85 | IndentExternBlock: Indent 86 | IndentGotoLabels: false 87 | IndentPPDirectives: BeforeHash 88 | # clang-format 15 89 | # IndentRequiresClause: false 90 | IndentWidth: 4 91 | IndentWrappedFunctionNames: false 92 | # clang-format 15 93 | # InsertBraces: false 94 | InsertTrailingCommas: None 95 | KeepEmptyLinesAtTheStartOfBlocks: false 96 | # clang-format 13 97 | LambdaBodyIndentation: Signature 98 | MaxEmptyLinesToKeep: 1 99 | NamespaceIndentation: Inner 100 | # clang-format 13 101 | # PPIndentWidth: 2 102 | # clang-format 14 103 | # PackConstructorInitializers: NextLine 104 | PointerAlignment: Left 105 | # clang-format 14 106 | # QualifierAlignment: Leave 107 | # clang-format 13 108 | # ReferenceAlignment: Left 109 | ReflowComments: false 110 | # clang-format 14 111 | # RemoveBracesLLVM: false 112 | # clang-format 15 113 | # RequiresClausePosition: OwnLine 114 | # clang-format 14 115 | SeparateDefinitionBlocks: Always 116 | # clang-format 13 117 | # ShortNamespaceLines: 0 118 | SortIncludes: Never 119 | SortUsingDeclarations: true 120 | SpaceAfterCStyleCast: false 121 | SpaceAfterLogicalNot: false 122 | SpaceAfterTemplateKeyword: false 123 | SpaceAroundPointerQualifiers: Default 124 | SpaceBeforeAssignmentOperators: true 125 | SpaceBeforeCaseColon: false 126 | SpaceBeforeCpp11BracedList: true 127 | SpaceBeforeCtorInitializerColon: true 128 | SpaceBeforeInheritanceColon: true 129 | SpaceBeforeParens: Never 130 | SpaceBeforeRangeBasedForLoopColon: false 131 | SpaceBeforeSquareBrackets: false 132 | SpaceInEmptyBlock: false 133 | SpaceInEmptyParentheses: false 134 | SpacesBeforeTrailingComments: 2 135 | SpacesInAngles: false 136 | SpacesInCStyleCastParentheses: false 137 | SpacesInConditionalStatement: false 138 | SpacesInContainerLiterals: false 139 | SpacesInParentheses: false 140 | SpacesInSquareBrackets: false 141 | Standard: c++20 142 | StatementAttributeLikeMacros: [ emit ] 143 | StatementMacros: [ Q_UNUSED ] 144 | TabWidth: 2 145 | TypenameMacros: [ ] 146 | UseCRLF: false 147 | UseTab: Never 148 | WhitespaceSensitiveMacros: [ ] 149 | -------------------------------------------------------------------------------- /src/wmic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::string ConvertWideToMultiByte(std::wstring_view str); 9 | 10 | std::wstring ConvertMultiByteToWide(std::string_view str); 11 | 12 | constexpr auto &W2A = ConvertWideToMultiByte; 13 | constexpr auto &A2W = ConvertMultiByteToWide; 14 | 15 | /*! 16 | WMI所有类别 17 | https://docs.microsoft.com/en-us/previous-versions//aa394084(v=vs.85)?redirectedfrom=MSDN 18 | https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-start-page 19 | 20 | UEFI Non-Volatile Random-Access Memory(NVRAM) 21 | https://learn.microsoft.com/en-us/windows/win32/sysinfo/access-uefi-firmware-variables-from-a-universal-windows-app 22 | 23 | wmi Windows自带测试程序 24 | C:\Windows\System32\wbem\wbemtest.exe 25 | SELECT * FROM [ClassName] 26 | SELECT * FROM Win32_VideoController 27 | */ 28 | 29 | // 显卡 Win32_VideoController 30 | struct WMIC_VideoController { 31 | std::wstring name; 32 | std::wstring deviceID; 33 | }; 34 | 35 | // 硬盘 Win32_DiskDrive 36 | struct WMIC_DiskDrive { 37 | std::wstring name; 38 | std::wstring deviceID; 39 | std::wstring serialNumber; 40 | std::uint64_t size = 0; // GB 41 | }; 42 | 43 | // 主板 Win32_BaseBoard 44 | struct WMIC_BaseBoard { 45 | std::wstring name; 46 | std::wstring manufacturer; // 生产厂商 47 | std::wstring product; // 产品 48 | std::wstring version; // 版本 49 | std::wstring serialNumber; 50 | }; 51 | 52 | // 主板BIOS Win32_BIOS 53 | struct WMIC_BIOS { 54 | std::wstring manufacturer; // 生产厂商 55 | std::wstring releaseDate; // 发布日期 56 | std::wstring serialNumber; 57 | }; 58 | 59 | // 内存 Win32_PhysicalMemory 60 | struct WMIC_PhysicalMemory { 61 | std::wstring name; 62 | std::wstring manufacturer; // 生产厂商 63 | std::wstring serialNumber; // 序列号 64 | std::uint32_t speed; // 频率 MHz(兆赫) 65 | std::uint64_t size; // 容量 GB 66 | }; 67 | 68 | // CPU Win32_Processor 69 | struct WMIC_Processor { 70 | std::wstring name; 71 | std::wstring desc; // Description 72 | std::wstring manufacturer; // 生产厂商 73 | std::uint32_t numberOfCores; // CPU核心数量 74 | std::wstring processorId; // 处理器ID 75 | std::uint32_t threadCount; // 线程数量 76 | std::double_t maxClockSpeed; // 最大时钟频率 GHz 77 | }; 78 | 79 | // 串口 Win32_SerialPort 80 | 81 | // 声卡 Win32_SoundDevice 82 | 83 | // 网络适配器 Win32_NetworkAdapter 84 | struct WMIC_NetworkAdapter { 85 | std::wstring name; 86 | std::wstring desc; // Description 87 | std::wstring manufacturer; // 生产厂商 88 | std::wstring macAddress; 89 | std::wstring adapterType; 90 | }; 91 | 92 | // 系统信息 Win32_OperatingSystem 93 | struct WMIC_OperatingSystem { 94 | std::wstring name; 95 | std::wstring buildNumber; 96 | std::wstring version; 97 | std::wstring installDate; 98 | std::wstring osArchitecture; 99 | std::wstring registeredUser; 100 | std::wstring serialNumber; 101 | }; 102 | 103 | class WMICException : public std::exception 104 | { 105 | public: 106 | explicit WMICException(const std::string &message) 107 | : mMessage(message) {} 108 | 109 | const char *what() const noexcept override { return mMessage.data(); } 110 | 111 | private: 112 | std::string mMessage; 113 | }; 114 | 115 | inline uint32_t uid(const std::vector &data) { 116 | uint32_t id {0}; 117 | for(const auto &v: data) { 118 | id = (id << 8) | v; 119 | } 120 | id &= 0x1fffffff; 121 | return id; 122 | } 123 | 124 | class WMIC 125 | { 126 | public: 127 | explicit WMIC(); 128 | ~WMIC(); 129 | WMIC_OperatingSystem OperatingSystem(); // 系统 130 | std::vector VideoController(); // 显卡 131 | std::vector DiskDrive(); // 硬盘 132 | WMIC_BaseBoard BaseBoard(); // 主板 133 | WMIC_BIOS BIOS(); // 主板BIOS 134 | std::vector PhysicalMemory(); // 内存条 135 | std::vector Processor(); // cpu处理器 136 | std::vector NetworkAdapter(); // 网络适配器 137 | 138 | private: 139 | std::unique_ptr pCtx; 140 | 141 | private: 142 | WMIC(const WMIC &) = delete; 143 | WMIC &operator=(const WMIC &) = delete; 144 | }; 145 | 146 | typedef struct alignas(sizeof(void *)) uid_meta_t { 147 | uint32_t uid; // 用户标识符/许可证唯一ID 148 | uint8_t license_key[32]; // 许可证密钥 149 | uint64_t issue_date; // 许可证发布日期(UNIX时间戳) 150 | uint64_t expiry_date; // 许可证过期日期(UNIX时间戳) 151 | uint32_t version; // 许可证版本号 152 | uint32_t features_mask; // 功能权限位掩码 153 | uint16_t max_devices; // 允许激活的最大设备数量 154 | uint16_t current_devices; // 当前已激活的设备数量 155 | uint8_t name[64]; // 客户名称 156 | uint8_t email[128]; // 客户电子邮件 157 | uint8_t license_type; // 许可证类型(试用版、专业版、企业版等) 158 | uint8_t status; // 许可状态(有效、暂停、已撤销等) 159 | uint8_t activation_count; // 激活次数 160 | uint8_t hash_signature[64]; // 许可证数据的加密签名,用于验证完整性 161 | uint8_t reserved[32]; // 保留字段,用于将来扩展 162 | } uid_meta_t; 163 | 164 | bool wmicUefiRead(uint32_t uid, void *data, int len); 165 | 166 | bool wmicUefiWrite(uint32_t uid, void *data, int len); 167 | -------------------------------------------------------------------------------- /src/wmic.cpp: -------------------------------------------------------------------------------- 1 | #include "WMIC.h" 2 | // windows 3 | #include 4 | #include 5 | #include 6 | 7 | #pragma comment(lib, "wbemuuid.lib") 8 | 9 | // STL 10 | #include 11 | #include 12 | 13 | std::string ConvertWideToMultiByte(std::wstring_view str) { 14 | BOOL isUsedDefaultChar; 15 | if(auto const size = WideCharToMultiByte(CP_ACP, NULL, str.data(), -1, NULL, NULL, NULL, &isUsedDefaultChar); !isUsedDefaultChar && size > 0) { 16 | std::vector result(size); 17 | WideCharToMultiByte(CP_ACP, NULL, str.data(), -1, result.data(), size, NULL, NULL); 18 | return result.data(); 19 | } 20 | return {}; 21 | } 22 | 23 | std::wstring ConvertMultiByteToWide(std::string_view str) { 24 | if(auto const size = MultiByteToWideChar(CP_UTF8, NULL, str.data(), -1, NULL, NULL); size > 0) { 25 | std::vector result(size); 26 | MultiByteToWideChar(CP_UTF8, NULL, str.data(), -1, result.data(), size); 27 | return result.data(); 28 | } 29 | return {}; 30 | } 31 | 32 | struct WMICContext { 33 | HRESULT hResult = NULL; 34 | IWbemLocator *pLoc = NULL; 35 | IWbemServices *pSvc = NULL; 36 | std::stringstream message; 37 | }; 38 | 39 | IEnumWbemClassObject *ExecQuery(std::unique_ptr &ctx, const std::wstring className) { 40 | IEnumWbemClassObject *pEnumerator = NULL; 41 | std::wstring cmd = L"SELECT * FROM "; 42 | cmd += className; 43 | 44 | ctx->hResult = ctx->pSvc->ExecQuery(bstr_t("WQL"), bstr_t(cmd.data()), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); 45 | 46 | if(FAILED(ctx->hResult)) { 47 | ctx->message.clear(); 48 | ctx->message << "Query for xxx failed." 49 | << " Error code = 0x" << std::hex << ctx->hResult << std::endl; 50 | ctx->pSvc->Release(); 51 | ctx->pLoc->Release(); 52 | CoUninitialize(); 53 | throw WMICException(ctx->message.str()); 54 | // Program has failed. 55 | } 56 | return pEnumerator; 57 | } 58 | 59 | WMIC::WMIC() { 60 | pCtx = std::make_unique(); 61 | 62 | // Step 1 63 | // Initialize COM 64 | pCtx->hResult = CoInitializeEx(0, COINIT_MULTITHREADED); 65 | if(FAILED(pCtx->hResult)) { 66 | pCtx->message.clear(); 67 | pCtx->message << "Failed to initialize COM library. Error code = 0x" << std::hex << pCtx->hResult << std::endl; 68 | throw WMICException(pCtx->message.str()); 69 | } 70 | 71 | // Step 2 72 | // Set general COM security levels 73 | pCtx->hResult = CoInitializeSecurity(NULL, 74 | -1, // COM authentication 75 | NULL, // Authentication services 76 | NULL, // Reserved 77 | RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication 78 | RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation 79 | NULL, // Authentication info 80 | EOAC_NONE, // Additional capabilities 81 | NULL // Reserved 82 | ); 83 | if(FAILED(pCtx->hResult)) { 84 | pCtx->message.clear(); 85 | pCtx->message << "Failed to initialize security. Error code = 0x" << std::hex << pCtx->hResult << std::endl; 86 | CoUninitialize(); 87 | throw WMICException(pCtx->message.str()); 88 | // Program has failed. 89 | } 90 | 91 | // Step 3 92 | // Obtain the initial locator to WMI 93 | pCtx->hResult = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pCtx->pLoc); 94 | 95 | if(FAILED(pCtx->hResult)) { 96 | pCtx->message.clear(); 97 | pCtx->message << "Failed to create IWbemLocator object." 98 | << " Err code = 0x" << std::hex << pCtx->hResult << std::endl; 99 | CoUninitialize(); 100 | throw WMICException(pCtx->message.str()); 101 | // Program has failed. 102 | } 103 | 104 | // Step 4 105 | // Connect to WMI through the IWbemLocator::ConnectServer method 106 | 107 | // Connect to the root\cimv2 namespace with 108 | // the current user and obtain pointer pSvc 109 | // to make IWbemServices calls. 110 | pCtx->hResult = pCtx->pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace 111 | NULL, // User name. NULL = current user 112 | NULL, // User password. NULL = current 113 | NULL, // Locale. NULL indicates current 114 | NULL, // Security flags. 115 | NULL, // Authority (for example, Kerberos) 116 | NULL, // Context object 117 | &pCtx->pSvc // pointer to IWbemServices proxy 118 | ); 119 | 120 | if(FAILED(pCtx->hResult)) { 121 | pCtx->message.clear(); 122 | pCtx->message << "Could not connect. Error code = 0x" << std::hex << pCtx->hResult << std::endl; 123 | pCtx->pLoc->Release(); 124 | CoUninitialize(); 125 | throw WMICException(pCtx->message.str()); 126 | // Program has failed. 127 | } 128 | 129 | std::println("Connected to ROOT\\CIMV2 WMI namespace"); 130 | 131 | // Step 5 132 | // Set security levels on the proxy 133 | pCtx->hResult = CoSetProxyBlanket(pCtx->pSvc, // Indicates the proxy to set 134 | RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx 135 | RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx 136 | NULL, // Server principal name 137 | RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx 138 | RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx 139 | NULL, // client identity 140 | EOAC_NONE // proxy capabilities 141 | ); 142 | 143 | if(FAILED(pCtx->hResult)) { 144 | pCtx->message.clear(); 145 | pCtx->message << "Could not set proxy blanket. Error code = 0x" << std::hex << pCtx->hResult << std::endl; 146 | pCtx->pSvc->Release(); 147 | pCtx->pLoc->Release(); 148 | CoUninitialize(); 149 | throw WMICException(pCtx->message.str()); 150 | // Program has failed. 151 | } 152 | 153 | // Step 6: 154 | // Use the IWbemServices pointer to make requests of WMI 155 | } 156 | 157 | WMIC::~WMIC() { 158 | // Cleanup 159 | pCtx->pSvc->Release(); 160 | pCtx->pLoc->Release(); 161 | CoUninitialize(); 162 | // Program successfully completed. 163 | } 164 | 165 | WMIC_OperatingSystem WMIC::OperatingSystem() { 166 | IEnumWbemClassObject *pEnumerator = ExecQuery(pCtx, L"Win32_OperatingSystem"); 167 | 168 | // Step 7: 169 | // Get the data from the query in step 6 170 | 171 | IWbemClassObject *pclsObj = NULL; 172 | ULONG uReturn = 0; 173 | 174 | WMIC_OperatingSystem operatingSystem; 175 | while(pEnumerator) { 176 | HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 177 | 178 | if(0 == uReturn) { 179 | break; 180 | } 181 | 182 | VARIANT vtProp; 183 | VariantInit(&vtProp); 184 | 185 | hr = pclsObj->Get(L"Caption", 0, &vtProp, 0, 0); 186 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 187 | operatingSystem.name = vtProp.bstrVal; 188 | } 189 | VariantClear(&vtProp); 190 | 191 | hr = pclsObj->Get(L"BuildNumber", 0, &vtProp, 0, 0); 192 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 193 | operatingSystem.buildNumber = vtProp.bstrVal; 194 | } 195 | VariantClear(&vtProp); 196 | 197 | hr = pclsObj->Get(L"Version", 0, &vtProp, 0, 0); 198 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 199 | operatingSystem.version = vtProp.bstrVal; 200 | } 201 | VariantClear(&vtProp); 202 | 203 | hr = pclsObj->Get(L"InstallDate", 0, &vtProp, 0, 0); 204 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 205 | operatingSystem.installDate = vtProp.bstrVal; 206 | } 207 | VariantClear(&vtProp); 208 | 209 | hr = pclsObj->Get(L"OSArchitecture", 0, &vtProp, 0, 0); 210 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 211 | operatingSystem.osArchitecture = vtProp.bstrVal; 212 | } 213 | VariantClear(&vtProp); 214 | 215 | hr = pclsObj->Get(L"RegisteredUser", 0, &vtProp, 0, 0); 216 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 217 | operatingSystem.registeredUser = vtProp.bstrVal; 218 | } 219 | VariantClear(&vtProp); 220 | 221 | hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); 222 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 223 | operatingSystem.serialNumber = vtProp.bstrVal; 224 | } 225 | VariantClear(&vtProp); 226 | 227 | #ifdef _DEBUG 228 | std::print("{}\t", W2A(operatingSystem.name)); 229 | std::print("{}\t", W2A(operatingSystem.buildNumber)); 230 | std::print("{}\t", W2A(operatingSystem.version)); 231 | std::print("{}\t", W2A(operatingSystem.installDate)); 232 | std::print("{}\t", W2A(operatingSystem.osArchitecture)); 233 | std::print("{}\t", W2A(operatingSystem.registeredUser)); 234 | std::println("{}\t", W2A(operatingSystem.serialNumber)); 235 | #endif 236 | pclsObj->Release(); 237 | } 238 | if(pEnumerator) pEnumerator->Release(); 239 | return operatingSystem; 240 | } 241 | 242 | std::vector WMIC::VideoController() { 243 | IEnumWbemClassObject *pEnumerator = ExecQuery(pCtx, L"Win32_VideoController"); 244 | 245 | // Step 7: 246 | // Get the data from the query in step 6 247 | 248 | IWbemClassObject *pclsObj = NULL; 249 | ULONG uReturn = 0; 250 | 251 | std::vector set; 252 | WMIC_VideoController videoController; 253 | while(pEnumerator) { 254 | HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 255 | 256 | if(0 == uReturn) { 257 | break; 258 | } 259 | 260 | VARIANT vtProp; 261 | VariantInit(&vtProp); 262 | 263 | // Get the value of the Name property 264 | hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); 265 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 266 | videoController.name = vtProp.bstrVal; 267 | } 268 | VariantClear(&vtProp); 269 | 270 | hr = pclsObj->Get(L"PNPDeviceID", 0, &vtProp, 0, 0); 271 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 272 | videoController.deviceID = vtProp.bstrVal; 273 | } 274 | VariantClear(&vtProp); 275 | 276 | set.emplace_back(videoController); 277 | #ifdef _DEBUG 278 | std::print("{}\t", W2A(videoController.name)); 279 | std::println("{}\t", W2A(videoController.deviceID)); 280 | #endif 281 | pclsObj->Release(); 282 | } 283 | if(pEnumerator) pEnumerator->Release(); 284 | 285 | return set; 286 | } 287 | 288 | std::vector WMIC::DiskDrive() { 289 | IEnumWbemClassObject *pEnumerator = ExecQuery(pCtx, L"Win32_DiskDrive"); 290 | 291 | // Step 7: 292 | // Get the data from the query in step 6 293 | 294 | IWbemClassObject *pclsObj = NULL; 295 | ULONG uReturn = 0; 296 | 297 | std::vector set; 298 | WMIC_DiskDrive diskDrive; 299 | while(pEnumerator) { 300 | HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 301 | 302 | if(0 == uReturn) { 303 | break; 304 | } 305 | 306 | VARIANT vtProp; 307 | VariantInit(&vtProp); 308 | 309 | // Get the value of the Name property 310 | hr = pclsObj->Get(L"Caption", 0, &vtProp, 0, 0); 311 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 312 | diskDrive.name = vtProp.bstrVal; 313 | } 314 | VariantClear(&vtProp); 315 | 316 | hr = pclsObj->Get(L"PNPDeviceID", 0, &vtProp, 0, 0); 317 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 318 | diskDrive.deviceID = vtProp.bstrVal; 319 | } 320 | VariantClear(&vtProp); 321 | 322 | hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); 323 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 324 | diskDrive.serialNumber = vtProp.bstrVal; 325 | } 326 | VariantClear(&vtProp); 327 | 328 | hr = pclsObj->Get(L"Size", 0, &vtProp, 0, 0); 329 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 330 | VarUI8FromStr(vtProp.bstrVal, NULL, LOCALE_NOUSEROVERRIDE, &diskDrive.size); 331 | diskDrive.size = diskDrive.size / (1024 * 1024 * 1024); // 1 byte / (1024*1024*1024) = x GB 332 | } 333 | VariantClear(&vtProp); 334 | 335 | set.emplace_back(diskDrive); 336 | #ifdef _DEBUG 337 | std::print("{}\t", W2A(diskDrive.name)); 338 | std::print("{}\t", W2A(diskDrive.deviceID)); 339 | std::print("{}\t", W2A(diskDrive.serialNumber)); 340 | std::println("{} GB\t", diskDrive.size); 341 | #endif 342 | pclsObj->Release(); 343 | } 344 | if(pEnumerator) pEnumerator->Release(); 345 | 346 | return set; 347 | } 348 | 349 | WMIC_BaseBoard WMIC::BaseBoard() { 350 | IEnumWbemClassObject *pEnumerator = ExecQuery(pCtx, L"Win32_BaseBoard"); 351 | 352 | // Step 7: 353 | // Get the data from the query in step 6 354 | 355 | IWbemClassObject *pclsObj = NULL; 356 | ULONG uReturn = 0; 357 | 358 | WMIC_BaseBoard baseBoard; 359 | while(pEnumerator) { 360 | HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 361 | 362 | if(0 == uReturn) { 363 | break; 364 | } 365 | 366 | VARIANT vtProp; 367 | VariantInit(&vtProp); 368 | 369 | // Get the value of the Name property 370 | hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); 371 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 372 | baseBoard.name = vtProp.bstrVal; 373 | } 374 | VariantClear(&vtProp); 375 | 376 | hr = pclsObj->Get(L"Manufacturer", 0, &vtProp, 0, 0); 377 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 378 | baseBoard.manufacturer = vtProp.bstrVal; 379 | } 380 | VariantClear(&vtProp); 381 | 382 | hr = pclsObj->Get(L"Product", 0, &vtProp, 0, 0); 383 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 384 | baseBoard.product = vtProp.bstrVal; 385 | } 386 | VariantClear(&vtProp); 387 | 388 | hr = pclsObj->Get(L"Version", 0, &vtProp, 0, 0); 389 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 390 | baseBoard.version = vtProp.bstrVal; 391 | } 392 | VariantClear(&vtProp); 393 | 394 | hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); 395 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 396 | baseBoard.serialNumber = vtProp.bstrVal; 397 | } 398 | VariantClear(&vtProp); 399 | 400 | #ifdef _DEBUG 401 | std::print("{}\t", W2A(baseBoard.name)); 402 | std::print("{}\t", W2A(baseBoard.manufacturer)); 403 | std::print("{}\t", W2A(baseBoard.product)); 404 | std::print("{}\t", W2A(baseBoard.version)); 405 | std::println("{}\t", W2A(baseBoard.serialNumber)); 406 | #endif 407 | 408 | pclsObj->Release(); 409 | } 410 | if(pEnumerator) pEnumerator->Release(); 411 | 412 | return baseBoard; 413 | } 414 | 415 | WMIC_BIOS WMIC::BIOS() { 416 | IEnumWbemClassObject *pEnumerator = ExecQuery(pCtx, L"Win32_BIOS"); 417 | 418 | // Step 7: 419 | // Get the data from the query in step 6 420 | 421 | IWbemClassObject *pclsObj = NULL; 422 | ULONG uReturn = 0; 423 | 424 | WMIC_BIOS bios; 425 | while(pEnumerator) { 426 | HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 427 | 428 | if(0 == uReturn) { 429 | break; 430 | } 431 | 432 | VARIANT vtProp; 433 | VariantInit(&vtProp); 434 | 435 | // Get the value of the Name property 436 | hr = pclsObj->Get(L"ReleaseDate", 0, &vtProp, 0, 0); 437 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 438 | bios.releaseDate = vtProp.bstrVal; 439 | } 440 | VariantClear(&vtProp); 441 | 442 | hr = pclsObj->Get(L"Manufacturer", 0, &vtProp, 0, 0); 443 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 444 | bios.manufacturer = vtProp.bstrVal; 445 | } 446 | VariantClear(&vtProp); 447 | 448 | hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); 449 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 450 | bios.serialNumber = vtProp.bstrVal; 451 | } 452 | VariantClear(&vtProp); 453 | 454 | #ifdef _DEBUG 455 | std::print("{}\t", W2A(bios.manufacturer)); 456 | std::print("{}\t", W2A(bios.releaseDate)); 457 | std::println("{}\t", W2A(bios.serialNumber)); 458 | #endif 459 | 460 | pclsObj->Release(); 461 | } 462 | if(pEnumerator) pEnumerator->Release(); 463 | 464 | return bios; 465 | } 466 | 467 | std::vector WMIC::PhysicalMemory() { 468 | IEnumWbemClassObject *pEnumerator = ExecQuery(pCtx, L"Win32_PhysicalMemory"); 469 | 470 | // Step 7: 471 | // Get the data from the query in step 6 472 | 473 | IWbemClassObject *pclsObj = NULL; 474 | ULONG uReturn = 0; 475 | 476 | std::vector set; 477 | WMIC_PhysicalMemory physicalMemory; 478 | while(pEnumerator) { 479 | HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 480 | 481 | if(0 == uReturn) { 482 | break; 483 | } 484 | 485 | VARIANT vtProp; 486 | VariantInit(&vtProp); 487 | 488 | // Get the value of the Name property 489 | hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); 490 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 491 | physicalMemory.name = vtProp.bstrVal; 492 | } 493 | VariantClear(&vtProp); 494 | 495 | hr = pclsObj->Get(L"Manufacturer", 0, &vtProp, 0, 0); 496 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 497 | physicalMemory.manufacturer = vtProp.bstrVal; 498 | } 499 | VariantClear(&vtProp); 500 | 501 | hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); 502 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 503 | physicalMemory.serialNumber = vtProp.bstrVal; 504 | } 505 | VariantClear(&vtProp); 506 | 507 | hr = pclsObj->Get(L"Speed", 0, &vtProp, 0, 0); 508 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_I4)) { 509 | physicalMemory.speed = vtProp.uintVal; 510 | } 511 | VariantClear(&vtProp); 512 | 513 | hr = pclsObj->Get(L"Capacity", 0, &vtProp, 0, 0); 514 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 515 | VarUI8FromStr(vtProp.bstrVal, NULL, LOCALE_NOUSEROVERRIDE, &physicalMemory.size); 516 | physicalMemory.size = physicalMemory.size / (1024 * 1024 * 1024); // 1 byte / (1024*1024*1024) = x GB 517 | } 518 | VariantClear(&vtProp); 519 | 520 | set.emplace_back(physicalMemory); 521 | 522 | #ifdef _DEBUG 523 | std::print("{}\t", W2A(physicalMemory.name)); 524 | std::print("{}\t", W2A(physicalMemory.manufacturer)); 525 | std::print("{}\t", W2A(physicalMemory.serialNumber)); 526 | std::print("{} MHz\t", physicalMemory.speed); 527 | std::println("{} GB\t", physicalMemory.size); 528 | #endif 529 | 530 | pclsObj->Release(); 531 | } 532 | if(pEnumerator) pEnumerator->Release(); 533 | 534 | return set; 535 | } 536 | 537 | std::vector WMIC::Processor() { 538 | IEnumWbemClassObject *pEnumerator = ExecQuery(pCtx, L"Win32_Processor"); 539 | 540 | // Step 7: 541 | // Get the data from the query in step 6 542 | 543 | IWbemClassObject *pclsObj = NULL; 544 | ULONG uReturn = 0; 545 | 546 | std::vector set; 547 | WMIC_Processor processor; 548 | while(pEnumerator) { 549 | HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 550 | 551 | if(0 == uReturn) { 552 | break; 553 | } 554 | 555 | VARIANT vtProp; 556 | VariantInit(&vtProp); 557 | 558 | // Get the value of the Name property 559 | hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); 560 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 561 | processor.name = vtProp.bstrVal; 562 | } 563 | VariantClear(&vtProp); 564 | 565 | hr = pclsObj->Get(L"Description", 0, &vtProp, 0, 0); 566 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 567 | processor.desc = vtProp.bstrVal; 568 | } 569 | VariantClear(&vtProp); 570 | 571 | hr = pclsObj->Get(L"Manufacturer", 0, &vtProp, 0, 0); 572 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 573 | processor.manufacturer = vtProp.bstrVal; 574 | } 575 | VariantClear(&vtProp); 576 | 577 | hr = pclsObj->Get(L"NumberOfCores", 0, &vtProp, 0, 0); 578 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_I4)) { 579 | processor.numberOfCores = vtProp.uintVal; 580 | } 581 | VariantClear(&vtProp); 582 | 583 | hr = pclsObj->Get(L"ThreadCount", 0, &vtProp, 0, 0); 584 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_I4)) { 585 | processor.threadCount = vtProp.uintVal; 586 | } 587 | VariantClear(&vtProp); 588 | 589 | hr = pclsObj->Get(L"ProcessorId", 0, &vtProp, 0, 0); 590 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 591 | processor.processorId = vtProp.bstrVal; 592 | } 593 | VariantClear(&vtProp); 594 | 595 | hr = pclsObj->Get(L"MaxClockSpeed", 0, &vtProp, 0, 0); 596 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_I4)) { 597 | processor.maxClockSpeed = static_cast(vtProp.uintVal) / 1000.0; 598 | } 599 | VariantClear(&vtProp); 600 | 601 | set.emplace_back(processor); 602 | 603 | #ifdef _DEBUG 604 | std::print("{}\t", W2A(processor.name)); 605 | std::print("{}\t", W2A(processor.desc)); 606 | std::print("{}\t", W2A(processor.manufacturer)); 607 | std::print("{}\t", processor.numberOfCores); 608 | std::print("{}\t", processor.threadCount); 609 | std::print("{}\t", W2A(processor.processorId)); 610 | std::println("{} GHz\t", processor.maxClockSpeed); 611 | #endif 612 | 613 | pclsObj->Release(); 614 | } 615 | if(pEnumerator) pEnumerator->Release(); 616 | 617 | return set; 618 | } 619 | 620 | std::vector WMIC::NetworkAdapter() { 621 | IEnumWbemClassObject *pEnumerator = ExecQuery(pCtx, L"Win32_NetworkAdapter"); 622 | 623 | // Step 7: 624 | // Get the data from the query in step 6 625 | 626 | IWbemClassObject *pclsObj = NULL; 627 | ULONG uReturn = 0; 628 | 629 | std::vector set; 630 | WMIC_NetworkAdapter networkAdapter; 631 | while(pEnumerator) { 632 | HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 633 | 634 | if(0 == uReturn) { 635 | break; 636 | } 637 | 638 | VARIANT vtProp; 639 | VariantInit(&vtProp); 640 | 641 | // Get the value of the Name property 642 | hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0); 643 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 644 | networkAdapter.name = vtProp.bstrVal; 645 | } 646 | VariantClear(&vtProp); 647 | 648 | hr = pclsObj->Get(L"Description", 0, &vtProp, 0, 0); 649 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 650 | networkAdapter.desc = vtProp.bstrVal; 651 | } 652 | VariantClear(&vtProp); 653 | 654 | hr = pclsObj->Get(L"Manufacturer", 0, &vtProp, 0, 0); 655 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 656 | networkAdapter.manufacturer = vtProp.bstrVal; 657 | } 658 | VariantClear(&vtProp); 659 | 660 | hr = pclsObj->Get(L"MACAddress", 0, &vtProp, 0, 0); 661 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 662 | networkAdapter.macAddress = vtProp.bstrVal; 663 | } 664 | VariantClear(&vtProp); 665 | 666 | hr = pclsObj->Get(L"AdapterType", 0, &vtProp, 0, 0); 667 | if(SUCCEEDED(hr) && (V_VT(&vtProp) == VT_BSTR)) { 668 | networkAdapter.adapterType = vtProp.bstrVal; 669 | } 670 | VariantClear(&vtProp); 671 | 672 | set.emplace_back(networkAdapter); 673 | 674 | #ifdef _DEBUG 675 | std::print("{}\t", W2A(networkAdapter.name)); 676 | std::print("{}\t", W2A(networkAdapter.desc)); 677 | std::print("{}\t", W2A(networkAdapter.manufacturer)); 678 | std::print("{}\t", W2A(networkAdapter.macAddress)); 679 | std::println("{}\t", W2A(networkAdapter.adapterType)); 680 | #endif 681 | 682 | pclsObj->Release(); 683 | } 684 | if(pEnumerator) pEnumerator->Release(); 685 | 686 | return set; 687 | } 688 | 689 | static bool isWindowsVersionGreaterThan1803() { 690 | HMODULE hModule = GetModuleHandleW(L"ntdll.dll"); 691 | if(hModule) { 692 | auto RtlGetVersion = reinterpret_cast(GetProcAddress(hModule, "RtlGetVersion")); 693 | if(RtlGetVersion) { 694 | RTL_OSVERSIONINFOW osvi; 695 | ZeroMemory(&osvi, sizeof(RTL_OSVERSIONINFOW)); 696 | osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW); 697 | 698 | if(RtlGetVersion(&osvi) == 0) { // STATUS_SUCCESS = 0 699 | // Windows 10 的主版本号是10 700 | if(osvi.dwMajorVersion > 10) { 701 | return true; 702 | } else if(osvi.dwMajorVersion == 10) { 703 | // 版本1803的构建号是17134 704 | return osvi.dwBuildNumber >= 17134; 705 | } 706 | } 707 | } 708 | } 709 | return false; 710 | } 711 | 712 | // 尝试获取必要的特权 713 | static bool EnablePrivilege() { 714 | HANDLE hToken; 715 | TOKEN_PRIVILEGES tp; 716 | LUID luid; 717 | 718 | // 打开进程令牌 719 | if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { 720 | std::println("无法打开进程令牌,错误码: {}", GetLastError()); 721 | return false; 722 | } 723 | 724 | // 查找SE_SYSTEM_ENVIRONMENT_NAME特权的LUID 725 | if(!LookupPrivilegeValue(nullptr, SE_SYSTEM_ENVIRONMENT_NAME, &luid)) { 726 | std::println("无法查找特权值,错误码: {}", GetLastError()); 727 | CloseHandle(hToken); 728 | return false; 729 | } 730 | 731 | // 设置特权信息 732 | tp.PrivilegeCount = 1; 733 | tp.Privileges[0].Luid = luid; 734 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 735 | 736 | // 调整特权 737 | if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) { 738 | std::println("无法调整令牌特权,错误码: {}", GetLastError()); 739 | CloseHandle(hToken); 740 | return false; 741 | } 742 | 743 | // 即使AdjustTokenPrivileges返回true,也要检查GetLastError() 744 | DWORD error = GetLastError(); 745 | if(error != ERROR_SUCCESS) { 746 | std::println("设置特权失败,错误码: {}", error); 747 | CloseHandle(hToken); 748 | return false; 749 | } 750 | 751 | CloseHandle(hToken); 752 | return true; 753 | } 754 | 755 | static inline bool canFirmwareEnvironmentVariable() { 756 | if(!isWindowsVersionGreaterThan1803()) return false; 757 | 758 | if(!EnablePrivilege()) { 759 | std::println("该功能需要以管理员权限运行"); 760 | return false; 761 | } 762 | 763 | return true; 764 | } 765 | 766 | // 便捷的辅助函数,用于指定UID创建变量名 767 | static std::string makeUefiVarName(uint32_t uid, const std::string &prefix = "WMIC_UID") { 768 | // return std::format("{}_{:08X}", prefix, uid); 769 | return prefix; 770 | } 771 | 772 | bool wmicUefiRead(uint32_t uid, void *data, int len) { 773 | if(!canFirmwareEnvironmentVariable()) return false; 774 | 775 | const auto key = makeUefiVarName(uid); 776 | bool ret = GetFirmwareEnvironmentVariableA(key.c_str(), "{00000000-0000-0000-0000-000000000000}", data, len); 777 | #ifdef _DEBUG 778 | if(!ret) { 779 | std::println("Error:{}", GetLastError()); 780 | } 781 | #endif 782 | return ret; 783 | } 784 | 785 | bool wmicUefiWrite(uint32_t uid, void *data, int len) { 786 | if(!canFirmwareEnvironmentVariable()) return false; 787 | 788 | const auto key = makeUefiVarName(uid); 789 | bool ret = SetFirmwareEnvironmentVariableA(key.c_str(), "{00000000-0000-0000-0000-000000000000}", data, len); 790 | #ifdef _DEBUG 791 | if(!ret) { 792 | std::println("Error:{}", GetLastError()); 793 | } 794 | 795 | #endif 796 | return ret; 797 | } 798 | --------------------------------------------------------------------------------