Battery FullChargeCapacity с использованием WMI возвращает 0

Я пытался использовать WMI в C ++. В классе 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 propertyhr = 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();
}

1

Решение

Как вы сами поняли, с WMI вы не получите нужную информацию, вам придется напрямую поговорить с драйвером батареи.

Драйвер батареи связывается с батареей через I²C и имеет доступ к этим значениям. К счастью, есть некоторые коды IOCLT, специфичные для батареи, которые вы можете использовать.

Сначала вам нужно знать имя устройства драйвера батареи. Ниже метод использует SetupApi для этого, но вы также можете получить его из реестра на HKEY_LOCAL_MACKINE\SYSTEM\CurrentControlSet\Services\CmBatt\Enum\0 (если ваша батарея использует 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);

Теперь нам нужна батарея тег, это идентификатор батареи, сгенерированный драйвером. F.E. если вы меняете батареи, драйвер сгенерирует новую метку. С помощью этого тега мы можем запросить остальную информацию о батарее (см. 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 Вы можете получить процентную информацию об оставшейся емкости батареи.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]