⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 skscsi.pas

📁 用于CD/DVD烧录的Delphi源码,包括source和demo
💻 PAS
📖 第 1 页 / 共 3 页
字号:
  private
    FCompanyName: string;
    FFileDescription: string;
    FFileVersion: string;
    FInternalName: string;
    FLegalCopyright: string;
    FLegalTradeMarks: string;
    FOriginalFilename: string;
    FProductName: string;
    FProductVersion: string;
    FComments: string;
    constructor GetVersionInfo(FileName: string);
  public
    property CompanyName: string read FCompanyName;
    property FileDescription: string read FFileDescription;
    property FileVersion: string read FFileVersion;
    property InternalName: string read FInternalName;
    property LegalCopyright: string read FLegalCopyright;
    property LegalTradeMarks: string read FLegalTradeMarks;
    property OriginalFilename: string read FOriginalFileName;
    property ProductName: string read FProductName;
    property ProductVersion: string read FProductVersion;
    property Comments: string read FComments;
  end;

type
  {****************************************************************************}
  {  SCSI INTERFACE CLASS                                                      }
  {****************************************************************************}
  TInterfaceType = (ifASPI, ifASAPI, ifSPTI);
  TskSCSI = class
  private
    FInitOK: Boolean; // Will be TRUE if Initialization was OK (Handle <> 0)
    FifType: TInterfaceType; // The Type of Interface in Use
    FosName: ShortString; // The Name of the Operating System
    FviASPI: TVersionInfo; // Version Info of ASPI or ASAPI DLL (NIL for SPTI)
  public
    constructor Create;
    destructor Destroy; override;
    function ExecCmd(HaId, Target, Lun: Byte; CDB: TCDB; CDBLen: Cardinal;
      Flags: Cardinal; Buffer: Pointer; BufferLen: Cardinal): Byte;
    function AbortCmd(FSRB_ExecSCSICmd: TSRB_ExecSCSICmd): Boolean;
    function InterfaceNameShort: string;
    function InterfaceNameLong: string;
    function InterfaceDeveloper: string;
    property InitOK: Boolean read FInitOK;
    property InterfaceType: TInterfaceType read FifType;
    property osName: ShortString read FosName;
    property viASPI: TVersionInfo read FviASPI;
    // Version Info of ASPI or ASAPI DLL (NIL for SPTI)
  end;

var
  {****************************************************************************}
  {  PUBLIC VARIABLES                                                          }
  {****************************************************************************}

  // Public to direct use, Named "ASPI", but we use for ASAPI or SPTI too
  GetASPI32SupportInfo: function: DWord; cdecl;
  SendASPI32Command: function(LPSRB: Pointer): DWord; cdecl;

implementation

const
  {****************************************************************************}
  {  CONSTANTS                                                                 }
  {****************************************************************************}
  ASPI = 'wnaspi32.dll';
  ASAPI = 'asapi.dll';
  SPTI = 'skSCSI'; // Dummy for Manager ID and Inquiry Data

var
  {****************************************************************************}
  {  VARIABLES                                                                 }
  {****************************************************************************}
  SCSIHandle: THandle; // DLL Handle if Using ASPI or ASAPI (1 if USING SPTI)
  SCSIDrives: TSCSIDRIVES;
  TGN: Byte = 0;
  inqData: array[0..1024] of Char = SPTI;

  {****************************************************************************}
  {  SPTI COMMANDS BEGIN                                                       }
  {****************************************************************************}

function SPTI_GetASPI32SupportInfo: DWord;
begin
  if SCSIDrives.numAdapters = 0 then
    Result := MAKEWORD(0, SS_NO_ADAPTERS)
  else
    Result := MAKEWORD(SCSIDrives.numAdapters, SS_COMP);
end;

function SPTI_HaInquiry(FPSRB: Pointer): DWord;
var
  PSRB: PSRB_HAInquiry;
begin
  PSRB := FPSRB;
  PSRB.HA_Count := SCSIDrives.numAdapters;
  if PSRB.HaId >= SCSIDrives.numAdapters then
  begin
    PSRB.Status := SS_INVALID_HA;
    Result := SS_INVALID_HA;
    Exit;
  end;
  PSRB.HA_SCSI_ID := 7;
  PSRB.HA_ManagerId := SPTI;
  PSRB.HA_Identifier := 'SPTI  '#0#0#0#0#0#0#0#0#0;
  PSRB.HA_Identifier[5] := Char($30 + PSRB.HaId);
  FillChar(PSRB.HA_Unique, 13, 0);
  PSRB.HA_Unique[0] := #7; // buffer alignment
  PSRB.HA_Unique[3] := #8; // scsi targets
  PSRB.HA_Unique[4] := #00;
  PSRB.HA_Unique[5] := #00;
  PSRB.HA_Unique[6] := #$FF;
  PSRB.Status := SS_COMP;
  Result := SS_COMP;
