Windows驱动开发WDM (16)- 完成例程 (重新获得IRP控制权)
来源:互联网 发布:python replace 正则 编辑:程序博客网 时间:2024/05/17 23:21
前一次(http://blog.csdn.net/zj510/article/details/8350184)学习了完成例程返回STATUS_SUCCESS的情况,也就是驱动调用IoCallDriver后不会再获得IRP。这次来看看再次获得IRP控制权的情况。
设置完成例程
先看看设置完成例程那里的代码:
IoCopyCurrentIrpStackLocationToNext(Irp);KEVENT event;KeInitializeEvent(&event, NotificationEvent, FALSE);//创建一个event对象。//通过第三个参数将event对象传递给完成例程IoSetCompletionRoutine(Irp, MyIoCompletion, &event, TRUE, TRUE, TRUE);status = IoCallDriver(pdx->NextStackDevice, Irp);if (status == STATUS_PENDING){//如果下层驱动是异步完成irp的话,就等待event被触发(完成例程会触发)//如果下层驱动是同步完成irp或者其他错误,那么就无需等待了。直接向上返回。KeWaitForSingleObject(&event,Executive,KernelMode ,FALSE,NULL);//等待完成例程触发这个事件,最后一个参数是NULL,表示无限等待status = Irp->IoStatus.Status;//获取下层驱动的irp状态}//获取内核模式下的地址,这个地址一定> 0x7FFFFFFFchar* outBuf = (char*)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);outBuf[1] = outBuf[2];//将第三个字节复制到第二个字节//虽然在底层驱动已经将IRP完成了,但是由于完成例程返回的是//STATUS_MORE_PROCESSING_REQUIRED,因此需要再次调用IoCompleteRequest!IoCompleteRequest (Irp, IO_NO_INCREMENT);
跟前一个版本相比,有3个分别:
1. 创建一个事件对象,初始化,并且在IoCallDriver后面等待这个事件;
2. 事件触发后,将输出缓冲的第三个字节赋值给第二个字节,也就是说过滤驱动再更改一下返回的内容;
3. 调用IoCompleteRequest再次完成IRP(因为完成例程返回了STATUS_MORE_PROCESSING_REQUIRED)
IoSetCompletionRoutine的第三个参数对应完成例程的第三个参数。也就是说我们可以传一些数据给完成例程。
VOID IoSetCompletionRoutine( _In_ PIRP Irp, _In_opt_ PIO_COMPLETION_ROUTINE CompletionRoutine, _In_opt_ PVOID Context, _In_ BOOLEAN InvokeOnSuccess, _In_ BOOLEAN InvokeOnError, _In_ BOOLEAN InvokeOnCancel);
完成例程代码
NTSTATUS MyIoCompletion(IN PDEVICE_OBJECT fdo, IN PIRP irp, IN PVOID context){KdPrint(("Enter MyIoCompletion\n"));//判断是否挂起返回,就是说下层驱动是挂起irp,然后再处理irp(异步irp)if(irp->PendingReturned){//设置完成例程那里,只有下层驱动返回pending状态才等待事件,那么我们//这里只需要挂起返回的时候才设置事件信号KeSetEvent((PKEVENT)context, IO_NO_INCREMENT, FALSE);}KdPrint(("Leave MyIoCompletion\n"));//返回STATUS_MORE_PROCESSING_REQUIRED,当前驱动将再次获得irp的控制权,//同时也需要再次调用IoCompleteRequest来完成irpreturn STATUS_MORE_PROCESSING_REQUIRED;}
跟前面的版本比较:
1. 当挂起返回的时候,给事件设置信号,这个事件对象是参数传进来的。
2. 返回STATUS_MORE_PROCESSING_REQUIRED
因为完成例程里面设置了信号,那么KeWaitForSingleObject就会返回。
测试代码:
跟前一个文章一样,相当的简单,就是起2个线程,发2个IRP请求:
// TestWDMDriver.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <windows.h>#include <process.h>#define DEVICE_NAME L"\\\\.\\HelloWDM"#define DEVICE_NAME2 L"\\\\.\\HelloWDM2"#define DEVICE_EX L"\\\\.\\HelloWDM_EX"void Test(void* pParam){int index = (int)pParam;//设置overlapped标志,表示异步打开HANDLE hDevice;hDevice = CreateFile(DEVICE_NAME,GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL);wprintf(L"CreateFile, name: %s, ret: %x\n", DEVICE_NAME, hDevice);if (hDevice != INVALID_HANDLE_VALUE){char inbuf[100] = {0};sprintf(inbuf, "hello world %d", index);char outbuf[100] = {0};DWORD dwBytes = 0;DWORD dwStart = GetTickCount();printf("input buffer: %s\n", inbuf);OVERLAPPED ol = {0};ol.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);BOOL b = DeviceIoControl(hDevice, CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_IN_DIRECT, FILE_ANY_ACCESS), inbuf, strlen(inbuf), outbuf, 100, &dwBytes, &ol);printf("DeviceIoControl thread %d, returns %d, last error: %d, used: %d ms, input: %s\n", index, b, GetLastError(), GetTickCount() - dwStart, inbuf);WaitForSingleObject(ol.hEvent, INFINITE);DWORD dwEnd = GetTickCount();//将输出buffer的数据和'm'亦或,看看是否能够得到初始的字符串。for (int i = 0; i < strlen(inbuf); i++){outbuf[i] = outbuf[i] ^ 'm';}printf("Verify thread %d, outbuf: %s, used: %d ms\n", index, outbuf, dwEnd - dwStart);CloseHandle(hDevice);}elseprintf("CreateFile failed, err: %x\n", GetLastError());}int _tmain(int argc, _TCHAR* argv[]){HANDLE t1 = (HANDLE)_beginthread(Test, 0, (void*)0);_beginthread(Test, 0, (void*)1);WaitForSingleObject(t1, INFINITE);printf("Test ends\n");return 0;}
看看输出结果:
可以看到原来输出是xello world 0和xello world 1,现在第二个字节变成l了。这是因为过滤驱动在下层驱动完成后,又再次更改了输出内容,就是将第三个字节赋值给第二个字节了。
代码:http://download.csdn.net/detail/zj510/4913259
目录1: 功能驱动,从控制面板里面安装
目录2: 过滤驱动,直接右键inf文件安装,同时再改一个注册表,参考http://blog.csdn.net/zj510/article/details/8332658
测试代码:一段简单的测试代码,起2个线程,发2个IRP请求。
WDK7600编译驱动,VS2008编译测试代码。
- Windows驱动开发WDM (16)- 完成例程 (重新获得IRP控制权)
- Windows驱动开发WDM (15)- 完成例程
- Windows驱动开发WDM (9)- StartIO例程(串行化处理IRP)
- Windows驱动开发WDM (7)- 异步IRP
- Windows驱动开发WDM (10)- StartIo取消例程
- 驱动开发(13)IRP 的异步完成和 CancelRoutine
- Windows驱动开发WDM (13)- 过滤驱动
- Windows驱动开发WDM (13)- 过滤驱动
- Windows 7驱动开发系列(四)--WDM模型介绍
- Windows驱动开发WDM (1) - 基本结构
- Windows驱动开发WDM (3)- 设备内存读写方式
- Windows驱动开发WDM (4)- 缓冲区方式例子
- Windows驱动开发WDM (6)- 中断请求级别
- Windows驱动开发WDM (8)- 内核同步对象
- Windows驱动开发WDM (2)- 一个简单的WDM驱动程序
- IRP 完成例程
- IRP的完成例程
- IRP 完成例程
- is_file file_exists的区别
- 外键和级联
- sql存储过程实例精讲
- Linux中用命令刪除所有.svn文件夾
- sql中游标的使用
- Windows驱动开发WDM (16)- 完成例程 (重新获得IRP控制权)
- [MySQL]MySQL Error 1130 Host 'localhost' is not allowed to connect to this MySQL server
- Android 混淆注意事项
- 体会函数参数传递
- Android ANR
- CSS3 HTML5实例二(图形化边界)
- 想成为Java高手的25个学习目标
- .mc文件
- poj 2485