2015-12-03 90 views
1

我嘗試在C++中使用WMI。在WMI類CIM_Battery,FullChargeCapacity值剛剛返回0.使用WMI的電池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(); 
} 

回答

0

當你想通了你自己,與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.Capacitybi.FullChargedCapacity就可以得到電池的剩餘容量的百分比表示。

+0

我真的很感謝你的幫助! 我合併了你編寫的所有代碼,但編譯器注意到我4錯誤其中之一是: 錯誤LNK2019:無法解析的外部符號__imp__SetupDiEnumDeviceInterfaces @ 20在函數中引用「class std :: basic_string ,class std :: allocator > const __cdecl GetBatteryDevicePath(int)「 我該怎麼辦? – KOO

+0

你必須鏈接到SetupApi.lib –

+1

哦,我的上帝......你有真棒技能! 那麼我是否也可以知道充電率,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