end;

function SPTI_GetDevIndex(H, T, L: Byte): Byte;
var
  i: Byte;
  Drv: TSCSIDRIVE;
begin
  for i := 2 to 26 do
  begin
    if SCSIDrives.Drive[i].Used then
    begin
      Drv := SCSIDrives.Drive[i];
      if (Drv.Ha = H) and (Drv.Target = T) and (Drv.Lun = L) then
      begin
        Result := i;
        Exit;
      end;
    end
  end;
  Result := 0;
end;

function SPTI_GetDevType(FPSRB: Pointer): DWord;
var
  PSRB: PSRB_GDEVBlock;
begin
  PSRB := FPSRB;
  PSRB.Status := SS_NO_DEVICE;
  if SPTI_GetDevIndex(PSRB.HaId, PSRB.Target, PSRB.Lun) <> 0 then
    PSRB.Status := SS_COMP;
  if PSRB.Status = SS_COMP then
    PSRB.DeviceType := DTYPE_CDROM
  else
    PSRB.DeviceType := DTYPE_UNKNOWN;
  Result := PSRB.Status;
end;

function SPTI_GetDiskInfo(FPSRB: Pointer): DWord;
var
  PSRB: PSRB_GetDiskInfo;
begin
  PSRB := FPSRB;
  PSRB.Int13HDriveInfo := SPTI_GetDevIndex(PSRB.HaId, PSRB.Target, PSRB.Lun);
  PSRB.Status := SS_COMP;
  Result := SS_COMP;
end;

function SPTI_GetDriveHandle(i: Byte): LongWord;
var
  Path: string;
