Programmierung > Delphi > Batterie > Informationen

Informationen zur Batterie abfragen

  • Beschreibung
  • Control Code IOCTL_BATTERY_QUERY_INFORMATION
  • Struktur BATTERY_QUERY_INFORMATION
  • Struktur BATTERY_REPORTING_SCALE
  • Struktur BATTERY_INFORMATION
  • Struktur BATTERY_MANUFACTURE_DATE
  • Funktion in Delphi 7
  • Download
  • Links
  • Beschreibung

    Mit dem Controlcode IOCTL_BATTERY_QUERY_INFORMATION erhält man verschiedene Informationen der Batteris, zum Beispiel Bezeichnung, Hersteller und Seriennummer.

    Control Code IOCTL_BATTERY_QUERY_INFORMATION

    Die c++-Definition im NSDN Windows Dev Center:

    BOOL DeviceIoControl(
      (HANDLE) hDevice,                // handle to battery
      IOCTL_BATTERY_QUERY_INFORMATION, // dwIoControlCode
      (LPVOID) lpInBuffer,             // input buffer
      (DWORD) nInBufferSize,           // size of input buffer
      (LPVOID) lpOutBuffer,            // output buffer
      (DWORD) nOutBufferSize,          // size of output buffer
      (LPDWORD) lpBytesReturned,       // number of bytes returned
      (LPOVERLAPPED) lpOverlapped      // OVERLAPPED structure
    );
    

    hDevice: Das Handle, welches im Kapitel Handle ermittelt wurde.

    dwIoControlCode: Der Controlcode für die Operation.

    lpInBuffer: Ein Zeiger auf den Speicher mit einer Datenstuktur BATTERY_QUERY_INFORMATION, mit welcher mitgeteilt wird, welche Information man möchte.

    nInBufferSize: Die Größe der Datenstruktur in Byte.

    lpOutBuffer: Der Zeiger auf den Rückgabepuffer. Der Datentyp und die Größe sind vom angeforderten Informationlevel abhängig.

    nOutBufferSize: Die Größe des Rückgabepuffers. Sie ist vom Informationslevel abhängig.

    lpBytesReturned: Ein Zeiger auf einen Wert, der angibt, wieviel Daten zurückgegben wurden. War der Rückgabepuffer zu klein ist der Wert 0 und GetLastError gibt den Fehlerwert ERROR_INSUFFICIENT_BUFFER zurück. Wenn die Overlapped Struktur nicht verwendet wird, darf dieser nicht 0 sein.

    lpOverlapped: Ein Zeiger auf die Overlapped Struktur. Sie kann nur vorhanden sein, wenn das Gerät mit dem Flag FILE_FLAG_OVERLAPPED geöffnet wurde. Dies ist hier nicht der Fall.

    Wurde die Operation fehlerfrei durchgeführt ist der Rückgabewert 0.

    Die Funktion ist in Delphi in der Unit Windows deklariert.

    Der Controlcode IOCTL_BATTERY_QUERY_INFORMATION ist in der batclass.h definiert:

    #define FILE_DEVICE_BATTERY   0x00000029
     
    #define IOCTL_BATTERY_QUERY_INFORMATION \
        CTL_CODE(FILE_DEVICE_BATTERY,0x11,METHOD_BUFFERED,FILE_READ_ACCESS)
    
    const
      FILE_DEVICE_BATTERY = $00000029;
      FILE_READ_ACCESS    = $0001;
      METHOD_BUFFERED     = $0000;
    
    const
      IOCTL_BATTERY_QUERY_INFORMATION = (FILE_DEVICE_BATTERY shl 16 or
                                         FILE_READ_ACCESS shl 14 or
                                         $11 shl 2 or
                                         METHOD_BUFFERED);
    

    Struktur BATTERY_QUERY_INFORMATION

    Die Struktur enthält die Batterieinformationen und die c++-Definition im NSDN Windows Dev Center lautet:

    typedef struct _BATTERY_QUERY_INFORMATION {
      ULONG                           BatteryTag;
      BATTERY_QUERY_INFORMATION_LEVEL InformationLevel;
      LONG                            AtRate;
    } BATTERY_QUERY_INFORMATION, *PBATTERY_QUERY_INFORMATION;
    

    BatteryTag: Der aktuelle Batterie-Tag für die Batterie, welcher im Kapitel Tag ermittelt wurde. Wenn dieser Wert nicht mit dem aktuellen Tag der Batterie übereinstimmt, wird die Anfrage mit ERROR_FILE_NOT_FOUND abgeschlossen.

    InformationLevel: Gibt an, welche Information gewünscht wird.

    Informationslevel Wert Beschreibung
    BatteryDeviceName 4 Nulltermierter Unicodestring mit dem Namen der Batterie.
    BatteryEstimatedTime 3 Die geschätzte Akkulaufzeit in Sekunden als ULONG. Bei Änderungen wird es keine Benachrichtigung. Wenn die Zeit unbekannt ist (zB. wenn die Batterie nicht entladen wird), ist der Rückgabewert BATTERY_UNKNOWN_TIME.
    BatteryGranularityInformation 1 Ein Array von BATTERY_REPORTING_SCALE-Strukturen mit maximal vier Einträgen.
    BatteryInformation 0 Eine BATTERY_INFORMATION Struktur.
    BatteryManufactureDate 5 Eine BATTERY_MANUFACTURE_DATE Struktur.
    BatteryManufactureName 6 Ein nullterminierter Unicodestring mit dem Namen des Herstellers.
    BatterySerialNumber 8 Ein nullterminierter Unicodestring mit der Seriennummer.
    BatteryTemperature 2 Ein ULONG-Wert, welcher die gegenwärtige Temperatur in Zehntel Grad Kelvin angibt.
    BatteryUniqueID 7 Ein nullterminierter Unicodestring für eine eindeutige Identifizierung.

    AtRate: Dieser Parameter wird nur im Zusammenhang mit BatteryEstimatedTime verwendet. Ist der Parameter Null basiert die Berechnung der Zeit auf der aktuellen Abflussrate. Sonst wurde die zurückgegebene Zeit für die angegebene Rate berechnet.

    Die Deklaration in Delphi:

    type
      BATTERY_QUERY_INFORMATION_LEVEL =
      (
        BatteryInformation,
        BatteryGranularityInformation,
        BatteryTemperature,
        BatteryEstimatedTime,
        BatteryDeviceName,
        BatteryManufactureDate,
        BatteryManufactureName,
        BatteryUniqueID,
        BatterySerialNumber
      );
      TBATTERY_QUERY_INFORMATION_LEVEL = BATTERY_QUERY_INFORMATION_LEVEL;
     
    type
      _BATTERY_QUERY_INFORMATION =
      record
        BatteryTag       : ULONG;
        InformationLevel : BATTERY_QUERY_INFORMATION_LEVEL;
        AtRate           : LongInt;
      end;
      TBATTERY_QUERY_INFORMATION = _BATTERY_QUERY_INFORMATION;
      PBATTERY_QUERY_INFORMATION = ^_BATTERY_QUERY_INFORMATION;
    

    Struktur BATTERY_REPORTING_SCALE

    typedef struct {
      ULONG Granularity;
      ULONG Capacity;
    } BATTERY_REPORTING_SCALE, *PBATTERY_REPORTING_SCALE;
    

    Granularity: Die Auflösung des Kapazitätswertes, der in Milliwattstunden (mWh) zurückgegeben wird. Sie kann sich im Laufe der Zeit ändern, da Batterieentladung und Wiederaufladung den Messbereich verändern.

    Capacity: Die obere Kapazitätsgrenze für die Auflösung. Die Auflösung gilt für die von IOCTL_BATTERY_QUERY_STATUS gemeldeten Kapazitäten, die kleiner oder gleich dieser Kapazität (mWh) sind, aber größer oder gleich der im vorherigen Arrayelement angegebenen Kapazität oder null, wenn dies das erste Arrayelement ist.

    Die Deklaration in Delphi:

    type
      BATTERY_REPORTING_SCALE =
      record
        Granularity : ULONG;
        Capacity    : ULONG;
      end;
      TBATTERY_REPORTING_SCALE = BATTERY_REPORTING_SCALE;
      PBATTERY_REPORTING_SCALE = ^BATTERY_REPORTING_SCALE;
     
      TBATTERY_REPORTING_SCALE_ARRAY = array[0..3] of TBATTERY_REPORTING_SCALE;
    

    Struktur BATTERY_INFORMATION

    Die Struktur enthält verschiedene Informationen über die Batterie.

    typedef struct _BATTERY_INFORMATION {
      ULONG Capabilities;
      UCHAR Technology;
      UCHAR Reserved[3];
      UCHAR Chemistry[4];
      ULONG DesignedCapacity;
      ULONG FullChargedCapacity;
      ULONG DefaultAlert1;
      ULONG DefaultAlert2;
      ULONG CriticalBias;
      ULONG CycleCount;
    } BATTERY_INFORMATION, *PBATTERY_INFORMATION;
    

    Capabilities: Die Kapazitäten der Batterie. In dem Parameter können mehrere Flags gesetzt sein:

    Konstante Beschreibung
    BATTERY_CAPACITY_RELATIVE
    0x40000000
    Wenn dieses Bit nicht gesetzt ist, ist die Kapazität in Milliwattstunden (mWh) und die Rate in Milliwatt (mW) angegeben. Ist es gesetzt, wird in Einheiten pro Stunde gemeldet. Bei einer voll aufgeladene Kapazität von 100 gibt eine Rate von 200 an, dass die Batterie in einer halben Stunde leer ist.
    BATTERY_IS_SHORT_TERM
    0x20000000
    Zeigt an, dass dies der normale Betrieb für eine fehlersichere Funktion ist. Wenn dieses Bit nicht gesetzt ist, wird erwartet, dass die Batterie während des normalen Systemgebrauchs verwendet wird.
    BATTERY_SET_CHARGE_SUPPORTED
    0x00000001
    Gibt an, dass die eingestellten Informationsanforderungen des Typs BatteryCharge von diesem Akku unterstützt werden.
    BATTERY_SET_DISCHARGE_SUPPORTED
    0x00000002
    Zeigt an, dass die eingestellten Informationsanforderungen des Typs BatteryDischarge von diesem Akku unterstützt werden.
    BATTERY_SYSTEM_BATTERY
    0x80000000
    Zeigt an, dass die Batterie die allgemeine Stromversorgung des Systems übernehmen kann.

    Technology: Der Wert 0 gibt an, dass die Batterie nicht wiederaufladbar ist. Der Wert 1 gibt an, dass die Batterie wiederauflladbar ist.

    Chemistry: Enthält einen Unicodestring mit der Abkürzung für die Batteriechemie.

    StringBedeutung
    PbAcLead Acid
    LIONLithium Ion
    Li-ILithium Ion
    NiCdNickel Cadmium
    NiMHNickel Metal Hydride
    NiZnNickel Zinc
    RAMRechargeable Alkaline-Manganese

    Wenn BATTERY_CAPACITY_RELATIVE nicht gesetzt ist, sind die Kapazitäten in mWh angegeben. Sonst sind es relative Angaben.

    DesignedCapacity: Die theoretische Kapazität der neuen Batterie.

    FullChargedCapacity: Die Kapazität des voll geladenen Akkus. Im Vergleich mit DesignedCapacity kann man den Verschleiß der Batterie schätzen.

    DefaultAlert1: Die vom Hersteller vorgeschlagene Kapazität in mWh, bei der ein geringer Batteriealarm auftreten sollte. Die Definitionen von niedrig variieren von Hersteller zu Hersteller. Dieser Wert wird üblicherweise als Standardeinstellung für den kritischen Batteriealarm verwendet.

    DefaultAlert2: Die vom Hersteller vorgeschlagene Kapazität in mWh, bei der eine Warnmeldung auftritt. Definitionen der Warnung variieren von Hersteller zu Hersteller. Dieser Wert wird üblicherweise als Standardeinstellung für den Batteriealarm verwendet.

    CriticalBias: Die Abweichung von Null in mWh, welche auf Batterie Berichterstattung angewendet wird. Einige Batterien reservieren eine kleine Reserve, damit die Batterie nicht komplett entleert wird.

    CycleCount: Die Anzahl der Lade-/Entladezyklen der Batterie, wenn die Batterie einen Zykluszähler unterstützt, sonst ist der Zähler 0.

    Die Deklaration in Delphi:

    type
      _BATTERY_INFORMATION =
      record
        Capabilities        : ULONG;
        Technology          : UCHAR;
        Reserved            : array [1..3] of UCHAR;
        Chemistry           : array [1..4] of UCHAR;
        DesignedCapacity    : ULONG;
        FullChargedCapacity : ULONG;
        DefaultAlert1       : ULONG;
        DefaultAlert2       : ULONG;
        CriticalBias        : ULONG;
        CycleCount          : ULONG;
      end;
      TBATTERY_INFORMATION = _BATTERY_INFORMATION;
      PBATTERY_INFORMATION = ^_BATTERY_INFORMATION;
    

    Den Datentyp von Chemistry kann man auch mit CHAR deklarieren. Dann kann man sich später die Konvertierung von UCHAR = Byte nach CHAR sparen.

    Struktur BATTERY_MANUFACTURE_DATE

    Die Struktur enthält das Datum der Herstellung der Batterie.

    typedef struct _BATTERY_MANUFACTURE_DATE {
      UCHAR  Day;
      UCHAR  Month;
      USHORT Year;
    } BATTERY_MANUFACTURE_DATE, *PBATTERY_MANUFACTURE_DATE;
    

    Day: Der Tag eines Monats im Bereich von 1 bis 31.

    Month: Der Monat eines Jahres im Bereich von 1 bis 12.

    Year: Ein Jahr im Bereich von 1900 bis 2100.

    Die Deklaration in Delphi:

    type
      _BATTERY_MANUFACTURE_DATE =
      record
        Day   : UCHAR;
        Month : UCHAR;
        Year  : Word;
      end;
      TBATTERY_MANUFACTURE_DATE = _BATTERY_MANUFACTURE_DATE;
      PBATTERY_MANUFACTURE_DATE = ^_BATTERY_MANUFACTURE_DATE;
    

    Funktion in Delphi 7

    Bei den Informationslevel BatteryDeviceName, BatteryManufactureName, BatterySerialNumber und BatteryUniqueID gibt es als Ergebnis nullterminierte Unicodestrings. Die Funktionen sind damit fast identisch.

    function GetBatteryManufactureName(hBattery: THandle; aTag: Cardinal): String;
    var
      rBatQueryInfo  : TBATTERY_QUERY_INFORMATION;
      pOutBuffer     : PWideChar;
      nOutBufferSize : Cardinal;
      dwReturned     : Cardinal;
    begin
      Result := rsError;
     
      ZeroMemory(@rBatQueryInfo, SizeOf(TBATTERY_QUERY_INFORMATION));
      rBatQueryInfo.BatteryTag       := aTag;
      rBatQueryInfo.InformationLevel := BatteryManufactureName;
      rBatQueryInfo.AtRate           := 0;
     
      nOutBufferSize := 255;
      pOutBuffer     := AllocMem(nOutBufferSize);
     
      dwReturned := 0;
     
      if (DeviceIoControl(hBattery,
                          IOCTL_BATTERY_QUERY_INFORMATION,
                          @rBatQueryInfo,
                          SizeOf(TBATTERY_QUERY_INFORMATION),
                          pOutBuffer,
                          nOutBufferSize,
                          dwReturned,
                          nil))
      then Result := WideCharToString(pOutBuffer);
     
      FreeMem(pOutBuffer);
    end;
    

    Obwohl alle drei Elemente von rBatQueryInfo gesetzt werden ist das ZeroMemry notwendig. Sonst gibt es den Systemfehler ERROR_INVALID_FUNCTION - 1 (0x1) - Incorrect function.

    Bei BatteryEstimatedTime erhält man eine Zeit in Sekunden als ULONG. Ist die Zeit unbekannt, ist der Wert $80000000 (BATTERY_UNKNOWN_TIME). Undokumentiert ist der Wert DWORD(-1) = $FFFFFFFF. Dieser wird zurückgegeben, wenn die Batterie vollständig geladen ist.

    function GetBatteryEstimatedTime(hBattery: THandle; aTag: Cardinal): String;
    var
      rBatQueryInfo  : TBATTERY_QUERY_INFORMATION;
      pOutBuffer     : ULONG;
      nOutBufferSize : Cardinal;
      dwReturned     : Cardinal;
    begin
      Result := rsError;
     
      ZeroMemory(@rBatQueryInfo, SizeOf(TBATTERY_QUERY_INFORMATION));
      rBatQueryInfo.BatteryTag       := aTag;
      rBatQueryInfo.InformationLevel := BatteryEstimatedTime;
      rBatQueryInfo.AtRate           := 0;
     
      nOutBufferSize := SizeOf(ULONG);
     
      dwReturned := 0;
     
      if (DeviceIoControl(hBattery,
                          IOCTL_BATTERY_QUERY_INFORMATION,
                          @rBatQueryInfo,
                          SizeOf(TBATTERY_QUERY_INFORMATION),
                          @pOutBuffer,
                          nOutBufferSize,
                          dwReturned,
                          nil))
      then begin
        case pOutBuffer of
          BATTERY_UNKNOWN_TIME : Result := rsUnknown;
          $FFFFFFFF            : Result := rsReady;
          else begin
            Result := rsClear;
            while (pOutBuffer > 0)
            do begin
              Result := IntToStr(pOutBuffer mod 60) + ':' + Result;
              pOutBuffer := pOutBuffer div 60;
            end;
            Delete(Result, Length(Result), 1);
          end;
        end;
      end;
    end;
    

    Für BatteryTemperature ist die Funktion ähnlich. Bei mir schlägt die Funktion mit dem Systemfehler ERROR_INVALID_FUNCTION - 1 (0x1) - Incorrect function. fehl. Da sie mit der Zeit funktioniert, denke ich, dass es daran liegt, dass kein Sensor vorhanden ist.

    function GetBatteryTemperature(hBattery: THandle; aTag: Cardinal): String;
    var
      rBatQueryInfo  : TBATTERY_QUERY_INFORMATION;
      pOutBuffer     : ULONG;
      nOutBufferSize : Cardinal;
      dwReturned     : Cardinal;
    begin
      Result := rsError;
     
      ZeroMemory(@rBatQueryInfo, SizeOf(TBATTERY_QUERY_INFORMATION));
      rBatQueryInfo.BatteryTag       := aTag;
      rBatQueryInfo.InformationLevel := BatteryTemperature;
      rBatQueryInfo.AtRate           := 0;
     
      nOutBufferSize := SizeOf(ULONG);
     
      dwReturned := 0;
     
      if (DeviceIoControl(hBattery,
                          IOCTL_BATTERY_QUERY_INFORMATION,
                          @rBatQueryInfo,
                          SizeOf(TBATTERY_QUERY_INFORMATION),
                          @pOutBuffer,
                          nOutBufferSize,
                          dwReturned,
                          nil))
      then Result := Format('%d.%d Kelvin', [pOutBuffer div 10, pOutBuffer mod 10])
      else Result := rsNotSupported;
    end;
    

    Das Informationslevel BatteryManufactureDate scheint von meiner Laptop-Batterie ebenfalls nicht unterstützt zu werden. Denn die Funktion bringt nur den Systemfehler ERROR_INVALID_FUNCTION - 1 (0x1) - Incorrect function.

    function GetBatteryManufactureDate(hBattery: THandle; aTag: Cardinal): String;
    var
      rBatQueryInfo  : TBATTERY_QUERY_INFORMATION;
      pOutBuffer     : TBATTERY_MANUFACTURE_DATE;
      nOutBufferSize : Cardinal;
      dwReturned     : Cardinal;
    begin
      Result := rsError;
     
      ZeroMemory(@rBatQueryInfo, SizeOf(TBATTERY_QUERY_INFORMATION));
      rBatQueryInfo.BatteryTag       := aTag;
      rBatQueryInfo.InformationLevel := BatteryManufactureDate;
      rBatQueryInfo.AtRate           := 0;
     
      nOutBufferSize := SizeOf(TBATTERY_MANUFACTURE_DATE);
     
      dwReturned := 0;
     
      if (DeviceIoControl(hBattery,
                          IOCTL_BATTERY_QUERY_INFORMATION,
                          @rBatQueryInfo,
                          SizeOf(TBATTERY_QUERY_INFORMATION),
                          @pOutBuffer,
                          nOutBufferSize,
                          dwReturned,
                          nil))
      then Result := Format('%.2d.%.2d.%.4d', [pOutBuffer.Day, pOutBuffer.Month, pOutBuffer.Year])
      else Result := rsNotSupported;
    end;
    

    Beim Informationslevel BatteryGranularityInformation bekommt man ein Array mit maximal vier Einträgen zurück. In einer Class sieht die Funktion sicher besser aus.

    function GetBatteryGranularityInformation(hBattery: THandle; aTag: Cardinal;
                               out rBRSArray: TBATTERY_REPORTING_SCALE_ARRAY): Boolean;
    var
      rBatQueryInfo : TBATTERY_QUERY_INFORMATION;
      dwReturned    : Cardinal;
    begin
      ZeroMemory(@rBRSArray, SizeOf(TBATTERY_REPORTING_SCALE_ARRAY));
     
      ZeroMemory(@rBatQueryInfo, SizeOf(TBATTERY_QUERY_INFORMATION));
      rBatQueryInfo.BatteryTag       := aTag;
      rBatQueryInfo.InformationLevel := BatteryGranularityInformation;
      rBatQueryInfo.AtRate           := 0;
     
      dwReturned := 0;
     
      Result := (DeviceIoControl(hBattery,
                                 IOCTL_BATTERY_QUERY_INFORMATION,
                                 @rBatQueryInfo,
                                 SizeOf(TBATTERY_QUERY_INFORMATION),
                                 @rBRSArray,
                                 SizeOf(TBATTERY_REPORTING_SCALE_ARRAY),
                                 dwReturned,
                                 nil));
    end;
    

    Das Informationslevel BatteryInformation liefert eine BATTERY_INFORMATION-Struktur. Diese wird erst abgeholt und dann ausgewertet.

    function GetBatteryInformation(hBattery: THandle; aTag: Cardinal;
                                        out rBatInfo: TBATTERY_INFORMATION): Boolean;
    var
      rBatQueryInfo : TBATTERY_QUERY_INFORMATION;
      dwReturned    : Cardinal;
    begin
      ZeroMemory(@rBatInfo, SizeOf(TBATTERY_INFORMATION));
     
      ZeroMemory(@rBatQueryInfo, SizeOf(TBATTERY_QUERY_INFORMATION));
      rBatQueryInfo.BatteryTag       := aTag;
      rBatQueryInfo.InformationLevel := BatteryInformation;
      rBatQueryInfo.AtRate           := 0;
     
      dwReturned := 0;
     
      Result := (DeviceIoControl(hBattery,
                                 IOCTL_BATTERY_QUERY_INFORMATION,
                                 @rBatQueryInfo,
                                 SizeOf(TBATTERY_QUERY_INFORMATION),
                                 @rBatInfo,
                                 SizeOf(TBATTERY_INFORMATION),
                                 dwReturned,
                                 nil));
    end;
    

    Download

    Demo mit Delphi 7 compiliert
    battery_info_exe.7z (155 kB) - MD5 (1kB)

    Source der Demo
    battery_info_src.7z (6 kB) - MD5 (1kB)