unit UBatterieFunktionen;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,
Activex,StdCtrls, ExtCtrls, Registry, ComCtrls,
ImgList, ShellAPI;
type
SP_DEVICE_INTERFACE_DATA =
record
cbSize: DWORD;
Guid: TGUID;
Flags: DWORD;
Reserve: Pointer;
end;
type
PSP_DEVICE_INTERFACE_DATA = ^SP_DEVICE_INTERFACE_DATA;
type
SP_DEVICE_INTERFACE_DETAIL_DATA =
packed record
cbSize: DWORD;
DevicePath:
array[0..0]
of AnsiChar;
end;
type
PSP_DEVICE_INTERFACE_DETAIL_DATA = ^SP_DEVICE_INTERFACE_DETAIL_DATA;
BATTERY_QUERY_INFORMATION_LEVEL = (
BatteryInformation,
BatteryGranularityInformation,
BatteryTemperature,
BatteryEstimatedTime,
BatteryDeviceName,
BatteryManufactureDate,
BatteryManufactureName,
BatteryUniqueID,
BatterySerialNumber);
TBatteryQueryInformationLevel = BATTERY_QUERY_INFORMATION_LEVEL;
_BATTERY_QUERY_INFORMATION =
record
BatteryTag: ULONG;
InformationLevel: BATTERY_QUERY_INFORMATION_LEVEL;
AtRate: integer;
end;
BATTERY_QUERY_INFORMATION = _BATTERY_QUERY_INFORMATION;
PBATTERY_QUERY_INFORMATION = ^BATTERY_QUERY_INFORMATION;
TBatteryQueryInformation = BATTERY_QUERY_INFORMATION;
PBatteryQueryInformation = PBATTERY_QUERY_INFORMATION;
_BATTERY_INFORMATION =
record
Capabilities: ULONG;
Technology: UCHAR;
Reserved:
array[0..2]
of UCHAR;
Chemistry:
array[0..3]
of UCHAR;
DesignedCapacity: ULONG;
FullChargedCapacity: ULONG;
DefaultAlert1: ULONG;
DefaultAlert2: ULONG;
CriticalBias: ULONG;
CycleCount: ULONG;
end;
BATTERY_INFORMATION = _BATTERY_INFORMATION;
PBATTERY_INFORMATION = ^BATTERY_INFORMATION;
TBatteryInformation = BATTERY_INFORMATION;
PBatteryInformation = PBATTERY_INFORMATION;
type
TGUID =
record
Data1: DWORD;
Data2: Word;
Data3: Word;
Data4:
array[0..7]
of Byte;
end;
type
LPGUID = ^TGUID;
type
SP_DEVINFO_DATA =
record
cbSize: DWord;
Guid: TGUID;
DevInst: DWORD;
Reserve: DWORD;
end;
type
PSP_DEVINFO_DATA = ^SP_DEVINFO_DATA;
type
TSetupDiGetClassDevs =
function(
const ClassGuid: LPGUID; Enumerator: LPCTSTR; hwndParent: HWND; Flags: DWORD): Pointer;
stdcall;
TSetupDiEnumDeviceInterfaces =
function(DeviceInfoSet: Pointer; DeviceInfoData: PSP_DEVINFO_DATA;
const InterfaceClassGuid: LPGUID; MemberIndex: DWORD; DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA): Boolean;
stdcall;
TSetupDiGetDeviceInterfaceDetail =
function(DeviceInfoSet: Pointer; DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA; DeviceInterfaceDetailData: PSP_DEVICE_INTERFACE_DETAIL_DATA; DeviceInterfaceDetailDataSize: DWORD; RequiredSize: PDWORD; DeviceInfoData: PSP_DEVINFO_DATA): Boolean;
stdcall;
TSetupDiDestroyDeviceInfoList =
function(DeviceInfoSet: Pointer): Boolean;
stdcall;
const
GUID_DEVICE_BATTERY: TGUID = (Data1: $72631E54; Data2: $78A4; Data3: $11D0; Data4: ($BC, $F7, $00, $AA, $00, $B7, $B3, $2A));
type //für den Record _BATTERY_MANUFACTURE_DATE
USHORT = Word;
type //für die Funktion WerteAuslesen
_BATTERY_MANUFACTURE_DATE =
record
Day: UCHAR;
Month: UCHAR;
Year: USHORT;
end;
BATTERY_MANUFACTURE_DATE = _BATTERY_MANUFACTURE_DATE;
PBATTERY_MANUFACTURE_DATE = ^BATTERY_MANUFACTURE_DATE;
TBatteryManufactureDate = BATTERY_MANUFACTURE_DATE;
PBatteryManufactureDate = PBATTERY_MANUFACTURE_DATE;
_BATTERY_WAIT_STATUS =
record
BatteryTag: ULONG;
Timeout: ULONG;
PowerState: ULONG;
LowCapacity: ULONG;
HighCapacity: ULONG;
end;
BATTERY_WAIT_STATUS = _BATTERY_WAIT_STATUS;
PBATTERY_WAIT_STATUS = ^BATTERY_WAIT_STATUS;
TBatteryWaitStatus = BATTERY_WAIT_STATUS;
PBatteryWaitStatus = PBATTERY_WAIT_STATUS;
_BATTERY_STATUS =
record
PowerState: ULONG;
Capacity: ULONG;
Voltage: ULONG;
Rate: integer;
end;
BATTERY_STATUS = _BATTERY_STATUS;
PBATTERY_STATUS = ^BATTERY_STATUS;
TBatteryStatus = BATTERY_STATUS;
PBatteryStatus = PBATTERY_STATUS;
type //für die Funktion WerteAuslesen
_BATTERY_REPORTING_SCALE =
record
Granularity: DWORD;
Capacity: DWORD;
end;
BATTERY_REPORTING_SCALE = _BATTERY_REPORTING_SCALE;
PBATTERY_REPORTING_SCALE = ^BATTERY_REPORTING_SCALE;
TBatteryReportingScale = BATTERY_REPORTING_SCALE;
PBatteryReportingScale = PBATTERY_REPORTING_SCALE;
const //für IOCTL_BATTERY_QUERY
DIGCF_DEFAULT = $00000001;
DIGCF_PRESENT = $00000002;
DIGCF_ALLCLASSES = $00000004;
DIGCF_PROFILE = $00000008;
DIGCF_DEVICEINTERFACE = $00000010;
FILE_DEVICE_BATTERY = $00000029;
FILE_READ_ACCESS = $0001;
METHOD_BUFFERED = 0;
BATTERY_CAPACITY_RELATIVE = $40000000;
BATTERY_IS_SHORT_TERM = $20000000;
BATTERY_SET_CHARGE_SUPPORTED = $00000001;
BATTERY_SET_DISCHARGE_SUPPORTED = $00000002;
BATTERY_SYSTEM_BATTERY = $80000000;
const //für die Funktion WerteAuslesen
BATTERY_CHARGING = $00000004;
BATTERY_CRITICAL = $00000008;
BATTERY_DISCHARGING = $00000002;
BATTERY_POWER_ON_LINE = $00000001;
const //für die Funktion WerteAuslesen
BATTERY_UNKNOWN_RATE = $80000000;
IOCTL_BATTERY_QUERY_INFORMATION = (FILE_DEVICE_BATTERY
shl 16)
or (FILE_READ_ACCESS
shl 14)
or ($11
shl 2)
or METHOD_BUFFERED;
IOCTL_BATTERY_QUERY_TAG = (FILE_DEVICE_BATTERY
shl 16)
or (FILE_READ_ACCESS
shl 14)
or ($10
shl 2)
or METHOD_BUFFERED;
IOCTL_BATTERY_QUERY_STATUS = (FILE_DEVICE_BATTERY
shl 16)
or (FILE_READ_ACCESS
shl 14)
or ($13
shl 2)
or METHOD_BUFFERED;
//-----------------------------------------
//-----------------------------------------
type
TBatterieFunktionen =
class
private
//Neue Variablen ab hier:
SetupDiGetClassDevs: TSetupDiGetClassDevs;
SetupDiEnumDeviceInterfaces: TSetupDiEnumDeviceInterfaces;
SetupDiGetDeviceInterfaceDetail: TSetupDiGetDeviceInterfaceDetail;
SetupDiDestroyDeviceInfoList: TSetupDiDestroyDeviceInfoList;
//Neue Funktionen ab hier:
function AkkusAufzaehlen(): Cardinal;
procedure UnitCreate;
public
//Neue Variablen ab hier:
Netzbetrieb: bool;
Powerstatus:
string;
AktuelleKapazität: integer;
//in mWh = Ladezustand
AktuelleSpannung: integer;
//in mV = Volt
AktuelleStromstaerke: integer;
//in mA
AktuelleRate: integer;
//in mWh = MG (Energiefluss)
AkkuHersteller:
string;
AkkuHerstellerDatum:
string;
AkkuName:
string;
AkkuNummer:
string;
AkkuID:
string;
AkkuChemie:
string;
AkkuTechnologie:
string;
AkkuFunktion:
string;
AkkuUnterteilungen:
array[0..3]
of Integer;
//in mWh
AkkuKapazitäten:
array[0..3]
of Integer;
//in mWh
AkkuKapazitätAngabe: integer;
//in mWh
AkkuKapazitätVoll: integer;
//in mWh = Wattvoll
AkkuRestZeit: integer;
//in Minuten
AkkuGesamtZeit: integer;
//in Minuten
AkkuLadeZyklen:integer;
AkkuAlarm1:integer;
// bei ... mWh
AkkuAlarm2:integer;
// bei ... mWh
AkkuKritisch:integer;
// bei ... mWh
AkkuTemperatur:integer;
// in GradCelsius;
Akkuanzahl: cardinal;
VorhandeneAkkus:
Array of String;
AkkuStatus:
string;
AkkuProzente: integer;
//Neue Funktionen ab hier:
procedure WerteAktualisieren(Batterienummer:integer);
//zu GetAccuStatus------------------------------------------
function GetAccuStatus(MeldungAnzeigen: boolean): boolean;
Constructor Create;
end;
var
BatterieFunktionen : TBatterieFunktionen;
implementation
Constructor TBatterieFunktionen.Create;
begin
UnitCreate;
end;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Kurz info: diese Funktion erhöht den Speicherbedarf je aufruf!
function TBatterieFunktionen.GetAccuStatus(MeldungAnzeigen: boolean): boolean;
var
SystemPowerStatus: TSystemPowerStatus;
Meldung:
String;
begin
result:=false;
GetSystemPowerStatus(SystemPowerStatus);
with SystemPowerStatus
do begin
// Wird das System mit Wechselstrom oder Akku betrieben ?
case ACLineStatus
of
0: Meldung:='
System wird mit Akku betrieben';
1: Meldung:='
System wird mit Wechselstrom betrieben';
else Meldung:='
Unbekannter Status';
end;
// +Ladezustand der Batterie
case BatteryFlag
of
1 : Meldung:=Meldung+'
, im Ladezustand';
//Hoher
2 : Meldung:=Meldung+'
, Achtung! Niedriger Ladezustand';
4 : Meldung:=Meldung+'
, Achtung! Kritischer Ladezustand';
8 : Meldung:=Meldung+'
, Die Batterie wird geladen';
128: Meldung:=Meldung+'
, Es existiert keine System-Batterie';
255: Meldung:=Meldung+'
, Unbekannter Status';
end;
AkkuStatus:= Meldung;
// +Ladezustand in Prozent
if BatteryLifePercent <> 255
then
AkkuProzente:=BatteryLifePercent
else
AkkuProzente:=-1;
if (ACLineStatus = 0)
and (Meldung <> '
')
then begin
if MeldungAnzeigen
then ShowMessage(Meldung);
result:=true;
end;
end;
end;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Kurz info
function TBatterieFunktionen.AkkusAufzaehlen(): Cardinal;
var
DeviceInfo: Pointer;
DeviceInterfaceData: SP_DEVICE_INTERFACE_DATA;
RequiredSize: DWORD;
DevicePath:
String;
PDeviceInformationDetailData: PSP_DEVICE_INTERFACE_DETAIL_DATA;
begin
Result := 0;
Finalize(VorhandeneAkkus);
Try
DeviceInfo := SetupDiGetClassDevs(@GUID_DEVICE_BATTERY,
nil, 0, DIGCF_PRESENT
or DIGCF_DEVICEINTERFACE);
except
DeviceInfo :=
nil;
end;
while DeviceInfo<>
nil do
begin
DeviceInterfaceData.cbSize := SizeOf(DeviceInterfaceData);
if not SetupDiEnumDeviceInterfaces(DeviceInfo,
nil, @GUID_DEVICE_BATTERY, Result, @DeviceInterfaceData)
then
Break;
SetupDiGetDeviceInterfaceDetail(DeviceInfo, @DeviceInterfaceData,
nil, 0, @RequiredSize,
nil);
PDeviceInformationDetailData := AllocMem(RequiredSize + SizeOf(SP_DEVICE_INTERFACE_DETAIL_DATA));
PDeviceInformationDetailData.cbSize := SizeOf(SP_DEVICE_INTERFACE_DETAIL_DATA);
SetupDiGetDeviceInterfaceDetail(DeviceInfo, @DeviceInterfaceData, PDeviceInformationDetailData, RequiredSize, @RequiredSize,
nil);
DevicePath := PChar(@PDeviceInformationDetailData^.DevicePath);
FreeMem(PDeviceInformationDetailData);
Inc(Result);
SetLength(VorhandeneAkkus, Result);
VorhandeneAkkus[Result - 1] := DevicePath;
end;
if DeviceInfo <>
nil then SetupDiDestroyDeviceInfoList(DeviceInfo);
end;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Kurz info
procedure TBatterieFunktionen.UnitCreate;
var
hLibrary: HMODULE;
i: Cardinal;
begin
//-------------------------------------------
Netzbetrieb:=true;
try
hLibrary := LoadLibrary('
setupapi.dll');
if hLibrary <> 0
then
begin
@SetupDiGetClassDevs := GetProcAddress(hLibrary, '
SetupDiGetClassDevsA');
@SetupDiEnumDeviceInterfaces := GetProcAddress(hLibrary, '
SetupDiEnumDeviceInterfaces');
@SetupDiGetDeviceInterfaceDetail := GetProcAddress(hLibrary, '
SetupDiGetDeviceInterfaceDetailA');
@SetupDiDestroyDeviceInfoList := GetProcAddress(hLibrary, '
SetupDiDestroyDeviceInfoList');
end;
Akkuanzahl := Akkusaufzaehlen();
except end;
WerteAktualisieren(0);
end;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Kurz info
procedure TBatterieFunktionen.WerteAktualisieren(Batterienummer:integer);
var
i, hBattery: Cardinal;
lpBytesReturned: DWORD;
BQI: TBatteryQueryInformation;
BI: TBatteryInformation;
BS: TBatteryStatus;
BMD: TBatteryManufactureDate;
BWS: TBatteryWaitStatus;
BRS:
array[0..3]
of BATTERY_REPORTING_SCALE;
OutBuffer: PWideChar;
begin
if (AkkusAufzaehlen > 0)
then
begin
hBattery := CreateFile(PAnsiChar(VorhandeneAkkus[Batterienummer]), GENERIC_READ
or GENERIC_WRITE, FILE_SHARE_READ
or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_TAG,
nil, 0, @i, SizeOf(Cardinal), lpBytesReturned,
nil);
ZeroMemory(@BQI, SizeOf(BATTERY_QUERY_INFORMATION));
BQI.BatteryTag := i;
BWS.BatteryTag := BQI.BatteryTag;
BWS.Timeout := 1;
BS.PowerState := 0;
BS.Capacity := 0;
//Powerstatus:
DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, @BWS, SizeOf(BWS), @BS, SizeOf(BS), lpBytesReturned,
nil);
Powerstatus := '
'; Netzbetrieb:=false;
if BS.PowerState
and BATTERY_CHARGING = BATTERY_CHARGING
then begin
Powerstatus := ('
Aufladen');
end else if BS.PowerState
and BATTERY_CRITICAL = BATTERY_CRITICAL
then begin
Powerstatus := ('
Kritisch');
end else if BS.PowerState
and BATTERY_DISCHARGING = BATTERY_DISCHARGING
then begin
Powerstatus := ('
Entladen');
end else if BS.PowerState
and BATTERY_POWER_ON_LINE = BATTERY_POWER_ON_LINE
then begin
Powerstatus := ('
Netzbetrieb');
Netzbetrieb:=true;
end;
//-------------------
//Aktuelle Kapazität:
AktuelleKapazität := BS.Capacity;
//-------------------
//Aktuelle Spannung:
if BS.Voltage = $FFFFFFFF
then AktuelleSpannung := 0
else AktuelleSpannung := BS.Voltage;
//-------------------
//Rate:
if BS.Rate = BATTERY_UNKNOWN_RATE
then AktuelleRate := 0
else AktuelleRate := BS.Rate;
//-------------------
OutBuffer := AllocMem(MAX_PATH + 1);
//Informationen:
try
BQI.InformationLevel := BatteryManufactureName;
if DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, @BQI, SizeOf(BATTERY_QUERY_INFORMATION), OutBuffer, 255, lpBytesReturned,
nil)
then
AkkuHersteller := WideCharToString(OutBuffer);
//-----------------
BQI.InformationLevel := BatteryDeviceName;
if DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, @BQI, SizeOf(BATTERY_QUERY_INFORMATION), OutBuffer, 255, lpBytesReturned,
nil)
then
AkkuName := WideCharToString(OutBuffer);
//-----------------
BQI.InformationLevel := BatterySerialNumber;
if DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, @BQI, SizeOf(BATTERY_QUERY_INFORMATION), OutBuffer, 255, lpBytesReturned,
nil)
then
AkkuNummer := WideCharToString(OutBuffer);
//-----------------
BQI.InformationLevel := BatteryUniqueID;
if DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, @BQI, SizeOf(BATTERY_QUERY_INFORMATION), OutBuffer, 255, lpBytesReturned,
nil)
then
AkkuID := WideCharToString(OutBuffer);
//-----------------
for i := 0
to 3
do
begin
BRS[i].Granularity := 0;
AkkuUnterteilungen[i] := 0;
BRS[i].Capacity := 0;
AkkuKapazitäten[i] := 0;
end;
BQI.InformationLevel := BatteryGranularityInformation;
if DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, @BQI, SizeOf(BATTERY_QUERY_INFORMATION), @BRS, SizeOf(BRS), lpBytesReturned,
nil)
then
begin
AkkuUnterteilungen[0]:=BRS[0].Granularity;
AkkuUnterteilungen[1]:=BRS[1].Granularity;
AkkuUnterteilungen[2]:=BRS[2].Granularity;
AkkuUnterteilungen[3]:=BRS[3].Granularity;
AkkuKapazitäten[0]:=BRS[0].Capacity;
AkkuKapazitäten[1]:=BRS[1].Capacity;
AkkuKapazitäten[2]:=BRS[2].Capacity;
AkkuKapazitäten[3]:=BRS[3].Capacity;
end;
BQI.InformationLevel := BatteryGranularityInformation;
//Hersteller Datum:
AkkuHerstellerDatum :='
';
if DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, @BQI, SizeOf(BATTERY_QUERY_INFORMATION), @BMD, SizeOf(BMD), lpBytesReturned,
nil)
then
AkkuHerstellerDatum := IntToStr(BMD.Day) + '
.' + IntToStr(BMD.Month) + '
.' + IntToStr(BMD.Year);
//-----------------
BQI.InformationLevel := BatteryInformation;
if DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, @BQI, SizeOf(BATTERY_QUERY_INFORMATION), @BI, SizeOf(BI), lpBytesReturned,
nil)
then
begin
//Chemie:
AkkuChemie := '
';
for i := 0
to 3
do
AkkuChemie := AkkuChemie + Char(BI.Chemistry[i]);
//-----------------
//Technologie:
case BI.Technology
of
0: AkkuTechnologie := '
Nicht Aufladbar';
1: AkkuTechnologie := '
Aufladbar';
end;
//-----------------
//Akku Kapazität insgesamt:
AkkuKapazitätAngabe :=BI.DesignedCapacity;
//Volle Kapazität:
AkkuKapazitätVoll := BI.FullChargedCapacity;
//Restzeit ermitteln:
AkkuGesamtZeit:= round((BI.DesignedCapacity / BI.FullChargedCapacity)*60);
AkkuRestZeit:= round(AktuelleKapazität * (AkkuGesamtZeit/60));
AkkuRestZeit:= round( AkkuRestZeit * AkkuGesamtZeit / BI.DesignedCapacity);
//Zykluszähler:
AkkuLadeZyklen:= BI.CycleCount;
//Alarm:
AkkuAlarm1 := BI.DefaultAlert1;
AkkuAlarm2 := BI.DefaultAlert2;
//Kritische:
AkkuKritisch := BI.CriticalBias;
//Funktion:
AkkuFunktion := '
';
if (BI.Capabilities
and BATTERY_CAPACITY_RELATIVE) <> 0
then begin
AkkuFunktion := '
Capacity Relative';
end else if (BI.Capabilities
and BATTERY_IS_SHORT_TERM) <> 0
then begin
AkkuFunktion := '
Is Short Term';
end else if (BI.Capabilities
and BATTERY_SET_CHARGE_SUPPORTED) <> 0
then begin
AkkuFunktion := '
Set Charge Supported';
end else if (BI.Capabilities
and BATTERY_SET_DISCHARGE_SUPPORTED) <> 0
then begin
AkkuFunktion := '
Set Discharge Supported';
end else if (BI.Capabilities
and BATTERY_SYSTEM_BATTERY) <> 0
then begin
AkkuFunktion := '
System Battery';
end;
end;
BQI.InformationLevel := BatteryEstimatedTime;
if DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, @BQI, SizeOf(BATTERY_QUERY_INFORMATION), @i, 255, lpBytesReturned,
nil)
then
begin
if (i < 1000)
and (i > 0)
then begin
AkkuRestZeit := i;
end;
end;
//the battery's current temperature, in 10ths of a degree Kelvin
//Round(Temperature/ 10 + 273.15)
//Temperatur:
BQI.InformationLevel := BatteryTemperature;
AkkuTemperatur := 0;
if DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, @BQI, SizeOf(BATTERY_QUERY_INFORMATION), @i, 255, lpBytesReturned,
nil)
then
begin
if i <> 0
then begin
AkkuTemperatur := i;
end;
end;
finally
FreeMem(OutBuffer);
end;
CloseHandle(hBattery);
end;
If (AktuelleRate = 0)
then begin
AktuelleStromstaerke:=(round(AktuelleKapazität/AktuelleSpannung*1000));
end else begin
AktuelleStromstaerke:=(round(Abs(AktuelleRate)/AktuelleSpannung*1000));
end;
GetAccuStatus(false);
end;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end.