以获取笔记本电池信息为例介绍WMI的使用

注:本人也还没有完全弄懂WMI的原理,以下内容仅供参考。。。
在这里插入图片描述

简单来说,比起Win32提供的接口,WMI可以提供更多的系统信息,它本身是一个数据库架构,通过它可以访问、配置、管理和监视几乎所有的Windows资源,比如用户可以在远程计算机上启动一个进程。

例如,如果我想调取笔记本的电量信息,用Win32的api就只能获得以下几个参数:

typedef struct _SYSTEM_POWER_STATUS {
  BYTE  ACLineStatus; // AC电源状态
  BYTE  BatteryFlag; // 电池充电状态
  BYTE  BatteryLifePercent; // 剩余电池电量的百分比
  BYTE  SystemStatusFlag; // 节电器的状态
  DWORD BatteryLifeTime; // 剩余电量的秒数
  DWORD BatteryFullLifeTime; // 完全充电时的电池运行时间的秒数
} SYSTEM_POWER_STATUS, *LPSYSTEM_POWER_STATUS;

官方文档链接:https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-system_power_status

而使用WMI,可以获得多得多的信息:

[Dynamic, Provider("CIMWin32"), UUID("{8502C4B9-5FBB-11D2-AAC1-006008C78BC7}"), AMENDMENT]
class Win32_Battery : CIM_Battery
{
  uint16   Availability;
  uint32   BatteryRechargeTime;
  uint16   BatteryStatus;
  string   Caption;
  uint16   Chemistry;
  uint32   ConfigManagerErrorCode;
  boolean  ConfigManagerUserConfig;
  string   CreationClassName;
  string   Description;
  uint32   DesignCapacity;
  uint64   DesignVoltage;
  string   DeviceID;
  boolean  ErrorCleared;
  string   ErrorDescription;
  uint16   EstimatedChargeRemaining;
  uint32   EstimatedRunTime;
  uint32   ExpectedBatteryLife;
  uint32   ExpectedLife;
  uint32   FullChargeCapacity;
  datetime InstallDate;
  uint32   LastErrorCode;
  uint32   MaxRechargeTime;
  string   Name;
  string   PNPDeviceID;
  uint16   PowerManagementCapabilities[];
  boolean  PowerManagementSupported;
  string   SmartBatteryVersion;
  string   Status;
  uint16   StatusInfo;
  string   SystemCreationClassName;
  string   SystemName;
  uint32   TimeOnBattery;
  uint32   TimeToFullCharge;
};

官方文档链接:
https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-battery

接下来在VS中,用C++来使用WMI:

#define _WIN32_DCOM

#include <iostream>
#include <comdef.h>
#include <Wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

using namespace std;



int main(int argc, char** argv) {
    HRESULT hres;

    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------

    hres = CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres)) {
        cout << "Failed to initialize COM library. Error code = 0x"
            << hex << hres << endl;
        return 1;                  // Program has failed.
    }

    // Step 2: --------------------------------------------------
    // Set general COM security levels --------------------------

    hres = CoInitializeSecurity(
        NULL,
        -1,                          // COM authentication
        NULL,                        // Authentication services
        NULL,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
        NULL,                        // Authentication info
        EOAC_NONE,                   // Additional capabilities 
        NULL                         // Reserved
    );


    if (FAILED(hres)) {
        cout << "Failed to initialize security. Error code = 0x"
            << hex << hres << endl;
        CoUninitialize();
        return 1;                    // Program has failed.
    }

    // Step 3: ---------------------------------------------------
    // Obtain the initial locator to WMI -------------------------

    IWbemLocator* pLoc = NULL;

    hres = CoCreateInstance(
        CLSID_WbemLocator,
        0,
        CLSCTX_INPROC_SERVER,
        IID_IWbemLocator, (LPVOID*)&pLoc);

    if (FAILED(hres)) {
        cout << "Failed to create IWbemLocator object."
            << " Err code = 0x"
            << hex << hres << endl;
        CoUninitialize();
        return 1;                 // Program has failed.
    }

    // Step 4: -----------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method

    IWbemServices* pSvc = NULL;

    // Connect to the root\cimv2 namespace with
    // the current user and obtain pointer pSvc
    // to make IWbemServices calls.
    hres = pLoc->ConnectServer(
        _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
        NULL,                    // User name. NULL = current user
        NULL,                    // User password. NULL = current
        0,                       // Locale. NULL indicates current
        NULL,                    // Security flags.
        0,                       // Authority (for example, Kerberos)
        0,                       // Context object 
        &pSvc                    // pointer to IWbemServices proxy
    );

    if (FAILED(hres)) {
        cout << "Could not connect. Error code = 0x"
            << hex << hres << endl;
        pLoc->Release();
        CoUninitialize();
        return 1;                // Program has failed.
    }

    cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;


    // Step 5: --------------------------------------------------
    // Set security levels on the proxy -------------------------

    hres = CoSetProxyBlanket(
        pSvc,                        // Indicates the proxy to set
        RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
        RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
        NULL,                        // Server principal name 
        RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
        RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
        NULL,                        // client identity
        EOAC_NONE                    // proxy capabilities 
    );

    if (FAILED(hres)) {
        cout << "Could not set proxy blanket. Error code = 0x"
            << hex << hres << endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // Step 6: --------------------------------------------------
    // Use the IWbemServices pointer to make requests of WMI ----

    // For example, get the name of the operating system
    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(
        bstr_t("WQL"),
        bstr_t("SELECT * FROM Win32_Battery"), // 改类名
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
        NULL,
        &pEnumerator);

    if (FAILED(hres)) {
        cout << "Query for operating system name failed."
            << " Error code = 0x"
            << hex << hres << endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // Step 7: -------------------------------------------------
    // Get the data from the query in step 6 -------------------

    IWbemClassObject* pclsObj = NULL;
    ULONG uReturn = 0;

    while (pEnumerator) {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
            &pclsObj, &uReturn);

        if (0 == uReturn) {
            break;
        }

        VARIANT vtProp;

        VariantInit(&vtProp);
        // Get the value of the Name property
        hr = pclsObj->Get(L"Chemistry", 0, &vtProp, 0, 0); // 改成员变量
        wcout << " Chemistry : " << vtProp.intVal << endl; // 改变量值的类型
        VariantClear(&vtProp);

        pclsObj->Release();
    }

    // Cleanup
    // ========

    pSvc->Release();
    pLoc->Release();
    pEnumerator->Release();
    CoUninitialize();

    return 0;   // Program successfully completed.

}

