问题描述
我尝试通过IOCTL命令访问USB扫描仪。这是在Windows 7上。我没有处理IOCTL编码之前,所以我首先尝试以下片段基于我可以找到与快速搜索。
I am trying to access a USB scanner through the IOCTL commands. This is on Windows 7. I did not deal with IOCTL coding before, so I first tried the following snippet based on what I could find with a quick search.
#include "stdafx.h"
#include <stddef.h>
#include <Windows.h>
#include <ntddscsi.h>
#include <usbscan.h>
typedef struct
{
SCSI_PASS_THROUGH spt;
BYTE sense[18];
BYTE data[36];
} SPTSD;
LPTSTR ErrorMessage(DWORD error)
{
LPTSTR errorText = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&errorText,
0,
NULL);
return errorText;
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE h = CreateFile(L"\\\\.\\Usbscan0", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != h)
{
SPTSD sptsd={0};
sptsd.spt.Length = sizeof (sptsd.spt);
sptsd.spt.SenseInfoLength = sizeof(sptsd.sense);
sptsd.spt.DataTransferLength = sizeof(sptsd.data);
sptsd.spt.SenseInfoOffset = offsetof (SPTSD, sense);
sptsd.spt.DataBufferOffset = offsetof (SPTSD, data);
sptsd.spt.TimeOutValue = 30;
sptsd.spt.DataIn = SCSI_IOCTL_DATA_IN;
sptsd.spt.CdbLength = 6;
sptsd.spt.Cdb[0] = 0x12; // SCSI INQUIRY command
sptsd.spt.Cdb[1] = 0;
sptsd.spt.Cdb[2] = 0;
sptsd.spt.Cdb[3] = 0;
sptsd.spt.Cdb[4] = sizeof(sptsd.data);
sptsd.spt.Cdb[5] = 0;
DWORD dwReturnedBytes;
BOOL b;
b = DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH, &sptsd, sizeof(sptsd), &sptsd, sizeof(sptsd), &dwReturnedBytes, NULL);
if (b == 0)
{
LPTSTR errortext = ErrorMessage(GetLastError());
wprintf(L"DeviceIoControl(IOCTL_SCSI_PASS_THROUGH-INQUIRY) failed with error %d : %s\r\n", GetLastError(), errortext);
LocalFree(errortext);
}
else
{
wprintf(L"DeviceIoControl(IOCTL_SCSI_PASS_THROUGH-INQUIRY) succeeded\r\n");
for (int i=0; i<dwReturnedBytes; i++)
{
wprintf(L"%02x ", sptsd.data[i]);
}
wprintf(L"\r\nEnd of returned data\r\n");
}
DEVICE_DESCRIPTOR dd;
b = DeviceIoControl(h, IOCTL_GET_DEVICE_DESCRIPTOR, &dd, sizeof(dd), &dd, sizeof(dd), &dwReturnedBytes, NULL);
if (b == 0)
{
LPTSTR errortext = ErrorMessage(GetLastError());
wprintf(L"DeviceIoControl(IOCTL_GET_DEVICE_DESCRIPTOR) failed with error %d : %s\r\n", GetLastError(), errortext);
LocalFree(errortext);
}
else
{
wprintf(L"DeviceIoControl(IOCTL_GET_DEVICE_DESCRIPTOR) succeeded\r\n");
wprintf(L"VendorId = %x, ProductId = %x, Version = %x\r\n", dd.usVendorId, dd.usProductId, dd.usBcdDevice);
wprintf(L"End of returned data\r\n");
}
CloseHandle(h);
}
return 0;
}
我尝试32位和64位版本的Windows 7,结果在两者上是一样的(错误50:不支持请求。)。有趣的是,第二个DeviceIoControl调用工作并返回设备的VID / PID以及固件版本。
I tried both 32-bit and 64-bit versions of Windows 7 but the result is the same on both (error 50 : The request is not supported.). Interestingly, second DeviceIoControl call works and returns the VID/PID of the device, along with the firmware version.
根据错误消息,我认为这个IOCTL不是支持的。但是,我查看它,发现这个IOCTL代码是强制性的所有设备,所以必须有一些我做错了。如何修改此代码以使INQUIRY命令成功?
Based on the error message, I would think this IOCTL is not supported. However, I looked into it and found out that this IOCTL code is mandatory for all devices, so there must be something I am doing wrong. How should this code be modified so that the INQUIRY command will succeed?
推荐答案
根据,这些IOCTL代码被USB总线的内核模式静态图像驱动程序识别。
According to http://msdn.microsoft.com/en-us/library/ff548569%28v=vs.85%29.aspx, these IOCTL codes are recognized by the kernel-mode still image driver for USB buses.
- IOCTL_CANCEL_IO
- IOCTL_GET_PIPE_CONFIGURATION
- IOCTL_GET_USB_DESCRIPTOR
- IOCTL_GET_VERSION
- IOCTL_READ_REGISTERS
- IOCTL_RESET_PIPE
- IOCTL_SEND_USB_REQUEST
-
- IOCTL_SET_TIMEOUT
- IOCTL_WAIT_ON_DEVICE_EVENT IOCTL_WRITE_REGISTERS
- IOCTL_CANCEL_IO
- IOCTL_GET_CHANNEL_ALIGN_RQST
- IOCTL_GET_DEVICE_DESCRIPTOR
- IOCTL_GET_PIPE_CONFIGURATION
- IOCTL_GET_USB_DESCRIPTOR
- IOCTL_GET_VERSION
- IOCTL_READ_REGISTERS
- IOCTL_RESET_PIPE
- IOCTL_SEND_USB_REQUEST
- IOCTL_SET_TIMEOUT
- IOCTL_WAIT_ON_DEVICE_EVENT IOCTL_WRITE_REGISTERS
任何其他IOCTL代码都应通过。这解释了为什么尝试使用上面的代码发送INQURY命令不起作用。
My understanding is that any other IOCTL code should be sent via IOCTL_SEND_USB_REQUEST control code. This explains why trying to send a INQURY command using the above code does not work.
编辑:这只是使用发送INQUIRY命令和来读取响应。但是,似乎还有一个我不明白的问题:设备需要一个额外的字节后的INQUIRY命令的6个字节发送响应。否则,ReadFile将只返回一个字节(0x3)。如果我想知道这里发生了什么,我会再次更新此回复。
It was simply a matter of using WriteFile to send the INQUIRY command and ReadFile to read the response. However, there seems an additional issue that I do not understand: The device wants an extra byte after the 6 bytes of the INQUIRY command to send the response. Otherwise, ReadFile will only return a single byte (0x3). I will update this reply again if I figure out what is happening here.
这篇关于DeviceIoControl for SCSI INQUIRY命令返回错误50的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!