begin
  Path := '\\.\' + Char(i + 65) + ':'#0;
  Result := CreateFile(@Path[1], GENERIC_WRITE or GENERIC_READ, FILE_SHARE_READ
    or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  if Result = INVALID_HANDLE_VALUE then
    Result := CreateFile(@Path[1], GENERIC_READ, FILE_SHARE_READ, nil,
      OPEN_EXISTING, 0, 0);
end;

function SPTI_SendASPI32Command_Internal(PSRB: PSRB_ExecSCSICmd; Again:
  Boolean): DWord;
var
  Status: Boolean;
  SPTI_WBUFFER: SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
  Length, Returned: Cardinal;
  Index: Byte;
label
  ExecSCSICmd;
begin
  if PSRB = nil then
  begin
    Result := SS_ERR;
    Exit;
  end;
  case PSRB^.Cmd of
    SC_EXEC_SCSI_CMD:
      goto ExecSCSICmd;
    SC_HA_INQUIRY:
      begin
        Result := SPTI_HaInquiry(PSRB);
        Exit;
      end;
    SC_GET_DEV_TYPE:
      begin
        Result := SPTI_GetDevType(PSRB);
        Exit;
      end;
    SC_GET_DISK_INFO:
      begin
        Result := SPTI_GetDiskInfo(PSRB);
        Exit;
      end;
  else
    begin
      PSRB^.Status := SS_ERR;
      Result := SS_ERR;
      Exit;
    end;
  end;
  ExecSCSICmd:
  Index := SPTI_GetDevIndex(PSRB^.HaId, PSRB^.Target, PSRB^.Lun);
  if Index = 0 then
  begin
    PSRB^.Status := SS_NO_DEVICE;
    Result := SS_NO_DEVICE;
    Exit;
  end;
  if PSRB^.CDBByte[0] = SC_SCSI_INQUIRY then
  begin
    if PSRB^.HaId >= SCSIDrives.numAdapters then
    begin
      PSRB^.Status := SS_INVALID_HA;
      Result := SS_INVALID_HA;
      Exit;
    end;
    PSRB^.Status := SS_COMP;
    Move(SCSIDrives.Drive[Index].inqData, PSRB^.BufPointer[0], 36);
    Result := SS_COMP;
    Exit;
  end;
  if (SCSIDrives.Drive[Index].DeviceHandle = INVALID_HANDLE_VALUE) then
    SCSIDrives.Drive[Index].DeviceHandle :=
      SPTI_GetDriveHandle(SCSIDrives.Drive[Index].Letter);
  FillChar(SPTI_WBUFFER, SizeOf(SPTI_WBUFFER), 0);
  if PSRB^.Flags and SRB_DIR_IN <> 0 then
    SPTI_WBUFFER.SPT.DataIn := SCSI_IOCTL_DATA_IN
  else if PSRB^.Flags and SRB_DIR_OUT <> 0 then
    SPTI_WBUFFER.SPT.DataIn := SCSI_IOCTL_DATA_OUT
  else
    SPTI_WBUFFER.SPT.DataIn := SCSI_IOCTL_DATA_UNSPECIFIED;
  with SPTI_WBUFFER.SPT do
  begin
    Length := SizeOf(SCSI_PASS_THROUGH_DIRECT);
    CdbLength := PSRB^.CDBLen;
    SenseInfoLength := PSRB^.SenseLen;
    DataTransferLength := PSRB^.BufLen;
    TimeOutValue := 120;
    DataBuffer := PSRB^.BufPointer;
    SenseInfoOffset := 48;
  end;
  Move(PSRB^.CDBByte[0], SPTI_WBUFFER.SPT.CDB, PSRB^.CDBLen);
  Length := SizeOf(SPTI_WBUFFER);
  Status := DeviceIoControl(SCSIDrives.Drive[Index].DeviceHandle,
    IOCTL_SCSI_PASS_THROUGH_DIRECT, @SPTI_WBUFFER, Length, @SPTI_WBUFFER,
      Length,
    Returned, nil);
  if ((SPTI_WBUFFER.SPT.SenseInfoLength = 0) or (SPTI_WBUFFER.SPT.SenseInfoLength
    = 32))
    and (SPTI_WBUFFER.SPT.SCSIStatus = 0) and Status then
    PSRB^.Status := SS_COMP
  else
  begin
    PSRB^.Status := SS_ERR;
    Move(SPTI_WBUFFER.ucSenseBuf, PSRB^.SenseArea,
      SPTI_WBUFFER.SPT.SenseInfoLength);
    PSRB^.TargStat := SPTI_WBUFFER.SPT.SCSIStatus;
  end;
  if SCSIDrives.Drive[Index].DeviceHandle <> INVALID_HANDLE_VALUE then
  begin
    if CloseHandle(SCSIDrives.Drive[Index].DeviceHandle) then
      SCSIDrives.Drive[Index].DeviceHandle := INVALID_HANDLE_VALUE;
  end;
  Result := PSRB^.Status;
end;

function SPTI_SendASPI32Command(PSRB: PSRB_ExecSCSICmd): DWord;
begin
  Result := SPTI_SendASPI32Command_Internal(PSRB, False);
end;

procedure SPTI_GetDriveInfo(i: Byte; var pDrive: TSCSIDRIVE);
var
  Handle: THandle;
  Buffer: array[0..1023] of Char;
  P_SCSI_WBUFFER: PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
  P_SCSI_ADDRESS: PSCSI_ADDRESS;
  Length, Returned: Cardinal;
  Status: Boolean;
begin
  Handle := SPTI_GetDriveHandle(i);
  if (Handle = INVALID_HANDLE_VALUE) then
    Exit;
  ZeroMemory(@Buffer, 1024);
  ZeroMemory(@inqData, SizeOf(inqData));
  P_SCSI_WBUFFER := @Buffer;
  with P_SCSI_WBUFFER.SPT do
  begin
    Length := SizeOf(SCSI_PASS_THROUGH);
    CDBLength := 6;
    SenseInfoLength := 24;
    DataIn := SCSI_IOCTL_DATA_IN;
    DataTransferLength := 96;
    TimeOutValue := 120;
    DataBuffer := @inqData;
    SenseInfoOffset := 48;
    CDB[0] := SC_SCSI_INQUIRY;
    CDB[4] := 96;
  end;
  Length := SizeOf(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
  Status := DeviceIoControl(Handle, IOCTL_SCSI_PASS_THROUGH_DIRECT,
    P_SCSI_WBUFFER, Length, P_SCSI_WBUFFER, Length, Returned, nil);
  if not Status then
  begin
    CloseHandle(Handle);
    Exit;
  end;
  Move(inqData, pDrive.inqData, 40);
  FillChar(Buffer, Sizeof(Buffer), 0);
  P_SCSI_ADDRESS := @Buffer;
  P_SCSI_ADDRESS.Length := SizeOf(SCSI_ADDRESS);
  if DeviceIoControl(Handle, IOCTL_SCSI_GET_ADDRESS, nil, 0, P_SCSI_ADDRESS,
    SizeOf(SCSI_ADDRESS), Returned, nil) then
  begin
    pDrive.Used := True;
    pDrive.Ha := P_SCSI_ADDRESS.Ha;
    pDrive.Target := P_SCSI_ADDRESS.Target;
    pDrive.Lun := P_SCSI_ADDRESS.Lun;
    pDrive.Letter := i;
    pDrive.DeviceHandle := INVALID_HANDLE_VALUE;
  end
  else
  begin
    pDrive.Used := True;
    pDrive.Ha := 0;
    pDrive.Target := TGN;
    pDrive.Lun := 250;
    pDrive.Letter := i;
    pDrive.DeviceHandle := INVALID_HANDLE_VALUE;
    Inc(TGN);
  end;
  CloseHandle(Handle);
end;

function SPTI_GetNumAdapters: Byte;
var
  i, numAdapters: Byte;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -