Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi VTOC/Inhaltsverzeichnis einer CD/DVD auslesen (https://www.delphipraxis.net/141666-vtoc-inhaltsverzeichnis-einer-cd-dvd-auslesen.html)

Dalai 13. Okt 2009 17:22


VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Hallo ihr Wissenden :),

ich möchte auf möglichst einfache Weise den VTOC (Volume Descriptor) einer CD/DVD auslesen. Konkret geht's mir dabei um PublisherID, PreparerID, ApplicationID und vor allem CreationDate bzw. ModificationDate.

Gibt's irgendwo eine (kostenlos verwendbare) Bibliothek, die sowas ermöglicht? Oder muss man sogar auf ASPI/SPTI zurückgreifen und wenn ja, wonach müsste ich suchen?

Ich hab sowas bereits vor 3 Jahren für DOS programmiert, aber Windows ist eben doch ein bisschen anders ;). Achso: bitte ohne .NET-Abhängigkeiten, denn das muss auch auf einem nackigen Windows 2000/XP laufen.

Ich danke schonmal im Voraus für Ideen, Anregungen usw.

MfG Dalai

marabu 13. Okt 2009 20:58

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Hallo Dalai,

die gesuchten Informationen solltest Du teilweise mittels DeviceIoControl() und dem Control Code IOCTL_CHANGER_GET_PRODUCT_DATA erhalten.
Mit den Anwendungsbeispielen hier im Forum und der
offiziellen Dokumentation solltest Du zumindest einen Schritt weiter kommen.

Grüße vom marabu

Dalai 13. Okt 2009 21:47

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Das hilft mir leider überhaupt nicht weiter. CHANGER_PRODUCT_DATA enthält Infos über Laufwerke (Vendor, ProductID, SerialNumber usw) und nicht über das Medium, was im Laufwerk liegt. Die Infos über das Laufwerk sind zwar auch ganz schick, aber ich brauche die über's Medium.

Um's evtl. einfacher, in jedem Fall anders, zu schreiben: ich will einen ISO9660-Header bzw. Volume Descriptor auslesen und ausgeben/auswerten. Die im OP genannten Dinge sind Attribute desselben, und zwar die, die für mich in diesem Fall wichtig sind.
Meinetwegen kann das Auslesen auch über Joliet erfolgen, so die Infos dort verfügbar sind. Der Weg ist mir ziemlich egal, das Ergebnis ist wichtig.

MfG Dalai

Sir Rufo 13. Okt 2009 21:52

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Hilft das hier vielleicht?

http://ostatic.org/freeburner

Hab es nicht getestet, aber wenn die Lib brennen kann, dann vielleicht ... ?

cu

Oliver

Hobby-Programmierer 13. Okt 2009 22:26

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Schau mal unter Torry. Da gibts einige Componenten auch mit Quellcode. Vielleicht lässt sich daraus ja was machen.

marabu 14. Okt 2009 08:19

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Moin,

Zitat:

Zitat von Dalai
... Oder muss man sogar auf ASPI/SPTI zurückgreifen und wenn ja, wonach müsste ich suchen? ...

das scheint mir sogar eine Vereinfachung zu sein, nachdem ich mich etwas eingelesen habe. Und alles deutet auf den bereits von Oliver in Beitrag #4 verlinkten FreeBurner als Referenz hin.

Freundliche Grüße

Dalai 14. Okt 2009 14:10

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Ja, über das FreeBurner bin ich im Vorfeld des Themas auch gestoßen, war aber bisher nicht in der Lage, die nötigen Funktionen zu identifizieren, die auf das Medium zugreifen und die gewünschten Infos auslesen.

Die ISO9660PrimaryVolClass.pas hab ich mir angeschaut, aber das sind ja nur Deklarationen - die hätte ich im Zweifel auch selbst hinbekommen. Das ist im Moment eben mein Problem: ich weiß nicht, wie ich auf das Laufwerk bzw. dessen Medium zugreifen kann, um das OS oder die Schnittstelle oder das Laufwerk anzuweisen, bestimmte Bereiche zu lesen.

Ich werd mir die anderen Libs von FreeBurner mal anschauen und melde mich wieder. Das isoinfo aus den cdrtools scheint auch ganz vielversprechend zu sein.

MfG Dalai

Garfield 14. Okt 2009 15:17

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Am besten liest Du den Sektor 16 der CD/DVD aus. http://www.cdroller.com/htm/technol.html

Ergänzung:

Volume and File Structure of CDROM for Information Interchange

CD/DVD Diagnostic

Dalai 15. Okt 2009 16:45

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Sodele,

der Hinweis von Hobby-Programmierer war gut, denn dadurch bin ich auf die APSI-Lib gekommen, die ein Testprojekt enthält, mit dem man beliebige Sektoren einer CD/DVD auslesen kann. Davon hab ich mir abgeschaut, welche Funktion man verwenden kann/muss, um das Gewünschte zu erreichen.

