DeviceIoControl 用于和应用层和驱动层之间的数据传送。是应用层调用驱动文件(SYS)中的控制请求的重要方法。
今天在使用DeviceIoControl 调用一个自行编写的驱动程序的使用返回值总是FALSE,使用GetLastError获得错误码为87
这个错误码对应的错误是:参数不正确。可是应用层的参数怎么看都没有问题。最终发现是驱动层的编码出现了问题。
在驱动层的分发函数中,在指定的控制请求分支,完成自定义的请求业务逻辑之后应该调用:
status=irp->IoStatus.Status;
来返回一个错误码,然后调用
IoCompleteRequest(irp,IO_NO_INCREMENT);
来结束对控制请求的处理
而发生错误的处理方法使用了
IoCallDriver(s_nextobj,irp);
将请求继续传递给了后续的驱动对象,这是系统的驱动对象
由于这个控制请求是自定义的,系统的驱动对象中没有这个处理分支,而一般的处理方法就是,对没有的分支返回参数错误。即是控制请求这个参数传递错误。
由此可以总结出在驱动层编写自定义的消息请求时,处理完成之后不能再路由到系统的驱动中,因为对控制请求这个参数的判断是以最后一个处理来判断的。使用IoCallDriver(s_nextobj,irp);不但在自己编写的代码中处理白做了,返回了错误码,同时也接受不到返回信息。因为这里对irpsp的处理被后续的处理覆盖了。
在来重新审视:
BOOL WINAPI DeviceIoControl(
__in HANDLE hDevice,
__in DWORD dwIoControlCode,//自定义的控制码就是这一项
__in LPVOID lpInBuffer,
__in DWORD nInBufferSize,
__out LPVOID lpOutBuffer,
__in DWORD nOutBufferSize,
__out LPDWORD lpBytesReturned,
__in LPOVERLAPPED lpOverlapped
);
这里遇到的问题只是针对参数dwIoControlCode的错误的解决,这个问题也比较隐蔽。
正确的调用当然还要保证其它的所有的参数都是正确的。在调试的时候要特别关注错误码,和对代码进行例行的分析。
附,我遇到这个问题的驱动程序的分发函数的代码,是正在调试中的代码,所以比较乱:
这里是一个串口的Filter驱动,对读写请求都要路由到系统,而对于自定义的消息一定要调用IoCompleteRequest完成请求
NTSTATUS ccpDispatch(PDEVICE_OBJECT device,PIRP irp) { PIO_STACK_LOCATION irpsp=IoGetCurrentIrpStackLocation(irp); NTSTATUS status; ULONG len; ULONG j; PUCHAR buffer=NULL; ULONG dwInputBufferLength; ULONG dwOutputBufferLength; PVOID pvIOBuffer; pvIOBuffer = irp->AssociatedIrp.SystemBuffer; dwInputBufferLength = irpsp->Parameters.DeviceIoControl.InputBufferLength; dwOutputBufferLength = irpsp->Parameters.DeviceIoControl.OutputBufferLength; switch (irpsp->MajorFunction) { case IRP_MJ_POWER: PoStartNextPowerIrp(irp); IoSkipCurrentIrpStackLocation(irp); return PoCallDriver(s_nextobj,irp); case IRP_MJ_WRITE: len=irpsp->Parameters.Write.Length; if (irp->MdlAddress!=NULL) { buffer=(PUCHAR)MmGetSystemAddressForMdlSafe(irp->MdlAddress,NormalPagePriority); } else { buffer=(PUCHAR)irp->UserBuffer; } if (buffer==NULL) { buffer=(PUCHAR)irp->AssociatedIrp.SystemBuffer; } for(j=0;j