Home | Kontakt | Sitemap

Start

Über mich

Kontakt

Sitemap

Lizenz

Anleitungen

DVD, miniDVD

SVCD

Audio, Audio-CD (CD-DA)

AVI

Software

Von Freunden und Bekannten

Eigene Programme

Programmierung

Delphi

Lazarus

Delphi/Lazarus

Projekte

MPEG-1/2 Video

Optische Laufwerke

Audio-CD (CDDA)

Raspberry Pi Dashcam

Verschiedenes

MPEG 2 Schnitt

Project X

VCD Easy

Hardlinks

Windows

Links

Software

Programmierung Delphi - Batterie - Das Handle zum Gerät "Batterie"

Das Handle zum Gerät "Batterie"

Beschreibung

Um die Control Codes verwenden zu können wird ein Handle auf das Gerät, das heißt die Batterie, benötigt. Das Windows Dev Center enthält dafür ein Beispiel, welches die SetupAPI verwendet. Wenn ich das richtig verstehe, wird mit Hilfe der ClassGuid ein Handle auf die Geräteklasse und dann auf die Geräteschnittstellen geholt. Dann werden die Daten der Schnittstelle zu einem bestimmten Gerät ermittelt, um damit das Handle zum Gerät zu erhalten.

Hier werden die Funktionen aus dem Windows Dev Center mit den Datenstrukturen kurz dargestellt. Ausserdem gibt es eine Funktion in Delphi 7, welche das Handle und den DevicePath der Batterie ermitteln.

SetupDiGetClassDevs

Die Funktion liefert ein Handle auf die Geräteinformationen einer bestimmten Geräteklasse des Computers zurück. Das MSDN Windows Dev Center liefert eine Definition in c++ mit Erläuterungen:

HDEVINFO SetupDiGetClassDevs(
  _In_opt_ const GUID   *ClassGuid,
  _In_opt_       PCTSTR Enumerator,
  _In_opt_       HWND   hwndParent,
  _In_           DWORD  Flags
);

ClassGuid: Dies ist eine eindeutige Identfikationsnummer innerhalb des Computersystem. Unter Windows gibt es die Definition:

Battery Devices
Class = Battery
ClassGuid = {72631e54-78a4-11d0-bcf7-00aa00b7b32a}
 
This class includes battery devices and UPS devices.

Enumerator: Dies ist ein Zeiger auf eine Aufzählung. Die Angabe ist optional und es kann die Konstante NULL verwendet werden. Dies ist im Beispiel der Fall.

hwndParent: Dies ist das Handle auf ein übergeordnetes Fenster. Die Angabe ist optional und es kann die Konstannte NULL verwendet werden. Dies ist im Beispiel der Fall.

Flags: Dies sind Filter für die Funktion. Möglich sind DIGCF_ALLCLASSES, DIGCF_DEVICEINTERFACE, DIGCF_DEFAULT, DIGCF_PRESENT und DIGCF_PROFILE. Im Beispiel werden DIGCF_PRESENT und DIGCF_DEVICEINTERFACE verwendet

Die Deklaration der Funktion in Delphi:

const
  csSetupApiModule = 'SETUPAPI.DLL';
 
function SetupDiGetClassDevsA(
                   const ClassGuid  : PGUID;
                   Enumerator       : PAnsiChar;
                   hwndParent       : HWND;
                   Flags            : DWORD
                   ): HDEVINFO; stdcall; external csSetupApiModule;

SetupDiEnumDeviceInterfaces

Mit dieser Funktion werden die Schnittstellendaten geholt. Die c++-Definition der Funktion im MSDN Windows Dev Center:

BOOL SetupDiEnumDeviceInterfaces(
  _In_           HDEVINFO                  DeviceInfoSet,
  _In_opt_       PSP_DEVINFO_DATA          DeviceInfoData,
  _In_     const GUID                      *InterfaceClassGuid,
  _In_           DWORD                     MemberIndex,
  _Out_          PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
);

DeviceInfoSet: Ein Zeiger auf die Geräteinformationen. Typischerweise das Handle, welches man von SetupDiGetClassDevs erhält.

