使用Device IO Control 讀寫 USB Mass Storage

http://www.ezblog.idv.tw/Download/USBStorage.rar

這是一個不透過檔案系統,去讀寫USB Mass Storage 任何位置(包含FAT)的方式

首先需安裝微軟的DDK並include "usbioctl.h" , "usbdi.h" , "ntddscsi.h"

有幾個資料結構要定義

typedef struct _SCSI_Device_Info_
{
  SCSI_PASS_THROUGH Spt;
  BYTE Sense[ 18 ];
  BYTE Data[ 36 ];
} SCSI_Device_Info, *pSCSI_Device_Info;
typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS
{
  SCSI_PASS_THROUGH Spt;
  ULONG Filler;      // realign buffers to double word boundary
  UCHAR ucSenseBuf[ SPT_SENSE_LENGTH ];
  UCHAR ucDataBuf[ SPTWB_DATA_LENGTH ];
} SCSI_PASS_THROUGH_WITH_BUFFERS, *pSCSI_PASS_THROUGH_WITH_BUFFERS;
typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
{
  SCSI_PASS_THROUGH_DIRECT sptd;
  ULONG Filler;      // realign buffer to double word boundary
  UCHAR ucSenseBuf[ SPT_SENSE_LENGTH ];
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *pSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;

/*
 * Required UFI Commands
 */
#define UFI_FORMAT_UNIT             0x04    // output
#define UFI_INQUIRY                 0x12    // input
#define UFI_MODE_SELECT             0x55    // output
#define UFI_MODE_SENSE_6            0x1A    // input
#define UFI_MODE_SENSE_10           0x5A    // input
#define UFI_PREVENT_MEDIUM_REMOVAL  0x1E
#define UFI_READ_10                 0x28    // input
#define UFI_READ_12                 0xA8    // input
#define UFI_READ_CAPACITY           0x25    // input
#define UFI_READ_FORMAT_CAPACITY    0x23    // input
#define UFI_REQUEST_SENSE           0x03    // input
#define UFI_REZERO_UNIT             0x01
#define UFI_SEEK_10                 0x2B
#define UFI_SEND_DIAGNOSTIC         0x1D
#define UFI_START_UNIT              0x1B
#define UFI_TEST_UNIT_READY         0x00
#define UFI_VERIFY                  0x2F
#define UFI_WRITE_10                0x2A    // output
#define UFI_WRITE_12                0xAA    // output
#define UFI_WRITE_AND_VERIFY        0x2E    // output
#define UFI_ALLOW_MEDIUM_REMOVAL    UFI_PREVENT_MEDIUM_REMOVAL
#define UFI_STOP_UNIT               UFI_START_UNIT

bool CUSBStorDrive::m_OpenDrive()
{
  char DriveStr[100];

  m_CloseDrive();
  memset(DriveStr,0x00,100);

  sprintf(DriveStr, "\\\\?\\%c:", m_cDrive);
  m_hDrive = CreateFile(
      DriveStr,           // device interface name
      GENERIC_READ | GENERIC_WRITE,// dwDesiredAccess
      FILE_SHARE_READ | FILE_SHARE_WRITE,// dwShareMode
      NULL,// lpSecurityAttributes
      OPEN_EXISTING,// dwCreationDistribution
      0,// dwFlagsAndAttributes
      NULL// hTemplateFile
  );
  if (m_hDrive == INVALID_HANDLE_VALUE)
  {
    m_LastErrCode = GetLastError();
    return false;
  }
  return m_SendInquiry(m_hDrive);
}

bool CUSBStorDrive::m_CloseDrive()
{
  if (m_hDrive != NULL)
  {
    CloseHandle(m_hDrive);
  }
  m_hDrive = NULL;
  return true;
}

bool CUSBStorDrive::m_SendInquiry(HANDLE hDrive)
{
  SCSI_Device_Info SCSIInfo =
  { 0};
  DWORD ReturnLen;
  BOOL bResult;

  if (hDrive == NULL) return false;

  SCSIInfo.Spt.Length = sizeof(SCSIInfo.Spt);
  SCSIInfo.Spt.SenseInfoLength = sizeof(SCSIInfo.Sense);
  SCSIInfo.Spt.DataTransferLength = sizeof(SCSIInfo.Data);
  SCSIInfo.Spt.SenseInfoOffset = offsetof(SCSI_Device_Info, Sense);
  SCSIInfo.Spt.DataBufferOffset = offsetof(SCSI_Device_Info, Data);
  SCSIInfo.Spt.TimeOutValue = 30;
  SCSIInfo.Spt.DataIn = SCSI_IOCTL_DATA_IN;
  SCSIInfo.Spt.CdbLength = 6;
  SCSIInfo.Spt.Cdb[0] = UFI_INQUIRY; // inquiry opcode
  SCSIInfo.Spt.Cdb[1] = 0x00;
  SCSIInfo.Spt.Cdb[2] = 0x00;
  SCSIInfo.Spt.Cdb[3] = 0x00;
  SCSIInfo.Spt.Cdb[4] = sizeof(SCSIInfo.Data);
  SCSIInfo.Spt.Cdb[5] = 0x00;

  bResult = DeviceIoControl(
      hDrive,
      IOCTL_SCSI_PASS_THROUGH,
      &SCSIInfo,
      sizeof(SCSIInfo),
      &SCSIInfo,
      sizeof(SCSIInfo),
      &ReturnLen,
      FALSE);
  if (bResult)
  {
    return true;
  }
  else
  {
    m_LastErrCode = GetLastError();
    return false;
  }
}

bool CUSBStorDrive::m_ReadCapacity(HANDLE hDrive)
{
  SCSI_Device_Info SCSIInfo =
  { 0};
  DWORD ReturnLen;
  BOOL bResult;
  if (hDrive == NULL) return false;

  SCSIInfo.Spt.Length = sizeof(SCSIInfo.Spt);
  SCSIInfo.Spt.SenseInfoLength = sizeof(SCSIInfo.Sense);
  SCSIInfo.Spt.DataTransferLength = sizeof(SCSIInfo.Data);
  SCSIInfo.Spt.SenseInfoOffset = offsetof(SCSI_Device_Info, Sense);
  SCSIInfo.Spt.DataBufferOffset = offsetof(SCSI_Device_Info, Data);
  SCSIInfo.Spt.TimeOutValue = 30;
  SCSIInfo.Spt.DataIn = SCSI_IOCTL_DATA_IN;
  SCSIInfo.Spt.CdbLength = 12;
  SCSIInfo.Spt.Cdb[0] = UFI_READ_CAPACITY; // Read Capacity opcode
  SCSIInfo.Spt.Cdb[1] = 0x00;
  SCSIInfo.Spt.Cdb[2] = 0x00;
  SCSIInfo.Spt.Cdb[3] = 0x00;
  SCSIInfo.Spt.Cdb[4] = 0x00;
  SCSIInfo.Spt.Cdb[5] = 0x00;
  SCSIInfo.Spt.Cdb[6] = 0x00;
  SCSIInfo.Spt.Cdb[7] = 0x00;
  SCSIInfo.Spt.Cdb[8] = 0x00;
  SCSIInfo.Spt.Cdb[9] = 0x00;
  SCSIInfo.Spt.Cdb[10] = 0x00;
  SCSIInfo.Spt.Cdb[11] = 0x00;

  bResult = DeviceIoControl(
      hDrive,
      IOCTL_SCSI_PASS_THROUGH,
      &SCSIInfo,
      sizeof(SCSIInfo),
      &SCSIInfo,
      sizeof(SCSIInfo),
      &ReturnLen,
      FALSE);
  if (bResult)
  {
    return true;
  }
  else
  {
    m_LastErrCode = GetLastError();
    return false;
  }
}

bool CUSBStorDrive::m_ReadFormatCapacity(HANDLE hDrive)
{
  SCSI_Device_Info SCSIInfo =
  { 0};
  DWORD ReturnLen = 0;
  BOOL bResult = false;
  if (hDrive == NULL) return false;

  WORD wAllocLeng = 0x0000;

  SCSIInfo.Spt.Length = sizeof(SCSIInfo.Spt);
  SCSIInfo.Spt.SenseInfoLength = sizeof(SCSIInfo.Sense);
  SCSIInfo.Spt.DataTransferLength = sizeof(SCSIInfo.Data);
  SCSIInfo.Spt.SenseInfoOffset = offsetof(SCSI_Device_Info, Sense);
  SCSIInfo.Spt.DataBufferOffset = offsetof(SCSI_Device_Info, Data);
  SCSIInfo.Spt.TimeOutValue = 30;
  SCSIInfo.Spt.DataIn = SCSI_IOCTL_DATA_IN;
  SCSIInfo.Spt.CdbLength = 12;
  SCSIInfo.Spt.Cdb[0] = UFI_READ_FORMAT_CAPACITY; // Read format Capacity opcode
  SCSIInfo.Spt.Cdb[1] = 0x00;
  SCSIInfo.Spt.Cdb[2] = 0x00;
  SCSIInfo.Spt.Cdb[3] = 0x00;
  SCSIInfo.Spt.Cdb[4] = 0x00;
  SCSIInfo.Spt.Cdb[5] = 0x00;
  SCSIInfo.Spt.Cdb[6] = 0x00;
  SCSIInfo.Spt.Cdb[7] = wAllocLeng >> 8;//Allocation Length (MSB)
  SCSIInfo.Spt.Cdb[8] = wAllocLeng & 0x00FF;//Allocation Length (LSB)
  SCSIInfo.Spt.Cdb[9] = 0x00;
  SCSIInfo.Spt.Cdb[10] = 0x00;
  SCSIInfo.Spt.Cdb[11] = 0x00;

  bResult = DeviceIoControl(
      hDrive,
      IOCTL_SCSI_PASS_THROUGH,
      &SCSIInfo,
      sizeof(SCSIInfo),
      &SCSIInfo,
      sizeof(SCSIInfo),
      &ReturnLen,
      FALSE);
  if (bResult)
  {
    //SCSIInfo.Data[];
    return true;
  }
  else
  {
    m_LastErrCode = GetLastError();
    return false;
  }
}

bool CUSBStorDrive::m_Read10WithBuffer(HANDLE hDrive,DWORD dwStartBlock,BYTE *pBuf,DWORD dwlength)
{
  SCSI_PASS_THROUGH_WITH_BUFFERS SCSIDataWithBuf =
  { 0};
  DWORD ReturnLen = 0;
  BOOL bResult = false;
  WORD wBlocks = 0x0001;
  BYTE *ptr = NULL;
  int iCount = 0;

  if (hDrive == NULL) return false;
  if (pBuf == NULL) return false;

  SCSIDataWithBuf.Spt.Length = sizeof(SCSI_PASS_THROUGH);
  SCSIDataWithBuf.Spt.SenseInfoLength = SPT_SENSE_LENGTH;
  SCSIDataWithBuf.Spt.DataTransferLength = SPTWB_DATA_LENGTH;
  SCSIDataWithBuf.Spt.PathId = 0;
  SCSIDataWithBuf.Spt.TargetId = 1;
  SCSIDataWithBuf.Spt.Lun = 0;
  SCSIDataWithBuf.Spt.TimeOutValue = TIME_OUT;
  SCSIDataWithBuf.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
  SCSIDataWithBuf.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
  SCSIDataWithBuf.Spt.DataIn = SCSI_IOCTL_DATA_IN;
  SCSIDataWithBuf.Spt.CdbLength = 12;
  SCSIDataWithBuf.Spt.Cdb[0] = UFI_READ_10;
  SCSIDataWithBuf.Spt.Cdb[1] = 0x00;
  SCSIDataWithBuf.Spt.Cdb[2] = (dwStartBlock & 0xFF000000) >> 24;
  SCSIDataWithBuf.Spt.Cdb[3] = (dwStartBlock & 0x00FF0000) >> 16;
  SCSIDataWithBuf.Spt.Cdb[4] = (dwStartBlock & 0x0000FF00) >> 8;
  SCSIDataWithBuf.Spt.Cdb[5] = (dwStartBlock & 0x000000FF);
  SCSIDataWithBuf.Spt.Cdb[6] = 0x00;
  SCSIDataWithBuf.Spt.Cdb[7] = (wBlocks & 0xFF00) >> 8;
  SCSIDataWithBuf.Spt.Cdb[8] = (wBlocks & 0x00FF);
  SCSIDataWithBuf.Spt.Cdb[9] = 0x00;
  SCSIDataWithBuf.Spt.Cdb[10] = 0x00;
  SCSIDataWithBuf.Spt.Cdb[11] = 0x00;

  ptr = pBuf;
  iCount = dwlength / SPTWB_DATA_LENGTH;
  if ((dwlength % SPTWB_DATA_LENGTH) > 0) iCount++;
  int iPos = 0;
  for (int i=0; i < iCount; i++)
  {
    SCSIDataWithBuf.Spt.Cdb[2] = (dwStartBlock & 0xFF000000) >> 24;
    SCSIDataWithBuf.Spt.Cdb[3] = (dwStartBlock & 0x00FF0000) >> 16;
    SCSIDataWithBuf.Spt.Cdb[4] = (dwStartBlock & 0x0000FF00) >> 8;
    SCSIDataWithBuf.Spt.Cdb[5] = (dwStartBlock & 0x000000FF);

    bResult = DeviceIoControl(
        hDrive,
        IOCTL_SCSI_PASS_THROUGH,
        &SCSIDataWithBuf,
        sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS),
        &SCSIDataWithBuf,
        //length,
        sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS),
        &ReturnLen,
        FALSE);
    if (bResult)
    {
      iPos = (i * 100)/iCount;
      if (m_pWaitUISetPosProc != NULL)
      {
        (m_pWaitUISetPosProc)(0,iPos);
      }
      if ((i+1) == iCount)  //last
      {
        memcpy(ptr,SCSIDataWithBuf.ucDataBuf,dwlength);
        dwlength = 0;
      }
      else
      {
        memcpy(ptr,SCSIDataWithBuf.ucDataBuf,SPTWB_DATA_LENGTH);
        dwlength -= SPTWB_DATA_LENGTH;
      }
      ptr += SPTWB_DATA_LENGTH;
      dwStartBlock ++;
    }
    else
    {
      m_LastErrCode = GetLastError();
      break;
    }
  }
  return bResult;
}

bool CUSBStorDrive::m_Write10WithBuffer(HANDLE hDrive,DWORD dwStartBlock,BYTE *pBuf,DWORD dwlength)
{
  SCSI_PASS_THROUGH_WITH_BUFFERS SCSIDataWithBuf =
  { 0};
  DWORD ReturnLen = 0;
  WORD wBlocks = 0x0001;
  BYTE *ptr = NULL;
  BOOL bResult = false;
  int iCount = 0;

  if (hDrive == NULL) return false;
  if (pBuf == NULL) return false;

  SCSIDataWithBuf.Spt.Length = sizeof(SCSI_PASS_THROUGH);
  SCSIDataWithBuf.Spt.SenseInfoLength = SPT_SENSE_LENGTH;
  SCSIDataWithBuf.Spt.DataTransferLength = SPTWB_DATA_LENGTH;
  SCSIDataWithBuf.Spt.PathId = 0;
  SCSIDataWithBuf.Spt.TargetId = 1;
  SCSIDataWithBuf.Spt.Lun = 0;
  SCSIDataWithBuf.Spt.TimeOutValue = TIME_OUT;
  SCSIDataWithBuf.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
  SCSIDataWithBuf.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
  SCSIDataWithBuf.Spt.DataIn = SCSI_IOCTL_DATA_OUT;
  SCSIDataWithBuf.Spt.CdbLength = 12;
  SCSIDataWithBuf.Spt.Cdb[0] = UFI_WRITE_10;
  SCSIDataWithBuf.Spt.Cdb[1] = 0x00;
  SCSIDataWithBuf.Spt.Cdb[2] = (dwStartBlock & 0xFF000000) >> 24;
  SCSIDataWithBuf.Spt.Cdb[3] = (dwStartBlock & 0x00FF0000) >> 16;
  SCSIDataWithBuf.Spt.Cdb[4] = (dwStartBlock & 0x0000FF00) >> 8;
  SCSIDataWithBuf.Spt.Cdb[5] = (dwStartBlock & 0x000000FF);
  SCSIDataWithBuf.Spt.Cdb[6] = 0x00;
  SCSIDataWithBuf.Spt.Cdb[7] = (wBlocks & 0xFF00) >> 8;
  SCSIDataWithBuf.Spt.Cdb[8] = (wBlocks & 0x00FF);
  SCSIDataWithBuf.Spt.Cdb[9] = 0x00;
  SCSIDataWithBuf.Spt.Cdb[10] = 0x00;
  SCSIDataWithBuf.Spt.Cdb[11] = 0x00;

  ptr = pBuf;
  iCount = dwlength / SPTWB_DATA_LENGTH;
  if ((dwlength % SPTWB_DATA_LENGTH) > 0) iCount++;
  int iPos = 0;

  for (int i=0; i < iCount; i++)
  {
    SCSIDataWithBuf.Spt.Cdb[2] = (dwStartBlock & 0xFF000000) >> 24;
    SCSIDataWithBuf.Spt.Cdb[3] = (dwStartBlock & 0x00FF0000) >> 16;
    SCSIDataWithBuf.Spt.Cdb[4] = (dwStartBlock & 0x0000FF00) >> 8;
    SCSIDataWithBuf.Spt.Cdb[5] = (dwStartBlock & 0x000000FF);
    memset(SCSIDataWithBuf.ucDataBuf,0x00,SPTWB_DATA_LENGTH);
    if (dwlength >= SPTWB_DATA_LENGTH)
    {
      memcpy(SCSIDataWithBuf.ucDataBuf,ptr,SPTWB_DATA_LENGTH);
    }
    else
    {
      memcpy(SCSIDataWithBuf.ucDataBuf,ptr,dwlength);
    }
    bResult = DeviceIoControl(
        hDrive,
        IOCTL_SCSI_PASS_THROUGH,
        SCSIDataWithBuf,
        sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS),
        SCSIDataWithBuf,
        //length,
        sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS),
        ReturnLen,
        FALSE);
    if (bResult)
    {
      iPos = (i * 100)/iCount;
      if (m_pWaitUISetPosProc != NULL)
      {
        (m_pWaitUISetPosProc)(0,iPos);
      }
      ptr += SPTWB_DATA_LENGTH;
      dwStartBlock ++;
      dwlength -= SPTWB_DATA_LENGTH;
    }
    else
    {
      m_LastErrCode = GetLastError();
      break;
    }
  }
  return bResult;
}

 

posted @ 2013-06-30 22:44  IAmAProgrammer  阅读(2045)  评论(0编辑  收藏  举报