Con el siguiente truco podemos obtener la propiedades de una unidad de Cd.
Código Delphi
[-]
const
SPT_SENSE_LENGTH = 32;
SPTWB_DATA_LENGTH = 512;
CDB6GENERIC_LENGTH = 6;
SCSI_IOCTL_DATA_IN = 1;
SCSIOP_INQUIRY = $12;
SCSIOP_MODE_SENSE = $1A;
MODE_PAGE_CAPABILITIES = $2A;
IOCTL_SCSI_PASS_THROUGH = $04D004;
type
ULONG_PTR = ULONG;
SCSI_PASS_THROUGH = record
Length: Word;
ScsiStatus: UCHAR;
PathId: UCHAR;
TargetId: UCHAR;
Lun: UCHAR;
CdbLength: UCHAR;
SenseInfoLength: UCHAR;
DataIn: UCHAR;
DataTransferLength: ULONG;
TimeOutValue: ULONG;
DataBufferOffset: ULONG_PTR;
SenseInfoOffset: ULONG;
Cdb: array[0..15] of UCHAR;
end;
PSCSI_PASS_THROUGH = ^SCSI_PASS_THROUGH;
SCSI_PASS_THROUGH_WITH_BUFFERS = record
spt: SCSI_PASS_THROUGH;
Filler: ULONG;
ucSenseBuf: array[0..SPT_SENSE_LENGTH-1] of UCHAR;
ucDataBuf: array[0..SPTWB_DATA_LENGTH-1]of UCHAR;
end;
PSCSI_PASS_THROUGH_WITH_BUFFERS = ^SCSI_PASS_THROUGH_WITH_BUFFERS;
TDeviceProperty = record
CDRReader: Boolean;
CDRWReader: Boolean;
CDRWriter: Boolean;
CDRWWriter: Boolean;
DVDROMReader: Boolean;
DVDRReader: Boolean;
DVDRAMReader: Boolean;
DVDRWriter: Boolean;
DVDRAMWriter: Boolean;
end;
function OffsetOf(a,b: Pointer): integer;
begin
Result:= Integer(b) - Integer(a);
end;
function GetDeviceProperty(Letra: Char; var DeviceProperty: TDeviceProperty): String;
var
Disk: THandle;
Sptwb: SCSI_PASS_THROUGH_WITH_BUFFERS;
l: ULONG;
Returned: Cardinal;
begin
Result:= EmptyStr;
FillChar(DeviceProperty,SizeOf(DeviceProperty),0);
Disk:= CreateFile(PChar('\\.\' + Letra + ':'),GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,nil,OPEN_EXISTING,0,0);
if Disk <> INVALID_HANDLE_VALUE then
begin
FillChar(Sptwb,Sizeof(Sptwb),0);
Sptwb.Spt.Length:= sizeof(SCSI_PASS_THROUGH);
Sptwb.Spt.PathId:= 0;
Sptwb.Spt.TargetId:= 1;
Sptwb.Spt.Lun:= 0;
Sptwb.Spt.CdbLength:= CDB6GENERIC_LENGTH;
Sptwb.Spt.SenseInfoLength:= 24;
Sptwb.Spt.DataIn:= SCSI_IOCTL_DATA_IN;
Sptwb.Spt.DataTransferLength:= 192;
Sptwb.Spt.TimeOutValue:= 2;
Sptwb.Spt.DataBufferOffset:=
OffsetOf(@Sptwb,@Sptwb.ucDataBuf);
Sptwb.Spt.SenseInfoOffset:=
OffsetOf(@Sptwb,@Sptwb.ucSenseBuf);
Sptwb.Spt.Cdb[0]:= SCSIOP_MODE_SENSE;
Sptwb.Spt.Cdb[1]:= $08;
Sptwb.Spt.Cdb[2]:= MODE_PAGE_CAPABILITIES;
Sptwb.Spt.Cdb[4]:= 192;
l:= OffsetOf(@Sptwb,@Sptwb.ucDataBuf) +
sptwb.Spt.DataTransferLength;
if DeviceIoControl(Disk,IOCTL_SCSI_PASS_THROUGH,@Sptwb,
Sizeof(SCSI_PASS_THROUGH),@sptwb,l,Returned,nil) then
begin
if ((Sptwb.ucDataBuf[6] and $01) or (Sptwb.ucDataBuf[6] and $02) > 0) then
begin
DeviceProperty.CDRReader:= (Sptwb.ucDataBuf[6] and $01) > 0;
DeviceProperty.CDRWReader:= (Sptwb.ucDataBuf[6] and $02) > 0;
if (Sptwb.ucDataBuf[7] and $01) or (Sptwb.ucDataBuf[7] and $02) > 0 then
begin
DeviceProperty.CDRWriter:= (Sptwb.ucDataBuf[7] and $01) > 0;
DeviceProperty.CDRWWriter:= (Sptwb.ucDataBuf[7] and $02) > 0;
end;
end;
if (Sptwb.ucDataBuf[6] and $08) or (Sptwb.ucDataBuf[6] and $10) or
(Sptwb.ucDataBuf[6] and $20) > 0 then
begin
DeviceProperty.DVDROMReader:= (Sptwb.ucDataBuf[6] and $08) > 0;
DeviceProperty.DVDRReader:= (Sptwb.ucDataBuf[6] and $10) > 0;
DeviceProperty.DVDRAMReader:= (Sptwb.ucDataBuf[6] and $20) > 0;
if ((Sptwb.ucDataBuf[7] and $10) or (Sptwb.ucDataBuf[7] and $20) > 0) then
begin
DeviceProperty.DVDRWriter:= (Sptwb.ucDataBuf[7] and $10) > 0;
DeviceProperty.DVDRAMWriter:= (Sptwb.ucDataBuf[7] and $20) > 0;
end;
end;
end else Result:= SysErrormessage(GetLastError);
CloseHandle(Disk);
end else Result:= SysErrormessage(GetLastError);
end;
Un ejemplo de como usar la función anterior:
Código Delphi
[-]
function BoolToSiNo(Value: Boolean): String;
begin
if Value then
Result:= 'Si'
else
Result:= 'No';
end;
var
DeviceProperty: TDeviceProperty;
Str: String;
begin
Str:= GetDeviceProperty('D',DeviceProperty);
if Str = EmptyStr then
begin
if DeviceProperty.CDRReader or DeviceProperty.CDRWReader then
begin
Str:= 'CD Reader: Si';
Str:= Str + #13#10 + 'CD-R: ' + BoolToSiNo(DeviceProperty.CDRReader);
Str:= Str + #13#10 + 'CD-RW: ' + BoolToSiNo(DeviceProperty.CDRWReader);
if DeviceProperty.CDRWriter or DeviceProperty.CDRWWriter then
begin
Str:= Str + #13#10#13#10 + 'CD Writer: Si';
Str:= Str + #13#10 + 'CD-R: ' + BoolToSiNo(DeviceProperty.CDRWriter);
Str:= Str + #13#10 + 'CD-RW: ' + BoolToSiNo(DeviceProperty.CDRWWriter);
end else Str:= Str + #13#10#13#10 + 'CD Writer: No';
end else Str:= Str + 'CD Reader: No';
if DeviceProperty.DVDROMReader or DeviceProperty.DVDRReader or
DeviceProperty.DVDRAMReader then
begin
Str:= Str + #13#10#13#10 + 'DVD Reader: Si';
Str:= Str + #13#10 + 'DVD-ROM: ' + BoolToSiNo(DeviceProperty.DVDROMReader);
Str:= Str + #13#10 + 'DVD-R: ' + BoolToSiNo(DeviceProperty.DVDRReader);
Str:= Str + #13#10 + 'DVD-RAM: ' + BoolToSiNo(DeviceProperty.DVDRAMReader);
if DeviceProperty.DVDRWriter or DeviceProperty.DVDRAMWriter then
begin
Str:= Str + #13#10#13#10 + 'DVD Writer: Si';
Str:= Str + #13#10 + 'DVD-R: ' + BoolToSiNo(DeviceProperty.DVDRWriter);
Str:= Str + #13#10 + 'DVD-RAM: ' + BoolToSiNo(DeviceProperty.DVDRAMWriter);
end else Str:= Str + #13#10#13#10 + 'DVD Writer: No';
end else Str:= Str + #13#10#13#10 + 'DVD Reader: No';
end;
ShowMessage(Str);
end;
Este truco esta basado en este ejemplo de microsoft:
http://support.microsoft.com/kb/305184