Da die ASPI-Lib aber einige Nachteile hat (abhängig von installiertem ASPI, kein Auslesen der Laufwerksinfos, also Hersteller, Modell usw.), habe ich dann doch die FreeBurner-Lib genommen. Danke an Sir Rufo an dieser Stelle für den passenden Hinweis darauf.

Nach einer Einbindungsorgie mit derselben habe ich dann endlich erreicht, was ich will - siehe Bild im Anhang. Ich habe noch nie so viele Units eingebunden wie bei diesem Projekt - insgesamt 19 Units allein aus der FreeBurner-Lib. Einige davon habe ich angepasst und die Einbindung von CDDB-Kram usw. rausgeschmissen, damit das nicht ausartet.

Was habe ich benutzt? Recht einfach:
Delphi-Quellcode:
uses [...], Devices, ScsiTypes, CovertFuncs;

type
  TMainForm = class(TForm)
    DriveCombo: TComboBox;
    ResultMemo: TMemo;
    ReadBtn: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ReadBtnClick(Sender: TObject);
  private
    fDrives: TDevices;
end;

//------------------------------------------------

procedure TMainForm.FormCreate(Sender: TObject);
begin
    fDrives:= TDevices.Create;
end;

//------------------------------------------------

procedure TMainForm.FormDestroy(Sender: TObject);
begin
    if Assigned(fDrives) then
        FreeAndNil(fDrives);
end;

//------------------------------------------------

procedure TMainForm.FormShow(Sender: TObject);
var i : integer;
begin
    for i:= 0 to Pred(fDrives.Count) do
        with fDrives.Items[i].DeviceInfo do
            DriveCombo.Items.Add(Format('%d,%d,%d %s %s (%s)',
                                        [HaId, Target, Lun, DriveName, VendorName, Revision]));
    if DriveCombo.Items.Count > 0 then
        DriveCombo.ItemIndex:= 0;
end;

//------------------------------------------------

procedure TMainForm.ReadBtnClick(Sender: TObject);
const
    BufLen = 2048;
var Buf   : Pointer;
    s     : string;
    c     : char;
    i     : DWORD;
    liste : TStringList;
begin
    Buf:= nil;
    ReallocMem(Buf, BufLen);
    try
        if fDrives.Items[DriveCombo.ItemIndex].DeviceReader.ReadData(16, 1, Buf, BufLen) then
        begin
            for i:=0 to BufLen do
            begin
                c:= (PChar(Buf) + i)^;
                (*if c < ' ' then
                    c := ' ';*)
                s:= s + c;
            end;
            liste:= TStringList.Create;
            HexStrToPVD(s, liste);
            ResultMemo.Lines.Assign(liste);
            liste.Free;
        end;
    finally
      ReallocMem(Buf, 0);
    end;
end;
Beim Start wird ein Objekt fDrives erzeugt, das die (optischen) Laufwerke des Rechners enthält, inkl. Infos zu Modell, Hersteller, Firmware usw. Beim Klick auf den Button wird mit der Funktion ReadData der Sektor 16 des Mediums ausgelesen und dann in einen String kopiert.

Um die Daten übersichtlich darzustellen, benutze ich die Funktion HexStrToPVD, die ich aus Längengründen mal weggelassen habe; dort passiert im Prinzip nichts weiter, als die Felder an den Indizes in eine StringListe zu kopieren, damit das Memo sie aufnehmen kann.

Das Ganze läuft auch ohne installiertes ASPI, zumindest auf Win2k und höher, was aber nicht weiter schlimm ist, denn wen interessiert schon Win9x noch? 8)

Was bleibt noch zu tun? Die Umrechnung der numerischen Felder fehlt noch, wie man auch leicht am Screenshot sieht ;). Und eine übersichtlichere Darstellung in Tabellenform steht auch noch an, aber das dürfte beides machbar sein - falls nicht, werde ich das Forum nochmals nerven :mrgreen:.

MfG Dalai

Garfield 15. Okt 2009 18:52

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
19 Units sind viel. Die Infos zu den CD/DVDs kann man auch so holen:

Delphi-Quellcode:
function TForm1.ReadDrives: Integer;
{******************************************************************************}
{** Laufwerke holen:                                                        **}
{**   DriveLetter, HaID, Target, LUN, Identfier und DeviveName.             **}
{******************************************************************************}
const
  Root2k = '';
  Root98 = 'Enum\Scsi\';
var
  Reg      : TRegistry;
  Root     : String;
  RegKey   : String;
  OSInfo   : TOSVersionInfo;
  szDrives : array[0..105] of Char;
  hDevice  : THandle;
  buf      : array[0..1023] of Char;
  pDrive   : PChar;
  pscsiAddr : PSCSI_ADDRESS;
  returned : Integer;