DeviceInfoData: Ein Zeiger auf eine Datenstruktur, welcher optional ist und NULL sein kann. Dies ist in dem Beispiel der Fall.

InterfaceClassGuid: Ein Zeiger auf die Schnittstellen-GUID. Das ist die selbe wie oben.

MemberIndex: Der Index auf ein Mitglied der Geräteklasse. 0 ist die erste Batterie. Normalerweise sollte nur eine vorhanden sein.

DeviceInterfaceData: Dies ist ein Zeiger auf einen zugewiesenen Puffer, welcher bei erfolgreichem Abschluss der Funktion eine Datenstruktur SP_DEVICE_INTERFACE_DATA mit Zugriffsinformationen zur Schnittstelle enthält.

Bei erfolgreichem Abschluss der Funktion wird als Ergebnis TRUE geliefert, andernfalls FALSE. Den Fehlercode erhält man mit der Funktion GetLastError.

DeviceInfoData

typedef struct _SP_DEVINFO_DATA {
  DWORD     cbSize;
  GUID      ClassGuid;
  DWORD     DevInst;
  ULONG_PTR Reserved;
} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;

cbSize: Größe der Struktur in Bytes.

ClassGuid: Die Schnittstellen-GUID.

DevInst: Die Infos zum Unterknoten.

DeviceInterfaceData

typedef struct _SP_DEVICE_INTERFACE_DATA {
  DWORD     cbSize;
  GUID      InterfaceClassGuid;
  DWORD     Flags;
  ULONG_PTR Reserved;
} SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;

Diese Struktur wird unten an die Funktion SetupDiGetDeviceInterfaceDetail weiter gegeben.

Die Deklarationen in Delphi:

type
  _SP_DEVINFO_DATA =
  record
    cbSize    : DWORD;
    ClassGuid : TGUID;
    DevInst   : DWORD;
    Reserved  : ULONG;
  end;
  TSP_DEVINFO_DATA = _SP_DEVINFO_DATA;
  PSP_DEVINFO_DATA = ^_SP_DEVINFO_DATA;
 
type
  _SP_DEVICE_INTERFACE_DATA =
  record
    cbSize             : DWORD;
    InterfaceClassGuid : TGUID;
    Flags              : DWORD;
    Reserved           : ULONG;
  end;
  TSP_DEVICE_INTERFACE_DATA = _SP_DEVICE_INTERFACE_DATA;
  PSP_DEVICE_INTERFACE_DATA = ^_SP_DEVICE_INTERFACE_DATA;
 
function SetupDiEnumDeviceInterfaces(
                   DeviceInfoSet            : HDEVINFO;
                   DeviceInfoData           : PSP_DEVINFO_DATA;
                   const InterfaceClassGuid : PGUID;
                   MemberIndex              : DWORD;
                   DeviceInterfaceData      : PSP_DEVICE_INTERFACE_DATA
                   ): Boolean; stdcall; external csSetupApiModule;

SetupDiGetDeviceInterfaceDetail

Diese Funktion ermittelt Einzelheiten zur Schnittstelle wie den Pfad, welcher für die Funktion CreateFile unten benötigt wird. Die c++-Definition im MSDN Windows Dev Center:

BOOL SetupDiGetDeviceInterfaceDetail(
  _In_      HDEVINFO                         DeviceInfoSet,
  _In_      PSP_DEVICE_INTERFACE_DATA        DeviceInterfaceData,
  _Out_opt_ PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData,
  _In_      DWORD                            DeviceInterfaceDetailDataSize,
  _Out_opt_ PDWORD                           RequiredSize,
  _Out_opt_ PSP_DEVINFO_DATA                 DeviceInfoData
);

DeviceInfoSet: Wieder der Zeiger auf die Geräteinformationen. Typischerweise das Handle, welches man von SetupDiGetClassDevs erhält.

DeviceInterfaceData: Ein Zeiger auf die Datenstruktur SP_DEVICE_INTERFACE_DATA, welche typischwerweise von der Funktion SetupDiEnumDeviceInterfaces zurück gegeben wird.

