首页 > 编程语言 >C/C++ 运用VMI接口查询系统信息

C/C++ 运用VMI接口查询系统信息

时间:2023-11-18 12:11:06浏览次数:37  
标签:hres VMI 接口 查询 Win32 C++ Release SELECT vtProp

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;
}

此时,当再一次运行这段代码,就可以查询到当前系统中所有的磁盘信息,如下图所示;

标签:hres,VMI,接口,查询,Win32,C++,Release,SELECT,vtProp
From: https://www.cnblogs.com/LyShark/p/17840252.html

相关文章

  • L1-6 吉老师的回归 (15 分)(C/C++)
    输入样例1:51L1-1isaqiandaoproblem.L1-2isso...easy.L1-3isEasy.L1-4isqianDao.Wow,suchL1-5,soeasy.输出样例1:L1-4isqianDao.输入样例2:54L1-1isa-qiandaoproblem.L1-2issoeasy.L1-3isEasy.L1-4isqianDao.Wow,suchL1-5,so!!easy.输出样例......
  • 创建顺序表(C++)
    include<stdio.h>defineMaxSize10 //定义最大长度//创建顺序表typedefstruct{intdata[MaxSize]; //创建数组data用来储存数据元素,并将data的长度设置为MaxSizeintlength; //顺序表的当前长度}SqList;//初始化顺序表voidInitList(SqList&L){for(inti=0;i<......
  • c++日志库-log4cplus
    《log4cplus日志库》1.Preface  log4cplus是一款开源的c++日志库,具有线程安全,灵活,以及多粒度控制的特点;log4cplus可以将日志按照优先级进行划分,使其可以面向程序的调试,运行,测试,后期维护等软件全生命周期;可以通过配置,选择将日志输出到屏幕,文件,NTeventlog,甚至是远程服务器......
  • 5 步在 Ubuntu22 上使用 C++20
    1.安装build-essentialsudoaptinstallbuild-essential安装完检查/usr/bin/下是否有gcc,g++,gcc-11,g++11.2.添加ppa源sudoadd-apt-repositoryppa:ubuntu-toolchain-r/test3.安装gcc-13和g++-13sudoapt-getinstallgcc-13sudoapt-getinstallg++-......
  • C++ STL 容器底层实现
    一、关键词I:容器1、顺序容器:底层是链表和数组array(数组)、vector(可变数组)、deque(双端队列)forward_list(单向链表)、list(双向链表)2、关联容器:底层是红黑树set(集合)、mulitset(可重复元素的集合)map(字典)、multimap(可重复键值的字典)3、无序关联......
  • C++线程
    进程以CPU为运行单位,多个CPU可以实现进程并行,单个CPU可以实现进程并发(进程调度)线程以CPU的核心为运行单位,多个CPU内核可以实现线程并行,单个内核可以实现线程并发(线程调度)1、创建和结束一个线程 #include<iostream>#include<pthread.h>///@brief创建一个线程///@param......
  • C++类与继承
    C++类有三种访问修饰符:public(共有的)、private(私有的)、protected(受保护的)类内各区域成员的访问:1、public类内成员函数、类外、友元函数都可以访问。2、private类内成员函数、友元函数可以访问,private区域成员不能在派生类中访问。3、protected与private不同之......
  • 第十四届蓝桥杯省赛 C++B组 ---- 景区导游
    第十四届蓝桥杯省赛C++B组----景区导游LCA原题连接​ lca同时得到按原来路径走的总时间​ 最后输出时处理跳过某个点的时间​ 预处理用bfs或dfs都可以importjava.io.BufferedReader;importjava.io.InputStreamReader;importjava.util.Arrays;importjava.......
  • C++ 指针学习笔记
    C++指针学习笔记引入指针是什么指针是一个变量,其值为另一个变量的地址。指针声明的一般形式为:type*ptr_name;type是指针的基类型,ptr_name是指针的名称,*用来指定一个变量是指针对于一个指针,需要明确四个方面的内容:指针的类型、指针所指向的类型、指针的值(指针所指向的......
  • C++从零复习
    0.前言子曰:“温故而知新,可以为师矣。”学习了知识,不复习怎么行。这篇随笔是为C++小白写的复习资料,根据目录使用效果更佳。悄悄告诉你:听课的时候走神了也可以查缺补漏哦1.顺序结构(1)框架头文件#include<clude_name>//将名为“clude_name”的头文件导入//常用头文件实例#i......