當你想通了你自己,與WMI,你不會得到你想要的信息,你必須直接與電池司機交談。
電池驅動程序通過I²C與電池通信並可以訪問這些值。幸運的是,您可以使用一些特定於電池的IOCLT代碼。
您首先需要知道電池驅動程序的deviceName。下面的方法使用SetupApi,但您也可以從登錄處得到它HKEY_LOCAL_MACKINE\SYSTEM\CurrentControlSet\Services\CmBatt\Enum\0
(假設您的電池使用了驅動程序CmBatt.sys驅動程序)。我建議使用SetupApi。
下面是一個輔助函數來獲取DEVICENAME:
#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);
現在我們所需要的電池tag,這是由驅動程序生成的電池的標識符。 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 Power Management Control Codes
UPDATE
概括爲您的評論的要求,爲了讀出時間估算,請求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
就可以得到電池的剩餘容量的百分比表示。
我真的很感謝你的幫助! 我合併了你編寫的所有代碼,但編譯器注意到我4錯誤其中之一是: 錯誤LNK2019:無法解析的外部符號__imp__SetupDiEnumDeviceInterfaces @ 20在函數中引用「class std :: basic_string,class std :: allocator > const __cdecl GetBatteryDevicePath(int)「 我該怎麼辦? –
KOO
你必須鏈接到SetupApi.lib –
哦,我的上帝......你有真棒技能! 那麼我是否也可以知道充電率,EstimatedChargeRemaining或當前電量? 我試過了: BATTERY_QUERY_INFORMATION bqi = {3,BatteryEstimatedTime}; \t \t \t std :: cout << bqi.AtRate; //返回0 AND // BATTERY_STATUS bi = {3}; \t \t \t \t如果(::的DeviceIoControl(hBattery, \t \t \t \t \t IOCTL_BATTERY_QUERY_STATUS, \t \t \t \t \t&BQI, \t \t \t \t \t的sizeof(BQI), \t \t \t \t \t&璧, \t \t \t \t \t的sizeof(BI), \t \t \t \t \t&dwBytesReturned, \t \t \t \t \t NULL)) \t \t \t \t {性病:: COUT << bi.Rate <<的std :: ENDL; //它沒有工作 – KOO