阅读:2157回复:5
总结应用和驱动之间用事件通讯的办法
1. 驱动中IoCreateNotificationEvent,KeClearEvent
应用中OpenEvent(SYNCHRONIZE, FALSE, EVENT_NAME) 这样,只能在应用中WaitForSingleObject,而不能SetEvent,ResetEvent 驱动中可以KeSetEvent,(而且必须紧接着KeClearEvent,因为在应用中不能修改核心态创建的对象的状态,只能在这个时候清除状态 了),即只能由驱动通知应用,在某些应用只需要等待通知的场合足够了,如应用等待数据准备好的通知,这时可以在中断处理函数中设置事件有信号 注意,OpenEvent第一个参数不能为EVENT_ALL_ACCESS,因为应用没有这么大权限操作在系统上下文创建的事件 2.在驱动中创建事件,并把时间句柄传给应用,应用不必OpenEvent。应用程序可以随意set,reset事件,这样可以和驱动中的系统线程进行同步 这种方法的前提条件是,event是在应用的进程上下文(在系统上下文创建的话就不可以)创建,并传给应用的,比如可以在某个IOCtl分支中创建事件并传给应用。 解释:在使用EVENT的PROCESS context中创的HANDLE就在这个进程的句柄表里,经检验没有权限限制,可以由应用直接使用;而在system context中创建的HANDLE当然就在SYSTEM进程里啦,若单单传句柄值给应用,而句柄表里根本就没有对应的句柄,当然不成功了。 代码如下 驱动中: void ppppp(PVOID event) { KeWaitForSingleObject((PKEVENT)event,Executive,UserMode,0,0); //......验证处 } ...... WCHAR wEventNameBuf[]=L"\\BaseNamedObjects\\SharedEvent"; UNICODE_STRING uEventName; PKEVENT pEvent; HANDLE hEvent,hThread; ...... case IOCTL_******: RtlInitUnicodeString(&uEventName,wEventNameBuf); pEvent = IoCreateNotificationEvent(&uEventName,&hEvent); KeResetEvent(pEvent); RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,&hEvent,4); PsCreateSystemThread(&hThread,THREAD_ALL_ACCESS,0,0,0,ppppp,pEvent); 应用中: if(!DeviceIoControl(hDevice,IOCTL_******,0,0,&Handle,4,&Bytes,0)) MessageBox("DeviceIo Error!"); esle{ wsprintf(str,"%x,%x,%x",hDevice,Bytes,Handle); MessageBox(str); if(!SetEvent((HANDLE)Handle)) ...... } 会看到,点击MessageBox OK后ppppp的确继续执行了。 3.在应用中创建事件,然后通过ioctl传给驱动,驱动中ObReferenceObjectByHandle来引用该事件对象。 这样应用和驱动中都可以检查和修改事件状态。 应用程序: HANDLE m_hCommEvent = CreateEvent(NULL, false, false, NULL); // download event object to device driver, // m_hCommDevice is the device object DeviceIoControl(m_hCommDevice, IO_REFERENCE_EVENT, (LPVOID) m_hCommEvent, 0, NULL, 0, dwReturn, NULL); 在需要的地方等待 while(true) { WaitForSingleObject(m_hCommEvent, INFINITE); // After this function, the event is set to // non signaled. Get information and deal with it. } 驱动程序: case IO_REFERENCE_EVENT: hEvent = (HANDLE) irpStack-> Parameters.DeviceIoControl.Type3InputBuffer; status = ObReferenceObjectByHandle(hEvent, GENERIC_ALL, NULL, KernelMode, &gpEventObject, &objHandleInfo); the gpEventObject is a PRKEVENT object, so we can use KeEventXXX and KeWaitForXXX to operate it. 当事件发生时,置信号 KeSetEvent(gpEventObject, 0, FALSE); 当不再需要事件对象时: case IO_DEREFERENCE_EVENT: if(gpEventObject) ObDereferenceObject(gpEventObject); |
|
沙发#
发布于:2010-05-12 11:45
感谢楼主的指教!请问如果我想在驱动中通知应用程序一个事件,并递交相应的数据,等应用程序处理完该事件后再返回驱动程序继续执行后面的代码,这样的功能应该怎样设计呢?
|
|
板凳#
发布于:2010-05-13 09:22
回 1楼(modernrabbit) 的帖子
我的设计方案是在应用层和驱动层个设置一个事件 这样就可以等应用程序处理完该事件后再返回驱动程序继续执行后面的代码 但是在驱动层一定要注意IRQL级别的 DISPATCH_LEVEL级别下不允许中断 这样的话你可以把驱动中的数据放入一个队列 在线程里面处理队列里面的数据 这样可以实现你想要的功能 |
|
地板#
发布于:2010-05-13 15:44
回 2楼(vipfengxiao) 的帖子
那是不是就意味着需要两个事件,一个用于驱动通知应用,驱动通知完以后就中断,等待应用发给驱动的另一个事件,我的理解对不对呢? |
|
地下室#
发布于:2010-05-13 16:08
回 2楼(vipfengxiao) 的帖子
另外补充一下,我是基于Passthru中间层驱动改写的一个过滤驱动,文档上说NDIS的回调函数都是工作在DISPATCH级,是不是意味着就不能无限等待KeWaitForSingleObject了呢? |
|
5楼#
发布于:2010-05-13 20:59
回 4楼(modernrabbit) 的帖子
恩 DISPATCH级是不能中断的 如果中断了你的机器就要over了 你可以把接收到的数据放在自己创建的一个线程里面在线程里面向上抛数据 接收函数里面不处理 |
|