Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi ISO-Image einer CDDA mit CreateFile und ReadFile möglich? (https://www.delphipraxis.net/80118-iso-image-einer-cdda-mit-createfile-und-readfile-moeglich.html)

Garfield 3. Nov 2006 08:14


ISO-Image einer CDDA mit CreateFile und ReadFile möglich?
 
Im Projekt von Bochs2Delphi gibt es eine Routine um von einer CD-ROM ein ISO-Image zu erstellen:

Delphi-Quellcode:
procedure TFormCreateIso.ripDrive(const driveRoot, fileIso: String);
const
  chunk_size = 4096 * 10;
var
  buffer:PChar;
  _fileHandle,bytesReaded,Written:LongWord;
  _totBytes:int64;
  _r:boolean;
  fp:file of byte;
begin
  cmrip.Enabled:=false;
  cmClose.Enabled:=false;
  cmStop.Enabled:=false;
  GetMem(buffer,chunk_size);
  _fileHandle:=CreateFile(PChar('\\.\' + driveRoot),GENERIC_READ,0,nil,OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN,0);
  bytesReaded:=chunk_size;
  _totBytes:=0;
  _r:=true;
  stopRun:=false;
  try
    if _fileHandle = INVALID_HANDLE_VALUE then
      begin
        raise Exception.Create('Errore opening: ' + '\\.\' + driveRoot);
        exit;
      end;
    AssignFile(fp,fileIso);
    Rewrite(fp);

    Written:=chunk_size;
    while (bytesReaded = chunk_size) and (_r) and (Written = chunk_size) and (not stopRun) do
      begin
        _r:=ReadFile(_fileHandle,buffer^,chunk_size,bytesReaded,nil);
        BlockWrite(fp,buffer^,chunk_size,Written);
        Inc(_totBytes,bytesReaded);
        if _totBytes mod (chunk_size * 10) = 0 then
          begin
            lblTot.Caption:=IntToStr(_totBytes);
            Application.ProcessMessages;
          end;
      end;
  finally
    CloseFile(fp);
    if _fileHandle <> INVALID_HANDLE_VALUE then
      CloseHandle(_fileHandle);
    if buffer <> nil then FreeMem(buffer);
    cmrip.Enabled:=True;
    cmClose.Enabled:=True;
    cmStop.Enabled:=True;
  end;
end;
Mit Mode1 CDs funktioniert es problemlos, bei Mode2 CDs (CDDA, VCD, SVCD) bekommt man zwar ein gültiges _FileHandle, jedoch ist beim ersten ReadFile Schluss, weil bytesReaded = 0 ist.

Gibt es eine Möglichkeit, dies anzupassen?

Nachtrag: Ich muss mich korrigieren. Bei einer SVCD wird der Datentrack inklusive Struktur gespeichert.

Garfield 4. Nov 2006 10:45

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Jetzt habe ich das gefunden:

http://www.codeproject.com/useritems/SimpleAudioCD.asp
http://www.insidepro.com/kk/020/020r.shtml

MuTzE 4. Nov 2006 11:37

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
http://isolib.xenome.info/

Garfield 4. Nov 2006 13:11

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Für CDDA dürfte es gehen. Bei CD Extra ging Dancemammals Freeburner nicht. Deshalb nehme ich an, dass er für VCD und SVCD auch nicht geht. Der Unterschied liegt ja nur in der Trackreihenfolge. Also CD Extra erst Audio und dann Daten, bei VCD und SVCD erst Daten und dann Video.

isolib_RevToMix.zip kenne ich noch nicht. Müsste man sehen, inwieweit der Freeburner Source übernommen wurde. Danke für den Hinweis.
__

Nachtrag: Beim Entpacken von http://isolib.xenome.info/releases/f...b_RevToMix.zip kommt eine Passwortabfrage. Und das bei Gnu LGPL. :gruebel:

Muetze1 4. Nov 2006 13:59

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Da es eine interne Revision war, welche zusammen gemixt wurde.

Garfield 4. Nov 2006 15:07

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Da die TIsoLib für meine Zwecke wahrscheinlich nicht das richtige ist, habe ich mir den FreeBurner 1.0.0.2 angesehen. Möglicherweise hat Dancemammal die TIsoLib erweitert?

Beim Test Project waren einige Units manuell einzufügen. Vermutlich weil ich die ISO9660-Komponente nicht installiert habe. Dann mussten noch ein paar Uint16 und Uint32 in Word und DWord geändert werden, damit Turbo Delphi das Projekt kompilierte.

Die TOC von CDDA und SVCD(2 Daten und ein Video Track) wurden eingelesen. Ein ISO-Image konnte nicht erstellt werden. Leider Ziel nicht erreicht.

Muetze1 4. Nov 2006 15:34

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Zitat:

Zitat von Garfield
Möglicherweise hat Dancemammal die TIsoLib erweitert?

Ja, hat er. Er hat die ISOLib als Grundlage genommen und dann erweitert.

Garfield 4. Nov 2006 15:53

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Leider nicht in die Richtung, welche ich brauche.

Garfield 24. Nov 2006 19:12

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Ich habe mir den Freeburner noch einmal angesehen und versucht mit der Testapplication Images von CDs zu ziehen. Die AudioCDs waren leer und beim Zugriff auf DatenCDs fror das System (Win2000) ein.

Ich habe es mit dieser Function versucht:

Delphi-Quellcode:
 // Sektoren lesen
//==============================================================================
function ReadCDAudioSector(cdHandle: THandle; Startsektor, Sektorlesen : Integer;
                      var Data : TRawData; var Fehler : String) : Boolean;
var
  RawReadInfo : RAW_READ_INFO;
  nb         : Cardinal;
begin
  Result := False;

  RawReadInfo.DiskOffset.QuadPart := Startsektor * CB_CDROMSECTOR;
  RawReadInfo.TrackMode          := CDDA;
  RawReadInfo.SectorCount        := Sektorlesen;

  nb := 0;

  if cdHandle <> INVALID_HANDLE_VALUE then
  Result := DeviceIoControl(cdHandle,
                            IOCTL_CDROM_RAW_READ,
                            @RawReadInfo,
                            SizeOf(RawReadInfo),
                            @Data,
                            Sektorlesen * CB_AUDIO,
                            nb,
                            nil);
  Fehler := GetLastErrorMsg;
end;
Dabei habe ich das CDHandle mit der Funktion geholt:

Delphi-Quellcode:
function GetDriveHandle(cDrive: Char): THandle;
begin
  Result := CreateFile(PChar('\\.\'+cDrive+':'),
                       GENERIC_READ or GENERIC_WRITE,
                       FILE_SHARE_READ or FILE_SHARE_WRITE,
                       nil,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL,
                       0);
end;
Beim Befehl DeviceIOControl erhalte ich immer die Meldung: "Ungültiger Parameter".

Anschliessend habe ich das ausprobiert:

Delphi-Quellcode:
function READ_RAW_SECTOR_FROM_CD(    hCD         : THandle;
                                     HTL         : String;
                                 var Data        : Array of Byte;
                                     StartSector : DWord;
                                     AnzahlSector : DWord;
                                     flags       : Byte)
                                 : Boolean;
const
  RAW_READ_CMD                   = $BE; // ATAPI RAW READ
  PACKET_LEN                     = 2352; // Sektorlänge
  SCSI_IOCTL_DATA_IN             = 1;
  IOCTL_SCSI_PASS_THROUGH        = $04D004;
var
  srb : SCSI_PASS_THROUGH_DIRECT;
  nb : Cardinal;
Begin
  Result := False;
  ZeroMemory(@srb, SizeOf(srb));
  ZeroMemory(@Data, SizeOf(Data));

  if hCD <> INVALID_HANDLE_VALUE
  then begin
    srb.Length            := sizeof(SCSI_PASS_THROUGH);
    srb.PathId            := StrToInt(HTL[1]); // SCSI controller ID
    srb.TargetId          := StrToInt(HTL[3]); // target device ID
    srb.Lun               := StrToInt(HTL[5]); // logical unit device ID
    srb.CdbLength         := 12;
    srb.SenseInfoLength   := 0; // SenseInfo
    srb.DataIn            := SCSI_IOCTL_DATA_IN;
    srb.DataTransferLength := PACKET_LEN * AnzahlSector;
    srb.TimeOutValue      := 200; // TimeOut
    srb.DataBuffer        := @Data;
    srb.SenseInfoOffset   := 0; // SenseInfo

    // CDB
    srb.Cdb[0]            := RAW_READ_CMD;
    srb.Cdb[1]            := $0; // Format Disk
    srb.Cdb[2]            := HIBYTE(HIWORD(StartSector));
    srb.Cdb[3]            := LOBYTE(HIWORD(StartSector));
    srb.Cdb[4]            := HIBYTE(LOWORD(StartSector));
    srb.Cdb[5]            := LOBYTE(LOWORD(StartSector));
    srb.Cdb[6]            := LOBYTE(HIWORD(AnzahlSector));
    srb.Cdb[7]            := LOBYTE(LOWORD(AnzahlSector));
    srb.Cdb[8]            := HIBYTE(LOWORD(AnzahlSector));
    srb.Cdb[9]            := flags;
    srb.Cdb[10]           := 0; // Sub-Channel Data Bits
    srb.Cdb[11]           := 0; // reserved

    Result := DeviceIoControl(hCD,
                              IOCTL_SCSI_PASS_THROUGH,
                              @srb,
                              sizeof(srb),
                              @srb,
                              0,
                              nb,
                              Nil);
  end;
end;
Hier friert das Programm beim DeviceIOControl ein.

Beide Sourcen habe ich als C im Internet gefunden.

himitsu 1. Dez 2006 16:45

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Was passiert wohl, wenn du versuchst eine schreibgeschützte CD mit Schreibrechten zu öffnen :?:
Zitat:

Zitat von #9
Result := CreateFile(PChar('\\.\'+cDrive+':'),
GENERIC_READ or GENERIC_WRITE,


Zum ersten Code (#1):

Zitat:

Zitat von #9
chunk_size = 4096 * 10;

Mal nachgesehen, ob die Sektoren wirklich 4096 Byte groß sind?
Vielleicht nochmals mit einer passenden Größe versuchen
und eventuell ohne FileCache (FILE_FLAG_NO_BUFFERING).


FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN ... hier könnte man es mal ohne FILE_ATTRIBUTE_NORMAL testen ... :zwinker:
Zitat:

Zitat von MSDN
FILE_ATTRIBUTE_NORMAL

The file has no other attributes set. This attribute is valid only if used alone.

... wer weiß was Windows in so'nem Fall (nicht) macht?


[add]
ansonsten etwas warten ... demnächst werde ich mich "leider" auch mal wieder mit sowas (Datenträger direkt auslesen) befassen müssen -.-''

OldGrumpy 1. Dez 2006 21:27

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Beim Lesen von Blockdevices muss die Leseposition eine Blockgrenze (bzw. der Anfang eines Blocks) sein, mittendrin anfangen zu lesen klappt nicht. Und weil in deiner Funktion oben (function ReadCDAudioSector) am Anfang mit CB_CDROMSECTOR gearbeitet wird, vermute ich mal dass da mit 2048 statt 2352 bzw. 2336 (je nach Trackmode) gerechnet wird - Der Lesezugriff schlägt dann auf die eine oder andere Art fehl. Beim direkten Lesen von USB-Devices muss darüber hinaus noch der Puffer im Speicher auf Speicherseiten aligned sein, so einen passend plazierten Puffer erhaelt man mittels VirtualAlloc. Ich hatte vor geraumer Zeit auch mal mit diesen Sourcen rumgespielt, dann aber irgendwann keine Zeit mehr gehabt, alles hinzubiegen.

himitsu 2. Dez 2006 11:22

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Zitat:

Zitat von OldGrumpy
Beim direkten Lesen von USB-Devices muss darüber hinaus noch der Puffer im Speicher auf Speicherseiten aligned sein, so einen passend plazierten Puffer erhaelt man mittels VirtualAlloc. Ich hatte vor geraumer Zeit auch mal mit diesen Sourcen rumgespielt, dann aber irgendwann keine Zeit mehr gehabt, alles hinzubiegen.

Dem ist ganz nicht so, daß kann ich dir inzwischen bestätigen ... jedenfalls nicht in "aktuellen" Systemen wie XP und 2000.

Laut Muetze1 (ich hoffe er war es) könnte das daran liegen, daß zum Auslesen der Speicher in 'nem bestimmten Bereich ganz weit vorn im RAM liegen muß und demnach Windows wohl über 'nen eigenen Zwischenspeicher geht und dann die Daten erst und deinen Speicher rüberkopiert werden, wobei dort egal ist wo dieser Speicher rumliegt.
Oder so in etwa ... jedenfalls geht es bei mir auch so, ohne aligned Speicher ... ist schon praktisch, wenn man da z.B. auch einfach etwas aus'm Stack nutzen kann und sich die Resourcenschutzblöcke, samt Speicherreservierung/-freigabe spart. :angel:

Aber Schaden kann es ja nie :roll:

Muetze1 2. Dez 2006 11:41

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Zitat:

Zitat von himitsu
Zitat:

Zitat von OldGrumpy
Beim direkten Lesen von USB-Devices muss darüber hinaus noch der Puffer im Speicher auf Speicherseiten aligned sein, so einen passend plazierten Puffer erhaelt man mittels VirtualAlloc. Ich hatte vor geraumer Zeit auch mal mit diesen Sourcen rumgespielt, dann aber irgendwann keine Zeit mehr gehabt, alles hinzubiegen.

Dem ist ganz nicht so, daß kann ich dir inzwischen bestätigen ... jedenfalls nicht in "aktuellen" Systemen wie XP und 2000.

Laut Muetze1 (ich hoffe er war es) könnte das daran liegen, daß zum Auslesen der Speicher in 'nem bestimmten Bereich ganz weit vorn im RAM liegen muß und demnach Windows wohl über 'nen eigenen Zwischenspeicher geht und dann die Daten erst und deinen Speicher rüberkopiert werden, wobei dort egal ist wo dieser Speicher rumliegt.
Oder so in etwa ... jedenfalls geht es bei mir auch so, ohne aligned Speicher ... ist schon praktisch, wenn man da z.B. auch einfach etwas aus'm Stack nutzen kann und sich die Resourcenschutzblöcke, samt Speicherreservierung/-freigabe spart. :angel:

Meine Aussage bezog auf den DMA Transfer, wobei der DMA Baustein keine "grossen" Adressen abkann und nur im unteren 1 MB arbeitet. Daher muss bei der DMA Übertragung der Speicher dort unten liegen. Unter Windows sorgt die WinAPI dafür und kopiert von diesem weiter - und dabei kommt dann kein DMA mehr zum Einsatz und die Adressen können auch "quer" liegen - dieses macht nur wieder den Zugriff der CPU langsamer durch die extra-cyclen die die CPU beim Data-fetch drehen muss...

Virtualisierungen im Sinne des V86 und Protected Modes gelten für die CPU und den Dingen die darauf ablaufen, der DMA Controller hängt aber ausserhalb der CPU im System und kümmert sich soweit selbstständig um die Datenübertragung kann nur mit physikalischen Adressen - und sein Register ist für diese beschränkt.

OldGrumpy 2. Dez 2006 18:11

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Zitat:

Zitat von himitsu
Zitat:

Zitat von OldGrumpy
Beim direkten Lesen von USB-Devices muss darüber hinaus noch der Puffer im Speicher auf Speicherseiten aligned sein, so einen passend plazierten Puffer erhaelt man mittels VirtualAlloc. Ich hatte vor geraumer Zeit auch mal mit diesen Sourcen rumgespielt, dann aber irgendwann keine Zeit mehr gehabt, alles hinzubiegen.

Dem ist ganz nicht so, daß kann ich dir inzwischen bestätigen ... jedenfalls nicht in "aktuellen" Systemen wie XP und 2000.

Sicher? Ich hatte nämlich vor gar nicht mal so langer Zeit genau so einen Fall: Memorycard im USB-Cardreader als physical device zum Lesen geöffnet. Lesen klappte auch super, nur stand im Puffer jede Menge Unsinn drin. Nach langem googlen hatte ich dann in der MSDN einen entsprechenden Hinweis gefunden. Nach Anlegen des Puffers mit VirtualAlloc funktionierte das Lesen dann einwandfrei...

Ich schau mal ob ich die Seite in der MSDN wiederfinde.

Edit: Hier isses: [msdn]http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/readfile.asp[/msdn]

Allerdings hatte ich es etwas anders in Erinnerung, der Puffer muss sector-aligned sein. Da die Pagegröße praktisch immer ein Vielfaches der Sektorgröße ist, erfüllt das Alignment auf Pages den gleichen Zweck :)
Zitat:

Zitat von MSDN
File access must begin at byte offsets within the file that are integer multiples of the volume sector size. To determine the sector size of a volume, call the GetDiskFreeSpace function.
File access must be for numbers of bytes that are integer multiples of the volume sector size. For example, if the sector size is 512 bytes, an application can request read and write operations of 512, 1024, 1536, or 2048 bytes, but not of 335, 981, or 7171 bytes.
Buffer addresses for read and write operations must be sector aligned (that is, aligned on addresses in memory that are integer multiples of the volume sector size).
One way to sector align buffers is to use the VirtualAlloc function to allocate the buffers. This function allocates memory that is aligned on addresses that are integer multiples of the system page size. Because both page and volume sector sizes are powers of 2 (two), memory aligned by multiples of the system page size is also aligned by multiples of the volume sector size.


himitsu 4. Dez 2006 16:32

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
@Muetze1: OK, wenn man dat so sieht, dann könnte es hinkommen :wall:

Zitat:

Zitat von OldGrumpy
Sicher? Ich hatte nämlich vor gar nicht mal so langer Zeit genau so einen Fall: Memorycard im USB-Cardreader als physical device zum Lesen geöffnet. Lesen klappte auch super, nur stand im Puffer jede Menge Unsinn drin.

Jo, denn ich hatte es erst selber nur über nicht ausgerichteten Speicher gemacht und dann meinte Muetze1 der Speicher müsse ausgerichtet werden ... aber es ging/geht auch so. ^^

Bei ReadFile/WriteFile und beim DMA-Trasfer ... was an Daten drin stand war eigentlich ganz OK :angel:

OldGrumpy 4. Dez 2006 16:56

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Vielleicht hattest Du einfach nur Glück und Deine Puffer waren zufällig halt entsprechend aligned :) Zumindest unter W2K (hab es später nicht mehr auf XP getestet, da ich es für sinnvoller hielt, eine Lösung zu implementieren die unter beiden Systemen funktioniert...) gehts mit krummen Werten definitiv nicht gut. Von mir aus kann ich gerne mal den Source rauswühlen und Samples posten :)

Garfield 23. Dez 2006 21:19

Re: ISO-Image einer CDDA mit CreateFile und ReadFile möglic
 
Entschuldigung für die späte Antwort. Ich war ein paar Wochen auf Montage und hatte keinen Internetzugang.

Zitat:

Zitat von himitsu
Was passiert wohl, wenn du versuchst eine schreibgeschützte CD mit Schreibrechten zu öffnen :?:

Meiner Ansicht nach wird nicht die schreibgeschützte CD sondern das Gerät geöffnet. Falls der Benutzer keine Schreibrechte bzw in diesem Fall keine Brennrechte besitzt, erhält er auch kein gültiges Handle. Des weiteren sind für einige Funktionen wie im vorliegenden Fall Schreibrechte erforderlich. Deshalb arbeitet zum Beispiel VCDEasy mit SPTI nur unter Administratorkonten.

Zitat:

Zitat von himitsu
Mal nachgesehen, ob die Sektoren wirklich 4096 Byte groß sind?

Diese Größe bezieht sich auf die Nutzdaten von zwei Datensektoren. Ist aber eher unwichtig, weil der Source funktioniert.

FILE_FLAG_NO_BUFFERING werde ich mal versuchen,

Zitat:

Zitat von OldGrumpy
... Und weil in deiner Funktion oben (function ReadCDAudioSector) am Anfang mit CB_CDROMSECTOR gearbeitet wird, vermute ich mal dass da mit 2048 statt 2352 bzw. 2336 (je nach Trackmode) gerechnet wird - Der Lesezugriff schlägt dann auf die eine oder andere Art fehl.

Die Sektoren sind auf jeder CD gleich groß und unterscheiden sich lediglich im Aufbau. 2048, 2352 und 2336 sind dabei jeweils die Größe der Nutzdaten. AudioCD zum Beispiel: http://de.wikipedia.org/wiki/Audio-CD

In allen Sourcen, welche ich fand, wurde bei der Positionierung mit der Größe der Nutzdaten von Datensektoren gerechnet. Anschließend wird der Typ des Sektors eingestellt und die tatsächliche Größe der Nutzdaten gelesen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:56 Uhr.

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