C/C++ 运用VMI接口查询系统信息
Windows Management Instrumentation(WMI)是一种用于管理和监视Windows操作系统的框架。它为开发人员、系统管理员和自动化工具提供了一种标准的接口,通过这个接口,可以获取有关计算机系统硬件、操作系统和应用程序的信息,以及对系统进行管理和控制的能力。
WMI允许通过编程方式查询系统信息、监视性能、执行管理任务等。它提供了一种统一的方式来访问和管理Windows操作系统的各个方面,而无需了解底层实现细节。通过WMI,可以使用各种编程语言(如C#、VBScript、PowerShell等)来执行诸如查询系统信息、监控性能、配置系统设置等任务。
当需要通过WMI编程提取参数时,我们就需要使用WQL(Windows Management Instrumentation Query Language)它是一种查询语言,专门用于查询Windows Management Instrumentation (WMI)数据。WMI 是Windows操作系统中用于管理和监视的框架,而WQL则是用于与WMI进行交互的查询语言。
WQL 的语法类似于 SQL(Structured Query Language),使用WQL可以执行各种查询来检索关于计算机系统、硬件、软件和其他管理信息的数据。这些查询可以用于编写脚本、管理任务、监视性能等。为了方便查询获取参数这里提供一个简单的查询工具供大家查询使用,下载后打开,其默认查询的是Win32_ComputerSystem也就是系统的基本参数信息;

如果我们需要获取其他信息,比如得到计算机中所安装的所有Windows服务信息,可以执行SELECT * FROM Win32_Service语句,当然也有许多其他的通用语句可以让我们使用,例如如下几种常用的语句。
- 查询所有安装的软件
- SELECT * FROM Win32_Product
- 查询所有逻辑磁盘的信息
- SELECT * FROM Win32_LogicalDisk
- 查询所有网络适配器的信息
- SELECT * FROM Win32_NetworkAdapter
- 查询操作系统信息
- SELECT * FROM Win32_OperatingSystem
- 查询所有正在运行的进程
- SELECT * FROM Win32_Process
- 查询所有用户账户信息
- SELECT * FROM Win32_UserAccount
- 查询系统启动项
- SELECT * FROM Win32_StartupCommand
- 查询物理内存
- SELECT * FROM Win32_PhysicalMemory

如上图所示,查询将返回Win32_Service类中所有服务的信息。你可以根据需要编写更复杂的查询,以满足特定的管理或监视要求。
为了让读者更加方便的使用查询功能,此处我封装了一个SelectQuerySQL查询函数,该函数需要传入特定的查询语句,特定的查询字段以及返回值缓冲区,此时只需要读取缓冲区内的数据即可得到查询结果。
#define _CRT_SECURE_NO_WARNINGS
#define _WIN32_DCOM
#define _CRT_NONSTDC_NO_DEPRECATE
#include <comdef.h>
#include <Wbemidl.h>
#include <iostream>
#include <string>
# pragma comment(lib, "wbemuuid.lib")
using namespace std;
// 去掉字符串中的空格
void Trims(char* data)
{
int i = -1, j = 0;
int ch = ' ';
while (data[++i] != '\0')
{
if (data[i] != ch)
{
data[j++] = data[i];
}
}
data[j] = '\0';
}
// 通用查询方法,每次查询一条
bool SelectQuerySQL(LPCWSTR SQL, LPCWSTR Key, OUT char OutBuf[1024])
{
HRESULT hres;
CoUninitialize();
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
return false;
}
hres = CoInitializeSecurity(0, -1, 0, 0, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, 0, EOAC_NONE, 0);
if (FAILED(hres))
{
CoUninitialize();
return false;
}
IWbemLocator* pLoc = NULL;
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
if (FAILED(hres))
{
CoUninitialize();
return false;
}
IWbemServices* pSvc = NULL;
hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), 0, 0, 0, 0, 0, 0, &pSvc);
if (FAILED(hres))
{
pLoc->Release();
CoUninitialize();
return false;
}
hres = CoSetProxyBlanket(pSvc,RPC_C_AUTHN_WINNT,RPC_C_AUTHZ_NONE,NULL,RPC_C_AUTHN_LEVEL_CALL,RPC_C_IMP_LEVEL_IMPERSONATE,NULL,EOAC_NONE);
if (FAILED(hres))
{
pSvc->Release();
pLoc->Release();
CoUninitialize();
return false;
}
IEnumWbemClassObject* pEnumerator = NULL;
// 执行WSQL语句
hres = pSvc->ExecQuery(bstr_t("WQL"),bstr_t(SQL),WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,NULL,&pEnumerator);
if (FAILED(hres))
{
pSvc->Release();
pLoc->Release();
CoUninitialize();
return false;
}
IWbemClassObject* pclsObj;
ULONG uReturn = 0;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (0 == uReturn)
{
break;
}
VARIANT vtProp;
// 获取到指定Key字段
hr = pclsObj->Get(Key, 0, &vtProp, 0, 0);
// 将获取到的数据返回给OutBuf
wcstombs(OutBuf, vtProp.bstrVal, 1024);
VariantClear(&vtProp);
pclsObj->Release();
}
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
CoUninitialize();
return true;
}
有了上述函数的封装,那么实现查询就变得很容易了,当我们需要查询CPU序列号时,可以直接执行SELECT * FROM win32_Processor并取出里面的ProcessorId字段,使用函数时可以总结为如下所示的案例;
int main(int argc, char *argv[])
{
char RefBuffer[1024] = { 0 };
bool ref = false;
ref = SelectQuerySQL(L"SELECT * FROM win32_Processor", L"ProcessorId", RefBuffer);
std::cout << "获取CPU序列号: " << RefBuffer << std::endl;
Trims(RefBuffer);
system("pause");
return 0;
}
输出效果如下所示;

根据这个查询方法,我们就可以得到系统的各类固件序列号,这对于软件认证尤为重要;
int main(int argc, char *argv[])
{
char RefBuffer[1024] = { 0 };
bool ref = false;
ref = SelectQuerySQL(L"SELECT * FROM win32_Processor", L"ProcessorId", RefBuffer);
std::cout << "获取CPU序列号: " << RefBuffer << std::endl;
Trims(RefBuffer);
ref = SelectQuerySQL(L"SELECT * FROM Win32_BaseBoard", L"SerialNumber", RefBuffer);
std::cout << "获取主板ID号: " << RefBuffer << std::endl;
Trims(RefBuffer);
ref = SelectQuerySQL(L"SELECT * FROM Win32_BIOS", L"SerialNumber", RefBuffer);
std::cout << "获取BIOS序列号: " << RefBuffer << std::endl;
Trims(RefBuffer);
ref = SelectQuerySQL(L"SELECT * FROM Win32_PhysicalMemory", L"SerialNumber", RefBuffer);
std::cout << "获取内存序列号: " << RefBuffer << std::endl;
Trims(RefBuffer);
ref = SelectQuerySQL(L"SELECT * FROM Win32_DiskDrive WHERE Index = 0", L"SerialNumber", RefBuffer);
Trims(RefBuffer);
std::cout << "获取硬盘序列号: " << RefBuffer << std::endl;
system("pause");
return 0;
}
输出效果如下所示;

当然,有时我们也需要一次性输出多个参数,某些数据存在多条记录,在输出时也需要增加一些代码,我们以Win32_LogicalDisk为例,代码需要进行一定的改进,在循环时分别取出不同的字段,此时的查询函数需要相应的做一些改进,如下是查询函数需要变化的位置。
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (0 == uReturn)
{
break;
}
// 输出盘符字段
VARIANT vtProp_DeviceID;
VARIANT vtProp_FreeSpace;
VARIANT vtProp_Size;
// 获取到指定Key字段
hr = pclsObj->Get(L"DeviceID", 0, &vtProp_DeviceID, 0, 0);
hr = pclsObj->Get(L"FreeSpace", 0, &vtProp_FreeSpace, 0, 0);
hr = pclsObj->Get(L"Size", 0, &vtProp_Size, 0, 0);
// 转换数据为字符串
char x[32], y[32], z[32];
wcstombs(x, vtProp_DeviceID.bstrVal, 32);
wcstombs(y, vtProp_FreeSpace.bstrVal, 32);
wcstombs(z, vtProp_Size.bstrVal, 32);
std::cout << "分区: " << x << std::endl;
std::cout << "剩余: " << y << std::endl;
std::cout << "容量: " << z << std::endl;
// 清理
VariantClear(&vtProp_DeviceID);
VariantClear(&vtProp_FreeSpace);
VariantClear(&vtProp_Size);
pclsObj->Release();
}
此外,在查询参数上也应该修改为对应的SELECT * FROM Win32_LogicalDisk查询磁盘;
int main(int argc, char *argv[])
{
char RefBuffer[1024] = { 0 };
bool ref = false;
ref = SelectQuerySQL(L"SELECT * FROM Win32_LogicalDisk", L"ProcessorId", RefBuffer);
Trims(RefBuffer);
system("pause");
return 0;
}
此时,当再一次运行这段代码,就可以查询到当前系统中所有的磁盘信息,如下图所示;