Begin
  Result := 0;
  SetLength(FDrive, Result);

  OSInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
  GetVersionEx(OSInfo);

  ZeroMemory(@szDrives, 106);
  GetLogicalDriveStrings(105, szDrives);

  pDrive := szDrives;

  while pDrive^ <> '' do
  begin
    if GetDriveType(pDrive) = DRIVE_CDROM then
    begin
      ZeroMemory(@buf, 1024);
      pscsiAddr := PSCSI_ADDRESS(@buf);
      pscsiAddr^.Length := sizeof(TSCSI_ADDRESS);

      hDevice := CreateFile(PChar(Format('\\.\%s:', [pDrive[0]])),
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            nil,
                            OPEN_EXISTING,
                            0,
                            0 );

      if hDevice <> INVALID_HANDLE_VALUE then
      if DeviceIoControl(hDevice,
                         IOCTL_SCSI_GET_ADDRESS,
                         nil,
                         0,
                         pscsiAddr,
                         sizeof(TSCSI_ADDRESS),
                         Cardinal(returned),
                         nil)
      then begin
        SetLength(FDrive, Result + 1);
        FDrive[Result].HaId  := pscsiAddr^.PortNumber;
        FDrive[Result].Target := pscsiAddr^.TargetId;
        FDrive[Result].Lun   := pscsiAddr^.Lun;
        FDrive[Result].Letter := pDrive^;

        // Registry öffnen
        Reg        := TRegistry.Create;
        Reg.RootKey := HKEY_LOCAL_MACHINE;

        // OS abhängigen RootKey setzen
        if OSInfo.dwPlatformId = VER_PLATFORM_WIN32_NT
        then Root := Root2k
        else Root := Root98;

        RegKey := Format('%sHARDWARE\DEVICEMAP\Scsi\Scsi Port %d\Scsi Bus 0\Target Id %d\Logical Unit Id %d',
                         [Root, FDrive[Result].HaId, FDrive[Result].Target, FDrive[Result].Lun]);

        if Reg.KeyExists(RegKey)
        then begin
          if Reg.OpenKeyReadOnly(RegKey) then
          // Ist es ein CDRom?
          if Reg.ReadString('Type') = 'CdRomPeripheral'
          then begin
            // Name holen
            FDrive[Result].Identifier := Reg.ReadString('Identifier');
            // Device
            FDrive[Result].DeviceName := Reg.ReadString('DeviceName');
          end;
          // Schlüssel schliessen
          Reg.CloseKey;
        end;
        // Schlüssel schliessen
        Reg.CloseKey;
        // Registry schliessen
        Reg.Free;
        // anzahl erhöhen
        inc(Result);
      end;
      CloseHandle(hDevice);
    end;
    pDrive := pDrive + lstrlen( pDrive ) + 1;
  end;
end;
Das Ergebnis der function ist die Anzahl der CD/DVD-Laufwerke. FDrive ist folgender Record:

Delphi-Quellcode:
FDrive = Record
  HaId       : Byte;
  Target     : Byte;
  Lun        : Byte;
  Identifier : String;
  DeviceName : String;
  Letter     : Char;
end;
Dummerweie weiß ich nicht mehr, welche Quellen ich dafür benutzt habe.

Dalai 15. Okt 2009 19:39

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Zitat:

Zitat von Garfield
19 Units sind viel.

Das Problem war eben, dass die Units teilweise aufeinander verweisen und man nicht genau weiß, welche davon man nun genau braucht. Dennoch ist das kompilierte Programm nicht sonderlich groß (derzeit knapp 400 KB inkl. inzwischen eingebundenem ListView für die Tabelle), ein Großteil der Units wird demzufolge nicht wirklich gebraucht.

Zitat:

Zitat von Garfield
Die Infos zu den CD/DVDs kann man auch so holen:

So ähnlich macht das die FreeBurner-Lib auch. Da ich aber eh noch das Auslesen des Mediums brauche, hab ich eben die Units eingebunden. Bevor ich da noch welche rausschmeiße und risikiere, dass nichts mehr funktioniert, lass ich es lieber so.

MfG Dalai

Dalai 16. Okt 2009 00:19

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Ich muss erneut um eure Hilfe bitten, weil ich momentan einen Knoten im Hirn habe und nicht weiterkomme :?.

