Projekte > Optische Laufwerke > Medieninformationen

Table of Contents (IOCTL)

IOCTL_CDROM_READ_TOC control code

Mit dem IOCTL_CDROM_READ_TOC control code kann man die Vorgehensweise aus Table of Content (MMC) vereinfachen. Man benötigt keinen Command Descriptor Block und muss die Antwort nicht auswerten sondern erhält sofort eine aufbereitete Struktur. Ausserdem benötigt man keine Schreibrechte für die Laufwerke. Der IOCTL_CDROM_READ_TOC control code ist in der Headerdatei Ntddcdrm.h definert. Diese findet sich nicht im MSDN sondern im DDK. Am besten bemüht man eine Internetsuchmaschine und findet zum Beispiel hier:

 
  #define IOCTL_CDROM_READ_TOC
             CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
          

Die Function CTL_CODE ist zum Beispiel bei OSR Online erläutert. Die Konstanten finden sich in der Ntddcdrm.h und der devioctl.h (Zum Beispiel hier).

 
  #define IOCTL_CDROM_BASE          FILE_DEVICE_CD_ROM
 
  #define FILE_DEVICE_CD_ROM        0x00000002
 
  #define FILE_READ_ACCESS          ( 0x0001 )
 
  #define METHOD_BUFFERED           0
          

Daraus ergibt sich dann in Delphi folgendes:

 
  const
    FILE_DEVICE_CD_ROM = $00000002;
    IOCTL_CDROM_BASE   = FILE_DEVICE_CD_ROM;
    FILE_READ_ACCESS   = $0001;
    METHOD_BUFFERED    = 0;
 
  const
    IOCTL_CDROM_READ_TOC = (IOCTL_CDROM_BASE shl 16) or
                           (FILE_READ_ACCESS shl 14) or
                           ($0000 shl 2) or
                           METHOD_BUFFERED;
          
 

Antwortstruktur

Als Antwort erhält man eine CDROM_TOC Struktur, welche die TRACK_DATA Struktur enthält:

 
  typedef struct _CDROM_TOC {
    UCHAR      Length[2];
    UCHAR      FirstTrack;
    UCHAR      LastTrack;
    TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
  } CDROM_TOC, *PCDROM_TOC;
 
  typedef struct _TRACK_DATA {
    UCHAR Reserved;
    UCHAR Control  :4;
    UCHAR Adr  :4;
    UCHAR TrackNumber;
    UCHAR Reserved1;
    UCHAR Address[4];
  } TRACK_DATA, *PTRACK_DATA;
          

Die Constante MAXIMUM_NUMBER_TRACKS findet sich in der ntddcdrm.h:

 
  #define MAXIMUM_NUMBER_TRACKS 100
          

Daraus ergibt sich eine ähnliche Struktur wie bereits in Table of Content (MMC). Sie unterscheidet sich darin, dass hier die Trackdata in einem statischen Array enthalten sowie Control und Adr als Halbbytes definiert sind, was es in Delphi nicht gibt. In Delphi ergibt sich:

 
  const
    MAXIMUM_NUMBER_TRACKS = 100;
 
  type
    TAddress = Array[0..3] of Byte;
 
  type
    TTRACK_DATA = record
      Reserved        : Byte;
      Adr_and_Control : Byte;
      TrackNumber     : Byte;
      Reserved1       : Byte;
      Address         : TAddress;
    end;
    PTRACK_DATA = ^TTRACK_DATA;
 
  type
    TCDROM_TOC = record
      Length     : Word;
      FirstTrack : Byte;
      LastTrack  : Byte;
      TrackData  : Array[1..MAXIMUM_NUMBER_TRACKS] of TTRACK_DATA;
    end;
    PCDROM_TOC = ^TCDROM_TOC;
          

Erläuterungen zu den Werten der Variablen findet man bei MSDN nicht. Da die Werte die selben sind wie bei der Verwendung der MMC sollten sie auch die selbe Bedeutung besitzen.

 

Ausführung

Die Ausführung reduziert sich auf:

         
  function TOptDrives.ReadTOCIOCTL(aDevice: THandle): Boolean;
  {*******************************************************************************
  *  Die Table of Contents mit den IOCTL ermitteln.
  }
  var
    nDescCount : Integer;
    nReturned  : Cardinal;
    i          : Integer;
  begin
    Result := False;
    {
    *  TOC initialisieren.
    }
    FillChar(FDrive[FActive].CDROM_TOC, SizeOf(FDrive[FActive].CDROM_TOC), $00);
    {
    *  Befehl ausführen.
    }
    Result := DeviceIoControl(aDevice,
                              IOCTL_CDROM_READ_TOC,
                              nil,
                              0,
                              @FDrive[FActive].CDROM_TOC,
                              SizeOf(FDrive[FActive].CDROM_TOC),
                              nReturned, nil);
    {
    *  Word drehen.
    }
    FDrive[FActive].CDROM_TOC.Length := Swap(FDrive[FActive].CDROM_TOC.Length);
  end;
          

Der Datentyp Word scheint in C und Delphi etwas unterschiedlich zu sein. Deshalb muss man die Bytes der Länge tauschen, da $1200 (4608) nicht das selbe ist wie $0012 (18).

Im Gegensatz zu Table of Content (MMC) führt die Ausführung von DeviceIoControl hier zu einem Fehler "Das Gerät ist nicht bereit" wenn kein Datenträger eingelegt ist.

 

Demo, welche diese Funktion nutzt:

Table of Contents (IOCTL) (podTableOfContentsIOCTL.7z - 309 kb) MD5 (1 kb). Stand: 10. Juni 2012

Änderungen an der Demo

Datum Beschreibung
18.07.2013Kleine Überarbeitung und neuer Name.
10.06.2012Fehler: Index bei Anzeige der Tracks korrigiert.
26.02.2012Aktualisiert: Groupbox "Optische Laufwerke".