Search code examples
c++winapibattery

Get battery device name


I am trying to get the names of all the battery devices on my computer using this code mostly acquired from a Microsoft tutorial but it isn't working.

#define INITGUID
#include <windows.h>
#include<batclass.h>
#include<setupapi.h>
#define GBS_HASBATTERY 0x1
#define GBS_ONBATTERY  0x2
#include<iostream>

using namespace std;

int main()
{
DWORD dwResult = GBS_ONBATTERY;
HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVICE_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

for (int idev = 0; idev < 100; idev++)
 {
  SP_DEVICE_INTERFACE_DATA did = {0};
  did.cbSize = sizeof(did);

  if (SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVICE_BATTERY, idev, &did))
   {
    DWORD cbRequired = 0;
    SetupDiGetDeviceInterfaceDetail(hdev, &did, 0, 0, &cbRequired, 0);

    if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
     {
      PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR,cbRequired);

      if (pdidd)
       {
        pdidd->cbSize = sizeof(*pdidd);

        if (SetupDiGetDeviceInterfaceDetail(hdev,&did,pdidd,cbRequired,&cbRequired,0))
         {
          HANDLE hBattery = CreateFile(pdidd->DevicePath,GENERIC_READ | GENERIC_WRITE,
          FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

          if (INVALID_HANDLE_VALUE != hBattery)
           {
            BATTERY_QUERY_INFORMATION bqi = {0};

            DWORD dwWait = 0;
            DWORD dwOut;

            if (DeviceIoControl(hBattery,
                                IOCTL_BATTERY_QUERY_TAG,
                                &dwWait,
                                sizeof(dwWait),
                                &bqi.BatteryTag,
                                sizeof(bqi.BatteryTag),
                                &dwOut,
                                NULL)
                && bqi.BatteryTag)
             {////////////////////////////////////////problem around here///////
              string  bi;
              bqi.InformationLevel = BatteryDeviceName;
              if (DeviceIoControl(hBattery,
                                  IOCTL_BATTERY_QUERY_INFORMATION,
                                  &bqi,
                                  sizeof(bqi),
                                  &bi,
                                  sizeof(bi),
                                  &dwOut,
                                  NULL))
            {
                cout<<bi;

                  BATTERY_WAIT_STATUS bws = {0};
                  bws.BatteryTag = bqi.BatteryTag;

                  BATTERY_STATUS bs;
                  if (DeviceIoControl(hBattery,
                                      IOCTL_BATTERY_QUERY_STATUS,
                                      &bws,
                                      sizeof(bws),
                                      &bs,
                                      sizeof(bs),
                                      &dwOut,
                                      NULL))
                   {
                    if (bs.PowerState & BATTERY_POWER_ON_LINE)
                     {
                      dwResult &= ~GBS_ONBATTERY;
                     }
                   }
               }
             }
            CloseHandle(hBattery);
           }
         }
        LocalFree(pdidd);
       }
     }
   }
    else  if (ERROR_NO_MORE_ITEMS == GetLastError())
     {
      break;
     }
 }
SetupDiDestroyDeviceInfoList(hdev);
}

i am trying to print the names of all the batteries, but when i run the program it doesnt print anything at all, it does however work when i request a battery_information structure instead of the string BatteryDeviceName please help


Solution

  • The problem is that in your call to DeviceIoControl is wrong. You are passing in garbage, and when you put garbage in you get garbage out.

    string bi;
    
    if(DeviceIoControl(hBattery,
                       IOCTL_BATTERY_QUERY_INFORMATION,
                       bqi,
                       sizeof(bqi),
                       &bi,         // Really?!?!?!
                       sizeof(bi),  // WHAT?!?
                       &dwOut,
                       NULL))
    

    You are passing the address a std::string object to DeviceIoControl, which knows nothing about std::string and expects the adress of a raw buffer that it can write to. You at least specify the right size for that buffer, but even that is wrong in a sense. Basically, when that function returns, that std::string is junk and accessing it could do just about anything - from crashing the program to playing Vivaldi on your speakers.

    Try something like this:

    WCHAR szBuf[_MAX_PATH] = { 0 }; // In a real program you'd dynamically 
                                    // allocate an appropriately sized buffer
                                    // instead. 
    
    if(DeviceIoControl(hBattery,
                           IOCTL_BATTERY_QUERY_INFORMATION,
                           bqi,
                           sizeof(bqi),
                           szBuf,
                           sizeof(szBuf),
                           &dwOut,
                           NULL))