使用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; }