Projekte > Optische Laufwerke > Laufwerke

Bezeichnungen

Mit der Funktion CreateFile erhält man ein Handle auf das Laufwerk. Dazu kann das Laufwerk mit dem Device Namespace oder dem File Namespace angegeben werden. Anschließend greift man sich mit der Funktion DeviceIOControl und dem ControlCode IOCTL_SCSI_PASS_THROUGH_DIRECT auf das SCSI Pass Through Interface zu erhält mit dem INQUIRY Command die Bezeichnung des Laufwerkes. Nähere Informationen zu dem Multi Media Command gibt es unter ..................

Deklarationen:

const
  SCSIOP_INQUIRY = $12;
 
type
  TSCSI_INQUIRY_CDB = record
    OperationCode    : Byte;
    EVPD             : Byte;
    PageCode         : Byte;
    AllocationLength : Word;
    Control          : Byte;
  end;
 
type
  TINQUIRY_STANDARD_DATA = record
    Other_Informations_1    : Array[0..7] of Byte;
    T10VendorIdentification : array[0..7] of Char;
    ProductIdentification   : array[0..15] of Char;
    ProductRevisionLevel    : array[0..3] of Char;
    VendorSpecific0         : array[0..19] of Char;
    Other_Informations_2    : Array[0..43] of Byte;
  end;

Die im Moment nicht benötigten Informationen werden hier mit Other_Informations_1 und Other_Information_2 bezeichnet.

Die Ausführung könnte beispielsweise so aussehen:

function TOptDrives.ReadInquiry(aDevice: THandle): Boolean;
{*******************************************************************************
*  Inquiry Command
}
var
  SCSI_INQUIRY_CDB : TSCSI_INQUIRY_CDB;
  pInquiryData     : pINQUIRY_STANDARD_DATA;
  aCDB             : Array of Byte;
  i                : Integer;
begin
  {
  *  Das übergebene Handle auf Gültigkeit prüfen.
  }
  if aDevice <> INVALID_HANDLE_VALUE
  then begin
    {
    *  Den Command Descriptor Block füllen.
    }
    ZeroMemory(@SCSI_INQUIRY_CDB, SizeOf(SCSI_INQUIRY_CDB));
    SCSI_INQUIRY_CDB.OperationCode    := SCSIOP_INQUIRY;
    SCSI_INQUIRY_CDB.AllocationLength := SizeOf(TINQUIRY_STANDARD_DATA);
    {
    *  Den Command Descriptor Block übertragen.
    }
    SetLength(aCDB, 6);
    aCDB[0] := SCSI_INQUIRY_CDB.OperationCode;
    aCDB[1] := SCSI_INQUIRY_CDB.EVPD;
    aCDB[2] := SCSI_INQUIRY_CDB.PageCode;
    aCDB[3] := HiByte(SCSI_INQUIRY_CDB.AllocationLength);
    aCDB[4] := LoByte(SCSI_INQUIRY_CDB.AllocationLength);
    aCDB[5] := SCSI_INQUIRY_CDB.Control;
    {
    *  Befehl ausführen. Manchmal ist es notwendig, den Speicher anzufordern.
    }
    GetMem(pInquiryData, SizeOf(TINQUIRY_STANDARD_DATA));
    Result := GET_SCSI_PASS_THROUGH_DIRECT(aDevice, aCDB,
                                           pInquiryData,
                                           SizeOf(TINQUIRY_STANDARD_DATA));
    if Result then
    with fDrive[fActive].DeviceInfo
    do begin
      T10VendorIdentification := Trim(pInquiryData.T10VendorIdentification);
      ProductIdentification   := Trim(pInquiryData.ProductIdentification);
      ProductRevisionLevel    := Trim(pInquiryData.ProductRevisionLevel);
      VendorSpecific0         := Trim(pInquiryData.VendorSpecific0);
    end;
    FreeMem(pInquiryData);
  end;
end;

Informationen zur Funktion GET_SCSI_PASS_THROUGH_DIRECT gibt es in Anhang 1. In der Demo wird die Funktion ReadInquiry bei der Erstellung der Klasse aufgerufen.

constructor TOptDrives.Create;
{*******************************************************************************
*  Class erstellen.
}
var
  i       : Integer;
  hDevice : THandle;
begin
  {
  *  Laufwerksbuchstaben ermitteln.
  }
  if ReadDrives > 0
  then begin
    for i := 0 to Length(fDrive) - 1
    do begin
      fActive := i;
      hDevice := DriveHandle(fDrive[fActive].Letter);
      if hDevice <> INVALID_HANDLE_VALUE
      then begin
        ReadSCSIAddress(hDevice);
        ReadInquiry(hDevice);
        CloseHandle(hDevice);
      end;
    end;
  end;
end;

Das Ergebnis des Beispiels sieht so aus:

Description (podDescription.7z - 230 kb) MD5 (1 kb). Stand: 28. April 2013

Änderungen an der Demo

28.04.2013Kleine Überarbeitung und neuer Name.
04.04.2013Überarbeitung.