`运行 Visual C++ 6.0 打开 Driver Wizard 生成的工程文件,可看到在***Device 这个类中已经有了很多设备操作的处理函数,例如上电(OnDevicePowerUp)、休眠(OnDeviceSleep)、启动(OnDeviceStart)等,可以根据需要修改这些函数,如果没有特殊要求,可以保持默认设置,如图 6-62 所示。
另外还需要完成的工作就是对上面定义的 IO 控制接口函数进行处理,其功能就是建立一个厂商请求。由于本次设计的 USB 设备是一个加密设备,它不是类设备,所以会有一些特定的请求(厂商请求)。为了介绍厂商请求的实现方法,本系统用到了两个厂商请求:设置密码和获取密码。由 Driver Wizard 自动生成的驱动一般都已经包括了标准请求的建立,但是不会包括厂商请求的建立。厂商请求是在 IO 控制接口函数中建立的,即 Driver Wizard 第 11 步所定义的两个函数,建立厂商请求的函数主要是 BuildVendorRequest 函数,其格式如下:
- PURB BuildVendorRequest(
- PUCHAR TransferBuffer,
- ULONG TransferBufferLength,
- UCHAR RequestTypeReservedBits,
- UCHAR Request,
- USHORT Value,
- BOOLEAN bIn=FALSE,
- BOOLEAN bShortOk=FALSE,
- PURB Link=NULL
- UCHAR Index=0,
- USHORT Function=URB_FUNCTION_VENDOR_DEVICE,
- PURB pUrb=NULL
- );
其中需要开发人员注意的是前 6 个参数,其意义如下:
• PUCHAR TransferBuffe 数据缓冲。如果是数据输入,用于存储接收到的数据;如果是数据输出,则是待发送数据的数据源;如果没有数据传输,此参数可是为空(NULL)。• ULONG TransferBufferLength 发送或者接收数据的长度。
• UCHAR RequestTypeReservedBit 请求类型的位掩码,一般为零。
• UCHAR Request 请求代码。
• USHORT Value 即 USB 请求中的 wValue 位
• BOOLEAN bIn=FALSE 此参数为 TRUE 表示数据输出,反之则表示数据输入。
其余的参数可以保持默认。下面就从 USBSOFTLOCK_IOCTL_GET_PASSWORD_Handler 处理函数为例介绍一下 BuildVendorRequest 函数的用法,代码如下:
- NTSTATUS USBSoftLockDevice::USBSOFTLOCK_IOCTL_GET_PASSWORD_Handler(KIrp I)
- {
- NTSTATUS status = STATUS_SUCCESS;
- // 输出提示信息
- t << "Entering USBSoftLockDevice::USBSOFTLOCK_IOCTL_GET_PASSWORD_Handler, "
- << I << EOL;
- t << "IOctrlBuffer address is " << (LONG)(I.IoctlBuffer()) << EOL;
- t << "BufferedReadDest address is " << (LONG)(I.BufferedReadDest()) << EOL;
- t << "BufferedWriteSource address is " << (LONG)(I.BufferedWriteSource()) << EOL;
- t << "IoctlOutputBufferSize is " << (LONG)(I.IoctlOutputBufferSize()) << EOL;
- // 保存 8 字节密码的缓存
- UCHAR buffer[8];
- // 创建厂商请求,请求的代码是 REQUEST_GET_PASSWORD,数据长度为 8
- PURB pUrb = m_Lower.BuildVendorRequest(
- buffer, -- 数据缓冲
- PASSWORD_LENGTH, -- 数据长度
- 0, -- 保留
- REQUEST_GET_PASSWORD, -- 请求代码
- 0, -- 即 USB 请求的 wValue 字段
- TRUE -- TRUE 表示数据输入,反之则是数据输出
- );
- status = m_Lower.SubmitUrb(pUrb, NULL, NULL, OPERATION_TIMEOUT);
- // 判断返回值
- if (status == STATUS_SUCCESS) {
- t << "Received buffer is ";
- for (int i=0;i
- t << " " << buffer[i];
- }
- t << EOL;
- PUCHAR output_buffer = (PUCHAR)(I.IoctlBuffer());
- memcpy(output_buffer, buffer, PASSWORD_LENGTH);
- }
- else {
- }
- return status;
- }
完成厂商请求的编写之后,就可以进行驱动程序编译了。驱动编译默认有两种版本,即Win32 Checked 和 Win32 Free,其中前者表示调试版本,而后者表示发布版本,发布版本相对调试版本去掉了大部分调试信息,比较简化。编 译 驱 动 的 方 法 是 在 Visual C++ 中 打 开 Driver Studio 的 工 具 条 CompuwareDriverStudio,如图 6-63 所示。
选择合适的编译版本,再单击 Compuware DriverStudio 工具条的最后一个按钮即可。请注意不能使用 Visual C++本身的编译按钮进行驱动编译。编译成功,如果是 Win32 Free 版本,则会在工程目录的 sysobjfrei386 子目录下生成驱动文件 USBSoftLock.sys;如果是 Win32Checked 版本,驱动文件会在工程目录的 sysobjchki386 子目录下。成功编译驱动程序之后,将它和 Driver Studio 自动生成的.inf 文件(在工程目录下)放在同一个目录下,在查找驱动的时候指定这个目录就可以了。`