控制台输出:

Connected to ROOT\CIMV2 WMI namespace
Chemistry : 6
D:\VSProject\demo1\Project1\x64\Debug\Project1.exe (process 9504) exited with code 0.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . . 

说明我的笔记本用的是锂电池。

如果想要获得其他参数,改三个地方就可以了。

  • 128行的Win32_Battery
  • 161行的Chemistry
  • 162行的intVal

官方C++使用WMI的帮助文档:
https://learn.microsoft.com/en-us/windows/win32/wmisdk/example–getting-wmi-data-from-the-local-computer

原理分析:

WMI的架构图如下:
在这里插入图片描述

根据上图,作为顶层使用人员,可以有三种方式调取WMI数据库的结构:

  • 使用C++
  • 使用命令行shell
  • 使用.NET客户端应用

也可以在命令行中直接敲命令,更简单:

PS C:\Users\Double Q> Get-WmiObject -Class Win32_Battery


__GENUS                     : 2
__CLASS                     : Win32_Battery
__SUPERCLASS                : CIM_Battery
__DYNASTY                   : CIM_ManagedSystemElement
__RELPATH                   : Win32_Battery.DeviceID="1Desay*******9ECW-41"
__PROPERTY_COUNT            : 33
__DERIVATION                : {CIM_Battery, CIM_LogicalDevice, CIM_LogicalElement, CIM_ManagedSystemElement}
__SERVER                    : LAPTOP-*********
__NAMESPACE                 : root\cimv2
__PATH                      : \\LAPTOP-********\root\cimv2:Win32_Battery.DeviceID="1Desay********ECW-41"
Availability                : 3
BatteryRechargeTime         :
BatteryStatus               : 1
Caption                     : 内部电池
Chemistry                   : 6
ConfigManagerErrorCode      :
ConfigManagerUserConfig     :
CreationClassName           : Win32_Battery
Description                 : 内部电池
DesignCapacity              :
DesignVoltage               : 14945
DeviceID                    : 1Desay********ECW-41
ErrorCleared                :
ErrorDescription            :
EstimatedChargeRemaining    : 44
EstimatedRunTime            : 85
ExpectedBatteryLife         :
ExpectedLife                :
FullChargeCapacity          :
InstallDate                 :
LastErrorCode               :
MaxRechargeTime             :
Name                        : ********ECW-41
PNPDeviceID                 :
PowerManagementCapabilities : {1}
PowerManagementSupported    : False
SmartBatteryVersion         :
Status                      : OK
StatusInfo                  :
SystemCreationClassName     : Win32_ComputerSystem
SystemName                  : LAPTOP-********
TimeOnBattery               :
TimeToFullCharge            :
PSComputerName              : LAPTOP-********
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DoubleQ666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值