DeviceInterfaceDetailData: Ein Zeiger zu der Struktur SP_DEVICE_INTERFACE_DETAIL_DATA, welche die Informationen zur angegebenen Schnittstelle enthält. Der Parameter ist optional und kann NULL sein.

DeviceInterfaceDetailDataSize: Die Größe der Struktur DeviceInterfaceDetailData, wobei vom DevicePath nur das erste Zeichen mitgezählt wird. Ist DeviceInterfaceDetailData mit NULL angegeben, ist die Größe 0.

RequiredSize: Dies ist ein Zeiger auf die Größe des Puffers, welcher für die Aufnahme der DeviceInterfaceDetailData notwendig ist. Der Zeiger ist optional und kann NULL sein.

DeviceInfoData: Ein Zeiger auf einen Puffer, welcher NULL sein kann. Dies ist im Beispiel der Fall.

Bei erfolgreichem Abschluss der Funktion wird als Ergebnis TRUE geliefert, andernfalls FALSE. Den Fehlercode erhält man mit der Funktion GetLastError.

Die Funktion wird zweimal aufgerufen. Beim ersten Aufruf ist DeviceInterfaceDetailData NULL um die Größe des Puffers zu ermitteln. Anschliessend wird der Puffer bereitgestellt und der Zeiger darauf gesetzt.

DeviceInterfaceDetailData

typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
  DWORD cbSize;
  TCHAR DevicePath[ANYSIZE_ARRAY];
} SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA;

cbSize: Größe der Struktur in Bytes.

DevicePath: Ein nullterminierter String, welcher den Schnittstellenpfad enthält, wecher für die Funktion CreateFile benötigt wird.

Die Deklarationen in Delphi:

type
  _SP_DEVICE_INTERFACE_DETAIL_DATA_A =
  packed record
    cbSize     : DWORD;
    DevicePath : array [0..0] of AnsiChar;
  end;
  TSP_DEVICE_INTERFACE_DETAIL_DATA_A = _SP_DEVICE_INTERFACE_DETAIL_DATA_A;
  PSP_DEVICE_INTERFACE_DETAIL_DATA_A = ^_SP_DEVICE_INTERFACE_DETAIL_DATA_A;
 
function SetupDiGetDeviceInterfaceDetailA(
                   DeviceInfoSet                 : HDEVINFO;
                   DeviceInterfaceData           : PSP_DEVICE_INTERFACE_DATA;
                   DeviceInterfaceDetailData     : PSP_DEVICE_INTERFACE_DETAIL_DATA_A;
                   DeviceInterfaceDetailDataSize : DWORD;
                   RequiredSize                  : PDWORD;
                   DeviceInfoData                : PSP_DEVINFO_DATA
                   ): Boolean; stdcall; external csSetupApiModule;

_SP_DEVICE_INTERFACE_DETAIL_DATA_A muss als packed record deklariert werden. Dies hat Einfluss auf seine Größe. Sie verringert sich von 8 auf 5 Byte. Ohne packed erhält man beim Aufruf der Funktion den Fehler ERROR_INVALID_USER_BUFFER, 1784 (0x6F8), The supplied user buffer is not valid for the requested operation.

SetupDiDestroyDeviceInfoList

Diese Funktion gibt die Informationen und durch die aufgerufenen Funktionen reservierten Speicher. Die c++-Definition im MSDN Windows Dev Center lautet:

BOOL SetupDiDestroyDeviceInfoList(
  _In_ HDEVINFO DeviceInfoSet
);

DeviceInfoSet: Dies ist das Handle, welches mit der Funktion SetupDiGetClassDevs ermittelt worden war.

Die Deklarationen in Delphi:

function SetupDiDestroyDeviceInfoList(
                   DeviceInfoSet: HDEVINFO
                   ): Boolean; stdcall; external csSetupApiModule;

CreateFile

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

HANDLE WINAPI CreateFile(
  _In_     LPCTSTR               lpFileName,
  _In_     DWORD                 dwDesiredAccess,
  _In_     DWORD                 dwShareMode,
  _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  _In_     DWORD                 dwCreationDisposition,
  _In_     DWORD                 dwFlagsAndAttributes,
  _In_opt_ HANDLE                hTemplateFile
);

