使用WMI的电池电量已满返回0
Battery FullChargeCapacity using WMI returns 0
我尝试在C++中使用WMI。在WMI类CIM_Battery
中,FullChargeCapacity
的值仅返回0。
有其他方法可以得到FullChargeCapacity
吗?
我尝试的代码是:
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
while (pEnumerator)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if (0 == uReturn)
{
break;
}
VARIANT vtProp;
// Get the value of the Name property
hr = pclsObj->Get(L"FullChargeCapacity", 0, &vtProp, 0, 0);
wcout << " FullChargeCapacity : " << vtProp.ulVal << endl;
VariantClear(&vtProp);
/*hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
wcout << " Name : " << vtProp.bstrVal << endl;
VariantClear(&vtProp);*/
pclsObj->Release();
}
正如您自己发现的那样,使用WMI将无法获得您想要的信息,您必须直接与电池驱动程序交谈。
电池驱动器通过I²C与电池通信,并可以访问这些值。幸运的是,您可以使用一些特定于电池的IOCLT代码。
您首先需要知道电池驱动程序的设备名称。下面的方法使用SetupApi,但您也可以从HKEY_LOCAL_MACKINESYSTEMCurrentControlSetServicesCmBattEnum
的注册表中获取它(假设您的电池使用CmBatt.sys驱动程序)。我确实建议使用SetupApi。
以下是获取设备名称:的辅助函数
#include <Windows.h>
#include <SetupAPI.h>
#include <batclass.h>
#include <devguid.h>
#include <string>
#include <iostream>
#ifndef UNICODE
typedef std::string String;
#else
typedef std::wstring String;
#endif
const String GetBatteryDevicePath(const int batteryIndex)
{
String result = TEXT("");
HDEVINFO hDeviceInfoList = ::SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDeviceInfoList != INVALID_HANDLE_VALUE)
{
SP_DEVICE_INTERFACE_DATA did = { 0 };
did.cbSize = sizeof(did);
if (::SetupDiEnumDeviceInterfaces(hDeviceInfoList, 0, &GUID_DEVCLASS_BATTERY, batteryIndex, &did))
{
DWORD dwRequiredSize = 0;
::SetupDiGetDeviceInterfaceDetail(hDeviceInfoList, &did, 0, 0, &dwRequiredSize, 0);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::LocalAlloc(LPTR, dwRequiredSize);
if (pdidd)
{
pdidd->cbSize = sizeof(*pdidd);
if (::SetupDiGetDeviceInterfaceDetail(hDeviceInfoList, &did, pdidd, dwRequiredSize, &dwRequiredSize, 0))
{
result = pdidd->DevicePath;
}
::LocalFree(pdidd);
}
}
}
::SetupDiDestroyDeviceInfoList(hDeviceInfoList);
}
return result;
}
之后,您可以使用CreateFile
:打开电池设备的手柄
const String devicePath = ::GetBatteryDevicePath(0);
const auto hBattery = ::CreateFile(devicePath.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
现在我们需要电池标签,这是驱动程序生成的电池的标识符。如果你更换电池,驱动程序会生成一个新标签。有了这个标签,我们可以查询其余的电池信息(请参阅battery_information):
if (hBattery != INVALID_HANDLE_VALUE)
{
DWORD dwBytesReturned, dwWait = 0;
BATTERY_QUERY_INFORMATION bqi = { 0 };
// Query battery tag
if (::DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_TAG,
&dwWait,
sizeof(dwWait),
&bqi.BatteryTag,
sizeof(bqi.BatteryTag),
&dwBytesReturned,
NULL)
&& bqi.BatteryTag)
{
// Now we can query all other battery info
BATTERY_INFORMATION bi = { 0 };
if (::DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_INFORMATION,
&bqi,
sizeof(bqi),
&bi,
sizeof(bi),
&dwBytesReturned,
NULL))
{
std::cout << "FullChargedCapacity = " << bi.FullChargedCapacity << std::endl;
std::cout << "DesignedCapacity = " << bi.DesignedCapacity << std::endl;
}
}
::CloseHandle(hBattery);
}
IOCTL代码和相关结构概述在MSDN电源管理控制代码上
更新
根据您的评论中的要求,为了读取时间估计,请像前一个片段中那样在bqi
中请求标签,然后像这样查询BatteryEstimatedTime
:
bqi.AtRate = 0;
bqi.InformationLevel = BatteryEstimatedTime;
ULONG lEstimatedTime;
if (::DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_INFORMATION,
&bqi,
sizeof(bqi),
&lEstimatedTime,
sizeof(lEstimatedTime),
&dwBytesReturned,
NULL))
{
if (lEstimatedTime != BATTERY_UNKNOWN_TIME)
std::cout << "EstimatedTime = " << lEstimatedTime / 60 << "m" << std::endl;
else
std::cout << "EstimatedTime = UNKNOWN" << std::endl;
}
用于读取实际电压和容量:
BATTERY_WAIT_STATUS bws = { 0 };
BATTERY_STATUS bs = { 0 };
bws.BatteryTag = bqi.BatteryTag;
if (::DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_STATUS,
&bws,
sizeof(bws),
&bs,
sizeof(bs),
&dwBytesReturned,
NULL))
{
if (bs.PowerState & BATTERY_CHARGING)
std::cout << "Battery is CHARGING" << std::endl;
if (bs.PowerState & BATTERY_DISCHARGING)
std::cout << "Battery is DISCHARGING" << std::endl;
if (bs.PowerState & BATTERY_POWER_ON_LINE)
std::cout << "Power on-line" << std::endl;
std::cout << "Battery voltage: " << bs.Voltage << "mV" << std::endl;
std::cout << "Battery capacity: " << bs.Capacity << "mW" << std::endl;
}
通过比较bs.Capacity
和bi.FullChargedCapacity
,您可以获得电池剩余容量的百分比指示。
相关文章:
- 如何使用单个返回语句返回对变量的引用
- 为什么重载运算符可以返回其返回类型以外的其他内容?
- 在函数返回中返回对新分配的shared_ptr的尊重合法吗
- 为什么要为指针返回类型返回一系列字符?
- 返回不同返回类型的函数的函数指针的函数
- 从弱指针返回类型返回共享指针
- 无法为unique_ptr返回类型返回 nullptr
- 程序的本地执行不会重新返回运输返回.远程执行确实
- QmetaObject :: IndexOfMethod返回到底返回索引
- 这是我的代码,它正在返回Process返回的255(0xff)码块
- 从模板返回的 C++ 返回
- 如何在 JNA 中获取字节数组作为从 C 字节指针返回的返回
- 返回未返回变量值
- 使用WMI的电池电量已满返回0
- 以Integer返回类型返回浮点值
- 如何使用数据类型的一次返回来返回错误
- 适当的函数返回类型返回日期时间
- 查宁在C++返回后返回了指针
- 返回语句返回一个空指针值而不是期望的值
- 为什么从浮点返回方法返回双精度不会在 c++ 中导致任何错误/警告