C/C++ 运用VMI接口查询系统信息的更多相关文章
- 读取jar文件的sha1码,请求maven官方的solrsearch接口查询该jar文件所对应的maven坐标信息
版权声明:本文为博主原创文章,未经博主允许不得转载. import com.google.gson.JsonObject; import com.google.gson.JsonParser; imp ...
- DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render
DRF框架 全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...
- 通过IFeatureClass 接口查询 IWorkspace, 查询通配符
IWorkspace pWsI = ((IDataset)pFtCls).Workspace 查询通配符 ISQLSyntax psqls = (ISQLSyntax)(((IDataset)pFtC ...
- Linux查询系统信息命令
Linux查看系统信息是比较基础的知识,所以这个应该都需要掌握,命令和解释如下: #uname -a 查看操作系统.内核.CPU信息 #head -n 1 /etc/issue ...
- Oracle 通过数据字典查询系统信息
简介:数据字典记录了数据库系统的信息,他是只读表和视图的集合,数据字典的所有者是sys用户.注:用户只能在数据字典上执行查询操作,而维护和修改是由系统自己完成的. 1.数据字典的组成:数据字典包括数据 ...
- rails的接口查询详解
Retrieving Objects from the Database find "find"是一种常用的数据库查询方法,在Rails中被用于从数据库中查找单个记录.它可以接收一 ...
- 非常全的API接口查询
http://www.apix.cn/services/category/3 https://www.showapi.com/ https://www.juhe.cn/docs http://deve ...
- 手机号码归属地查询api接口
淘宝网 API地址: http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=15850781443 参数: tel:手机号码 返回:JSON ...
- 新浪网易淘宝等IP地区信息查询开放API接口调用方法
通过IP地址获取对应的地区信息通常有两种方法:1)自己写程序,解析IP对应的地区信息,需要数据库.2)根据第三方提供的API查询获取地区信息. 第一种方法,参见文本<通过纯真IP数据库获取IP地 ...
- ArcGIS Engine开发之旅08--和查询相关的对象和接口
原文:ArcGIS Engine开发之旅08--和查询相关的对象和接口 查询在GIS领域应该是一个很频繁的操作,在GIS中除了具有属性查询(和其他关系型数据库的查询类似),还提供了空间查询.在介绍查询 ...
随机推荐
- 小白终于解决了在学习Go中不知道Makefile是什么的难题
如何在Go中使用Makefile 1.Makefile是什么 Makefile是一种构建工具,用于在项目中定义和执行一系列命令.它通常包含了一些规则和目标,用于编译.测试.运行和清理项目. 2.Mak ...
- Hi3798MV200 恩兔N2 NS-1 (二): HiNAS海纳思使用和修改
目录 Hi3798MV200 恩兔N2 NS-1 (一): 设备介绍和刷机说明 Hi3798MV200 恩兔N2 NS-1 (二): HiNAS海纳思使用和修改 Hi3798MV200 恩兔N2 NS ...
- 使用synapse搭建matrix去中心化加密通信服务
前言 首先必须介绍下Matrix.Matrix是一个开源.可交互.去中心化的实时通信服务框架.使用Matrix可以搭建安全的通信服务器,配合支持 Matrix 的客户端可以实现个人.团队间的实时聊天交 ...
- 【go笔记】使用sqlx操作MySQL
前言 go在操作MySQL时,可以使用ORM(比如gorm.xorm),也可以使用原生sql.本文以使用sqlx为例,简单记录步骤. go version: 1.16 安装相关库 # mysql驱动 ...
- 干了这么多年C#,后悔没早点用这种“分页”,简单/高效/易维护
[前言] 干了这么多年C#,后悔没早点用这种"分页",简单/高效/易维护,比其它的分页方式强多了,不信你自己看. [正文] 支持.Net Core(2.0及以上)与.Net Fra ...
- Hugging News #0821: 新的里程碑:一百万个代码仓库!
每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...
- The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发
The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发 1.乐观并 ...
- 一次搞定:借助Hutool封装代码快速解决webservice调用烦恼
前言 相信很多同行哪怕学了许多主流技术,但工作上依然免不了和传统企业打交道,而这样的企业往往还在用webservice做接口交互. 本文是作者近两年和医疗行业的厂家打交道研究出来的一点调用webser ...
- vue中添加音频和视频
视频播放功能 1. 安装vue-video-player npm install vue-video-player --save 或 yarn add vue-video-player --save ...
- ORM分组查询复杂查询
记录一下自己在工作中遇到的一个问题,就是根据一个字段分类,然后还要统计这个字段不同状态的数量,这里我举个例子 假如有好多学生,这些学生来自不同的班级,现在我们要统计每一个班级中男生和女生的数量 def ...