lpFileName: Der Name des Gerätes, welches geöffnet werden soll. Das ist hier der DevicePath aus den DeviceInterfaceDetailData aus der Funktion SetupDiGetDeviceInterfaceDetail

dwDesiredAccess: Die Flags für den Zugriff. Im Beispiel wird GENERIC_READ | GENERIC_WRITE verwendet.

dwShareMode: Die Flags für die Freigabe. Im Beispiel wird FILE_SHARE_READ | FILE_SHARE_WRITE verwendet.

lpSecurityAttributes: Ein Zeiger auf die Sicherheitsattribute. Der Parameter ist optional und kann NULL sein. Dies ist im Beispiel der Fall.

dwCreationDisposition: Eine Reaktion, wenn das Gerät existiert oder nicht. Im Beispiel ist der Wert OPEN_EXISTING, das bedeutet, öffnen wenn es existiert.

dwFlagsAndAttributes: Attribute und Flags für das Gerät. Im Beispiel ist dies FILE_ATTRIBUTE_NORMAL.

hTemplateFile: Ein Handle zu einem Template. Der Parameter ist optional und kann NULL sein. Dies ist im Beispiel der Fall.

Die Funktion ist in Delphi in der Unit Windows deklariert.

Die Funktion in Delphi 7

function GetBatteryHandle(out DevicePath: String): THandle;
var
  hdev       : HDEVINFO;
  idev       : DWORD;
  did        : TSP_DEVICE_INTERFACE_DATA;
  pdidd      : PSP_DEVICE_INTERFACE_DETAIL_DATA_A;
  cbRequired : DWORD;
  hBattery   : THandle;
begin
  Result := 0;
 
  hdev := SetupDiGetClassDevsA(@GUID_DEVCLASS_BATTERY,
                               nil,
                               0,
                               DIGCF_PRESENT or DIGCF_DEVICEINTERFACE);
 
  if (hdev <> INVALID_HANDLE_VALUE)
  then begin
    idev := 0; // Erste Batterie
    ZeroMemory(@did, SizeOf(did));
    did.cbSize := SizeOf(TSP_DEVICE_INTERFACE_DATA);
 
    if (SetupDiEnumDeviceInterfaces(hdev,
                                    nil,
                                    @GUID_DEVCLASS_BATTERY,
                                    idev,
                                    @did))
    then try
      cbRequired := 0;
 
      // Result ist FALSE weil die Größe für die Antwort zu klein ist.
      SetupDiGetDeviceInterfaceDetailA(hdev,
                                       @did,
                                       nil,
                                       0,
                                       @cbRequired,
                                       nil);
 
      if (ERROR_INSUFFICIENT_BUFFER = GetLastError)
      then begin
        pdidd := AllocMem(cbRequired + SizeOf(TSP_DEVICE_INTERFACE_DETAIL_DATA_A));
        pdidd.cbSize := SizeOf(TSP_DEVICE_INTERFACE_DETAIL_DATA_A);

        if (pdidd <> nil)
        then try
          if (SetupDiGetDeviceInterfaceDetailA(hdev,
                                               @did,
                                               pdidd,
                                               cbRequired,
                                               @cbRequired,
                                               nil))
          then begin
            hBattery := CreateFile(pdidd.DevicePath,
                                   GENERIC_READ or GENERIC_WRITE,
                                   FILE_SHARE_READ or FILE_SHARE_WRITE,
                                   nil,
                                   OPEN_EXISTING,
                                   FILE_ATTRIBUTE_NORMAL,
                                   0);
            if (hBattery <> INVALID_HANDLE_VALUE)
            then begin
              Result     := hBattery;
              DevicePath := PAnsiChar(@pdidd^.DevicePath);
            end;
          end;
        finally
          FreeMem(pdidd);
        end;
      end;
    finally
      SetupDiDestroyDeviceInfoList(hdev);
    end;
  end;
end;

Download

Demo mit Delphi 7 compiliert
battery_handle_exe.7z (152 kB) - MD5 (1kB)

Source der Demo
battery_handle_src.7z (3 kB) - MD5 (1kB)

Batterie > Handle > Tag