Ich hab das Programm etwas geändert, und zwar habe ich ein Record definiert, in dem die Daten ankommen:
Delphi-Quellcode:
var PVD : record
        VolDescType   : byte;
        StandardID    : array[2..6] of char;
        VolDescVer    : byte;
        X1             : byte;
        SystemID      : array[9..40] of char;
        VolID         : array[41..72] of char;
        X2             : array[73..80] of byte;
        VolSpaceSize  : array[81..88] of byte;
        X3             : array[89..120] of byte;
        VolSetSize    : array[121..124] of byte;
        VolSequNr     : array[125..128] of byte;
        LogBlockSize  : array[129..132] of byte;
        PathTableSize : array[133..140] of byte;
        TypeLPathTab  : array[141..144] of byte;
        OptTypeLPathTab: array[145..148] of byte;
        TypeMPathTab  : array[149..152] of byte;
        OptTypeMPathTab: array[153..156] of byte;
        DirRecordRoot : array[157..190] of char;
        VolumeSetID   : array[191..318] of char;
        PublisherID   : array[319..446] of char;
        DataPrepID    : array[447..574] of char;
        AppID         : array[575..702] of char;
        CopyFileID    : array[703..739] of char;
        AbstractFileID : array[740..776] of char;
        BibFileID     : array[777..813] of char;
        VolCreation   : array[814..830] of char;
        VolModDate    : array[831..847] of char;
        VolExpirDate  : array[848..864] of char;
        VolEffectDate : array[865..881] of char;
        FilStructVer  : byte;
        X4             : byte;
        AppUse        : array[884..1395] of char;
        X5             : array[1396..2048] of byte;
      end;
Um die Daten dann von dem Pointer Buf auf das Record zu übertragen, habe ich die Methode ReadBtnClick so abgeändert:
Delphi-Quellcode:
if fDrives.Items[DriveCombo.ItemIndex].DeviceReader.ReadData(16, 1, Buf, BufLen) then
begin
     Move(Buf^, PVD, SizeOf(PVD));
end;
Das landet auch alles schön in dem Record. Nur habe ich Schwierigkeiten, die numerischen Felder richtig zu verarbeiten. Konkret geht's mir um die Felder Volume Space Size, Volume Set Size usw. Laut Spec sind diese Felder als Both-byte orders geschrieben:
Zitat:

For example, the decimal number 305419896 has (12 34 56 78 ) as its hexadecimal representation and is recorded as (78 56 34 12 12 34 56 78 ).
Hat jemand eine gute Idee, wie ich das auf einfachem (und verständlichem ;)) Weg in einen Integer umrechnen kann? In meinem DOS-Programm damals habe ich das ebenfalls mit einem Record gemacht, aber da wurden nur die String-Felder weiterverarbeitet (die numerischen wurden nicht benötigt).

MfG Dalai

Klaus01 16. Okt 2009 08:51

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Guten Morgen,

vielleicht kannst Du mit variant records arbeiten.

Delphi-Quellcode:
type
  TVolSpaceSize = record
    case boolean of
      true: array[0..7] of Byte;
      false: Int64;
  end;
Delphi-Quellcode:
//VolSpaceSize  : array[81..88] of byte;
VoldSpaceSize : TVolSpaceSize;
aber vielleicht gibt es noch eine etwas bessere praktikabelere Lösung.

[edit]
alternativ:
Delphi-Quellcode:
VolSpaceSize  : array[81..88] of byte;
VolSpaceSizeValue: Int64;
..
VolSpaceSizeValue := int64(VolSpaceSize);
Grüße
Klaus

p80286 16. Okt 2009 13:02

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
@Klaus

Ich denke so wäre es besser:

Delphi-Quellcode:
Tvalue : record
    wert : Longint;
    dummy: array [0..3] of byte;
end;
Da der Wert einmal in "intel-Notation" und einmal in "MotorolaNotation" abgelegt wird.

Gruß
K-H

Dalai 16. Okt 2009 14:16

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Ja, da haut's mich doch vom Stuhl! Ich hatte gestern schon mit Cardinal-Typen statt des array of byte rumgespielt und es hat nicht funktioniert. Lag wohl daran, dass ich die letzten 4 Bytes genommen hatte statt der ersten 4...

"Kaum macht man's richtig, schon funktioniert's" - wie passend die Signatur ist :-D.

Dankeschön an p80286 und Klaus01!

MfG Dalai

Muetze1 16. Okt 2009 14:27

Re: VTOC/Inhaltsverzeichnis einer CD/DVD auslesen
 
Neben den Strukturen hatte ich damals in dem isolib Projekt auch explizite Funktionen zum Umwandeln der Integer bezüglich der Byte Order geschrieben. Diese hat dancemammal auch weiterhin in den Quellen nach der Übernahme der Quellen. Die kannst du nutzen um die Werte hin- und her zu wandeln. Ansonsten kann ich nur noch darauf hinweisen, dass nicht jedes Brennprogramm beide Felder ausfüllt (also mit beiden Byte Order) sondern meist nur eins von beiden. Von daher lohnt es sich immer vorher zu schauen welches Feld <> 0 ist und dann das entsprechende Feld zu nutzen und bei Bedarf zu wandeln.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:10 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz