源码:
电脑插入U盘,为物理驱动器3
如下使用DeviceIOControl发送MSC类规定的SCSI通信指令中
读指令(0x28)
指定读0扇区,读1长度的扇区,一共长度为512字节
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <ntddscsi.h>
// 定义 SCSI 直通控制码,用于与 SCSI 设备进行通信
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
int main() {
try {
// 尝试打开指定的物理设备(这里假设是 U 盘)
HANDLE hDevice = CreateFile(
L"\\\\.\\PhysicalDrive2",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL
);
// 如果打开失败,输出错误信息并返回错误码
if (hDevice == INVALID_HANDLE_VALUE) {
std::cerr << "无法打开 U 盘设备。错误代码: " << GetLastError() << std::endl;
return 1;
}
// 定义 SCSI 直通结构,用于发送 SCSI 命令和接收结果
SCSI_PASS_THROUGH_DIRECT sptd = { 0 };
sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
sptd.CdbLength = 10; // SCSI Read(6) 命令的命令描述块(CDB)长度为 10 字节
sptd.DataIn = SCSI_IOCTL_DATA_IN; // 表示从设备读取数据
sptd.DataTransferLength = 512; // 假设扇区大小为 512 字节
sptd.TimeOutValue = 2; // 设置超时时间为 2 秒
sptd.DataBuffer = malloc(512); // 分配 512 字节的数据缓冲区
// 设置 SCSI Read(6) 命令的具体参数
sptd.Cdb[0] = 0x28; // SCSI Read(6) 命令码
sptd.Cdb[1] = 0x00; // 逻辑块地址高字节
sptd.Cdb[2] = 0x00; // 逻辑块地址中高字节
sptd.Cdb[3] = 0x00; // 逻辑块地址中低字节
sptd.Cdb[4] = 0x00; // 逻辑块地址低字节(扇区 1)
sptd.Cdb[5] = 0x00; // 传输长度高字节
sptd.Cdb[6] = 0x00; // 传输长度中高字节
sptd.Cdb[7] = 0x00; // 传输长度中低字节
sptd.Cdb[8] = 0x01; // 传输长度低字节(1 个块)
sptd.Cdb[9] = 0x00; // 控制字节
DWORD bytesReturned = 0;
// 调用 DeviceIoControl 函数发送 SCSI 命令并接收结果
BOOL result = DeviceIoControl(
hDevice,
IOCTL_SCSI_PASS_THROUGH_DIRECT,
&sptd,
sizeof(SCSI_PASS_THROUGH_DIRECT),
&sptd,
sizeof(SCSI_PASS_THROUGH_DIRECT),
&bytesReturned,
NULL
);
// 如果命令发送成功
if (result) {
// 输出成功信息和返回的字节数
std::cout << "SCSI 命令发送成功。" << bytesReturned << std::endl;
// 将返回的数据以十六进制形式打印出来
unsigned char* data = reinterpret_cast<unsigned char*>(sptd.DataBuffer);
// 遍历数据缓冲区,每 16 个字节换行输出
for (DWORD i = 0; i < 512; ++i) {
if (0 == i % 16) std::cout << "\n" << std::endl;
std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(data[i]) << " ";
}
std::cout << std::endl;
}
else {
// 如果命令发送失败,输出错误信息和错误码
std::cerr << "SCSI 命令发送失败。错误代码: " << GetLastError() << std::endl;
}
// 关闭设备句柄并释放数据缓冲区
CloseHandle(hDevice);
free(sptd.DataBuffer);
}
catch (const std::exception& e) {
// 如果发生异常,输出异常信息并返回错误码
std::cerr << "发生异常: " << e.what() << std::endl;
return 1;
}
return 0;
}
运行结果
遇到的问题:返回的可用长度一直是44,但是我强制输出512的长度时发现缓冲区的数据都是正确的;