讨论WDM驱动程序和应用程序的通信方法

时间:2021-08-13 19:50:07
我现在所实现的驱动程序和应用程序的通信方法:
1.用注册表.通过检测注册表的内容可以实现此目的.缺点是DRIVER在读写注册表受到IRQL的限制.
2.通过磁盘文件.缺点是DRIVER在读写文件受到IRQL的限制,共享冲突.
3.用应用程序DeviceIoControl.通过设备链接名来呼叫驱动程序

我现在所想到的驱动程序和应用程序的通信方法:
1.信号量,互斥量.难点是如何传递较多的信息
2.共用内存.内核态和用户态内存地址如何相互应射


抛砖引玉,如果你有好的解决方法或好的想法不妨说出来,大家讨论讨论,欢迎UP.

30 个解决方案

#1


我觉得你说的不是很确切,但是我自己知道得也不是很确切,所以不能胡说,但是等我查查资料再说。

#2


欢迎大家畅所欲言!

#3


除非传送大文件,否则没有deviceiocontrol做不到。



你提这些问题让我好迷茫,不知道你是如何写出你的driver???,你的driver不是有IOCTL吗?,它不是有个属性,是缓冲还是direct io.


好好参考OSR的那篇文章,国人怎么不懂得search!!!!

#4


to  vcmfc(【痛苦的虫虫】) 
首先谢谢你的捧场!
如果用APP实时监控DRIVER,看是否有数据返回,你怎么做呢?
1.循环用deviceiocontrol查询,driver不管是否有数据都立即返回.这样会大量消耗CPU时间.如果在调用deviceiocontrol的循环内用SLEEP或SwitchToThread等函数,却又失去实时性.
2.用deviceiocontrol,driver有数据立即返回,没有数据时PENDING IRP等数据时返回.这样APP在PENDING IRP时不能退出,即使用WINDOWS任务管理器也无法强制退出,系统无法正常关机.
3.用写注册表的方法.DRIVER在DISPATCH_LEVEL不能读写注册表.
4......还没想出来

请教vcmfc(【痛苦的虫虫】) ,你建议用哪一种方法?应该不会是第4种吧!
另外你有没有读过Walter Oney的书,都读过哪几本?

#5


欢迎"确实"在做驱动程序的同行发表高见!

#6


不用实现,不要忘了,DeviceIoControl不是有个屁参数让你传递事件,实在不行,就分两次,第一次,你APP创建一个event,将句柄传入driver,driver里保存,当driver 需要通知APP,激活事件,app的线程就wait这个事件,一激活,就干活。

#7


1.2是最土的方法。


你的driver会在DISPATCH_LEVEL以上,你是什么驱动??,什么情况下做什么事?

#8


我想不会有人傻到用1、2的方法吧?
觉得一般都是用event,app开个线程等。或共享内存。
registry在某些场合也挺有用的。比如app和driver还没有建立联系的时候,就可以通过registry来传递一些简单的数据。

#9


“不用实现,不要忘了,DeviceIoControl不是有个屁参数让你传递事件,实在不行,就分两次,第一次,你APP创建一个event,将句柄传入driver,driver里保存,当driver 需要通知APP,激活事件,app的线程就wait这个事件,一激活,就干活。”
又学到一招,谢谢vcmfc.

#10


to vcmfc(【痛苦的虫虫】) 
  
  "不用实现,不要忘了,DeviceIoControl不是有个屁参数让你传递事件,实在不行,就分两次,第一次,你APP创建一个event,将句柄传入driver,driver里保存,当driver 需要通知APP,激活事件,app的线程就wait这个事件,一激活,就干活。"

先谢谢了,这个方法我开始提问时就想到了,但一直没有实现.
app产生的event是handle,但DRIVER里用的是PRKEVENT,两个声明完全不同,你是怎么做的?是用DDK写APP吗?这样又会引起编程不必要的难度.
  

to ArthurTu(猫王) 
"我想不会有人傻到用1、2的方法吧?
觉得一般都是用event,app开个线程等。或共享内存。
registry在某些场合也挺有用的。比如app和driver还没有建立联系的时候,就可以通过registry来传递一些简单的数据。"

关于共享内存你是如何实现的?我应该在DISPATCH_LEVEL如何访问PAGEG MEMORY

  
 

 

#11




你不会强制转换??????

#12


最后说:

 search osr的文章,里面有两篇就是专门讲这个主题的,大哥,好好看一下好吗!!!!!

#13


vcmfc和ArthurTu两位大虾,我在驱动开发网也经常看到你们,想问一个私人问题,你们现在在什么类型的公司工作阿,待遇如何?呵呵呵呵呵

#14


vcmfc和ArthurTu两位,我在驱动开发网也经常看到你们,想问一个私人问题,你们现在在什么类型的公司工作阿,待遇如何?呵呵呵呵呵
-------------------------------------------
刚刚下岗。。。


我应该在DISPATCH_LEVEL如何访问PAGEG MEMORY
-------------------------------------------
不能

#15


to vcmfc(【痛苦的虫虫】)

"你不会强制转换??????"



强制转换当然可以,但会引起蓝屏(0X0E).你是怎么做的,不妨把相关的代码贴出来,大家看看你说的是否正确.
另外你所说的OSR的文章是不是这一篇"Sharing Memory Between Drivers and Applications".这篇文章所说的方法有一些局限性.

我们所讨论的问题是:
APP应能实时的从DRIVER取得数据(如果DRIVER有数据上传),但DRIVER上传的数据在时间和数量上是不确定的.DRIVER工作在DISPATCH_LEVEL.要求占用系统资源尽量少.APP开启的时候不能阻止系统正常重启或关机.


  
 

#16


to ArthurTu(猫王) :

我应该在DISPATCH_LEVEL如何访问PAGEG MEMORY
-------------------------------------------
不能

那么你所谓的共享内存是如何实现的?

#17


我所知道的也就是"Sharing Memory Between Drivers and Applications"。不知有什么局限性不能满足你的要求?

我们所讨论的问题是:
APP应能实时的从DRIVER取得数据(如果DRIVER有数据上传),但DRIVER上传的数据在时间和数量上是不确定的.DRIVER工作在DISPATCH_LEVEL.要求占用系统资源尽量少.APP开启的时候不能阻止系统正常重启或关机.
------------------------
用event的方法不能满足你的要求吗?够了吧?

“DRIVER工作在DISPATCH_LEVEL”,什么driver,居然能一直工作在dispatch level?“实时的从DRIVER取得数据”,这个“实时”怎么定义?

#18


to ArthurTu(猫王)
用event的方法,能贴出相关代码吗?
app产生的event是handle,但DRIVER里用的是PRKEVENT,两个声明完全不同.强制转换当然可以,但会引起蓝屏(0X0E).你是怎么做的??
洗耳恭听!!

#19


工作在dispatch level的DRIVER很多,如声卡,鼠标,键盘,硬盘,光驱....
即使一般的DRIVER,工作在dispatch level的情况也很多,如DPC,COMPLETEROUTE,SPINLOCK...

#20


为什么你的那些处理一定要在dispatch,DPC回调,workitem等,都可以延期到pass level,全在pass level,如果是在dispatch,APP如何访问你?,在如此高的IRQL,APP根本就不可能访问。


OSR:2002:

Sharing is Caring -- Sharing Events Between Kernel-User Mode 


用心搜索..............


你有没有看过全部的inside nt????,至少我全看过,有些虽然不懂,但有个印象,一需要我就知道在哪儿查...........


不好意思,口气是不太友好,主要近来太忙了,问题一大堆,烦死了..........


在北京.................

#21


我是说“一直”工作在dispatch level的DRIVER。

Probably the simplest mechanism is sharing one or more named events.  When an application calls CreateEvent(), the named event is automatically created in the Object Manager’s BaseNamedObjects directory.  A driver can open, and share, these event objects by calling IoCreateNotificationEvent(), and specifying the same name as was specified in user mode (except, of course, specifying “\BaseNamedObjects” as the directory).

#22


ArthurTu(猫王) &  vcmfc(【痛苦的虫虫】) 
谢谢你的指点,因为需要更多的人关注"WDM驱动程序和应用程序的通信方法"话题,所以重新开贴给分,请到
http://expert.csdn.net/Expert/topic/1609/1609281.xml?temp=.342663
取分.

#23


我所做的DRIVER基本上是鼠标驱动,鼠标驱动的回调函数(用于取数据)是工作在DISPATCH LEVEL.由于我的DRIVER不仅把数据传给系统,而且要传给我们特定的服务程序(USER MODE),
因此,服务程序不能一直打开设备等待数据,而需要实时的通信方式,占用系统资源少,不能影响到系统的正常运做.

其实上面的问题我已经解决,但总觉得不够好,所以开贴来让大家讨论这么一个普遍性的问题!
感谢大家发表高见,我会随时开贴给分.

#24


因此,服务程序不能一直打开设备等待数据,而需要实时的通信方式,占用系统资源少,不能影响到系统的正常运做.

1、不清楚你的服务程序是干什么,非要打开设备才能接收数据?
2、“实时”?到哪种程度?Windows下谈不上什么实时。
3、2K下user mode的app不大会影响OS的运作,出错了大不了OS就kill他,driver不出错就好。你是说“APP开启的时候不能阻止系统正常重启或关机.”?

#25


1、EVENT和PKEVENT的转换。

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);

2、我曾经做过进程启动实时监视的程序,我是这样做的:

[1]、在WDM中建立一个具有名字的Event对象,如下:

    //
    // 建立通知事件
    //
    UNICODE_STRING NotifyEventName;
    HANDLE hTempEvent;

    RtlInitUnicodeString(&NotifyEventName,L"\\BaseNamedObjects\\ProcMonEvent");
    pDeviceExtension->ProcessEvent = IoCreateNotificationEvent(&NotifyEventName,&hTempEvent);
    KeClearEvent(pDeviceExtension->ProcessEvent);

[2]、在App中使用OpenEvent()来打开那个Event,并建立一个新的线程来监视那个Event,如下:

//
// StartMonitor
//
bool __fastcall TThreadMonitor::StartMonitor()
{
    //
    // Stop Monitor first
    //
    if(IsMonitoring)
    {
        StopMonitor();
    }    

    hEvent = OpenEvent(SYNCHRONIZE,false,EventName.c_str());
    if(hEvent == NULL)
    {
        return false;
    }    

    ///
    DWORD dwTempThreadId;

    hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)MonitorThread,
                           (LPVOID)this,0,&dwTempThreadId
                           );
                           
    IsMonitoring = (hThread != NULL) ;

    return IsMonitoring;
}
//---------------------------------------------------------------------------
//
// 有新的进程建立时,WDM触发事件。
//
DWORD WINAPI MonitorThread(TThreadMonitor *CurrentThreadMonitor)
{
    DWORD dwResult;

    while(true)
    {
        dwResult = WaitForSingleObject(CurrentThreadMonitor->hEvent,INFINITE);

        //    
        // 停止监视
        //
        if(!CurrentThreadMonitor->IsMonitoring)
        {
            break;
        }    

        if(dwResult == WAIT_OBJECT_0)
        {
            CurrentThreadMonitor->ProcessMonitor->ProcessCreated();
        }
    }

    //
    // 在这里释放资源
    //
    CloseHandle(CurrentThreadMonitor->hEvent);
    CloseHandle(CurrentThreadMonitor->hThread);

    CurrentThreadMonitor->hEvent = NULL;
    CurrentThreadMonitor->hThread = NULL;

    return 1;
}
//---------------------------------------------------------------------------


[3]、当WDM需要通知那个APP时,它调用KeSetEvent()触发事件,这样APP也就得到通知了,可以做一些事了........这样算实时吗??????????

#26


slwqw2(亚洲之鹰)
你的出现应该可以少浪费好多口水:)

#27


:)

#28


To ArthurTu(猫王) 
1、不清楚你的服务程序是干什么,非要打开设备才能接收数据?
------------------------------------------------------------------------
对于从DRIVER读取数据或PENDING时,需要打开设备


2、“实时”?到哪种程度?Windows下谈不上什么实时。
--------------------------------------------------------------------------
要求像鼠标和键盘一样实时

3、2K下user mode的app不大会影响OS的运作,出错了大不了OS就kill他,driver不出错就好。你是说“APP开启的时候不能阻止系统正常重启或关机.”?
----------------------------------------------------------------------------
如果DeviceIoControl在系统关机时不能返回(例如PENDING IRP),则系统不能正常关机.

 

#29


谢谢  slwqw2(亚洲之鹰) 

你说的方法很好,谢谢!
另外如何实现在关闭设备后,还能与DRIVER通信,例如共享内存.

#30


转帖
: LornWolf(绝地苍狼) ( )  
 
  影射核心内存到用户模式进程

映射由核心模式分配的缓冲到一个特定用户进程的虚拟地址空间,这种方法非常简单。并能使驱动程序保留对这种内存最大控制权。

驱动程序可以使用任意标准的方法来分配要共享的缓冲,如果没有特殊的要求并且大小适度,可以将它分配在非分页池中。

驱 动 程 序 使 用 IoAllocateMdl() 分 配 一 个 MDL 来 描 述 这 个 缓 冲, 然 后 调 用MmBuildMdlForNonPagedPool()。这个函数修改MDL以描述内核模式中一个非分页内存区域。
当用来描述共享缓冲的MDL建立起来以后,驱动程序现在可以准备将缓冲映射到用户进程的地 址空间了,由MmMapLockedPagesSpecifyCache() 这个函数完成。

你必须要在你想要映射共享缓冲的进程上下文环境中调用MmMapLockedPagesSpecifyCache(),并且指定AccessMode参数为UserMode。这个函数返回由MDL映射的用户态虚拟地址。 驱动程序可以把这个值作为用户程序发送IOCTL请求时的返回值返回给用户程序。

PVOID
CreateAndMapMemory()
{
    PVOID buffer;    
    PMDL  mdl;
    PVOID userVAToReturn;

    //
    // Allocate a 4K buffer to share with the application
    //

    buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'MpaM');

    if(!buffer) {
        return(NULL);
    }

    //
    // Allocate and initalize an MDL that describes the buffer
    //

    mdl = IoAllocateMdl(buffer,

                        PAGE_SIZE,

                        FALSE,

                        FALSE,

                        NULL);

    if(!mdl) {
        ExFreePool(buffer);
        return(NULL);
    }

    //
    // Finish building the MDL -- Fill in the "page portion" 
    //

    MmBuildMdlForNonPagedPool(mdl);

#if NT_40

    //
    // Map the buffer into user space
    //
    // NOTE: This function bug checks if out of PTEs
    //

    userVAToReturn = MmMapLockedPages(mdl, UserMode);

#else

    //
    // The preferred V5 way to map the buffer into user space
    //

    userVAToReturn = 

         MmMapLockedPagesSpecifyCache(mdl,          // MDL

                                      UserMode,     // Mode

                                      MmCached,     // Caching

                                      NULL,         // Address

                                      FALSE,        // Bugcheck?

                                      NormalPagePriority); // Priority

    //
    // If we get NULL back, the request didn't work.
    // I'm thinkin' that's better than a bug check anyday.
    //

    if(!userVAToReturn) {
        IoFreeMdl(mdl);
        ExFreePool(buffer);
        return(NULL);
    }


#endif

    //
    // Store away both the mapped VA and the MDL address, so that 
    // later we can call MmUnmapLockedPages(StoredPointer, StoredMdl)
    //

    StoredPointer = userVAToReturn;
    StoredMdl = mdl;

    DbgPrint("UserVA = 0x%0x\n", userVAToReturn);

    return(userVAToReturn);



在映射完共享缓冲以后,可以在任意进程上下文环境中对它进行访问,并且可以在提升的IRQL*问(因为是在非分页内存中)。

如果使用这种方法,有一个情况必须注意:你必须保证驱动程序提供一个方法在用户程序退出的时候来取消映射。

 

#1


我觉得你说的不是很确切,但是我自己知道得也不是很确切,所以不能胡说,但是等我查查资料再说。

#2


欢迎大家畅所欲言!

#3


除非传送大文件,否则没有deviceiocontrol做不到。



你提这些问题让我好迷茫,不知道你是如何写出你的driver???,你的driver不是有IOCTL吗?,它不是有个属性,是缓冲还是direct io.


好好参考OSR的那篇文章,国人怎么不懂得search!!!!

#4


to  vcmfc(【痛苦的虫虫】) 
首先谢谢你的捧场!
如果用APP实时监控DRIVER,看是否有数据返回,你怎么做呢?
1.循环用deviceiocontrol查询,driver不管是否有数据都立即返回.这样会大量消耗CPU时间.如果在调用deviceiocontrol的循环内用SLEEP或SwitchToThread等函数,却又失去实时性.
2.用deviceiocontrol,driver有数据立即返回,没有数据时PENDING IRP等数据时返回.这样APP在PENDING IRP时不能退出,即使用WINDOWS任务管理器也无法强制退出,系统无法正常关机.
3.用写注册表的方法.DRIVER在DISPATCH_LEVEL不能读写注册表.
4......还没想出来

请教vcmfc(【痛苦的虫虫】) ,你建议用哪一种方法?应该不会是第4种吧!
另外你有没有读过Walter Oney的书,都读过哪几本?

#5


欢迎"确实"在做驱动程序的同行发表高见!

#6


不用实现,不要忘了,DeviceIoControl不是有个屁参数让你传递事件,实在不行,就分两次,第一次,你APP创建一个event,将句柄传入driver,driver里保存,当driver 需要通知APP,激活事件,app的线程就wait这个事件,一激活,就干活。

#7


1.2是最土的方法。


你的driver会在DISPATCH_LEVEL以上,你是什么驱动??,什么情况下做什么事?

#8


我想不会有人傻到用1、2的方法吧?
觉得一般都是用event,app开个线程等。或共享内存。
registry在某些场合也挺有用的。比如app和driver还没有建立联系的时候,就可以通过registry来传递一些简单的数据。

#9


“不用实现,不要忘了,DeviceIoControl不是有个屁参数让你传递事件,实在不行,就分两次,第一次,你APP创建一个event,将句柄传入driver,driver里保存,当driver 需要通知APP,激活事件,app的线程就wait这个事件,一激活,就干活。”
又学到一招,谢谢vcmfc.

#10


to vcmfc(【痛苦的虫虫】) 
  
  "不用实现,不要忘了,DeviceIoControl不是有个屁参数让你传递事件,实在不行,就分两次,第一次,你APP创建一个event,将句柄传入driver,driver里保存,当driver 需要通知APP,激活事件,app的线程就wait这个事件,一激活,就干活。"

先谢谢了,这个方法我开始提问时就想到了,但一直没有实现.
app产生的event是handle,但DRIVER里用的是PRKEVENT,两个声明完全不同,你是怎么做的?是用DDK写APP吗?这样又会引起编程不必要的难度.
  

to ArthurTu(猫王) 
"我想不会有人傻到用1、2的方法吧?
觉得一般都是用event,app开个线程等。或共享内存。
registry在某些场合也挺有用的。比如app和driver还没有建立联系的时候,就可以通过registry来传递一些简单的数据。"

关于共享内存你是如何实现的?我应该在DISPATCH_LEVEL如何访问PAGEG MEMORY

  
 

 

#11




你不会强制转换??????

#12


最后说:

 search osr的文章,里面有两篇就是专门讲这个主题的,大哥,好好看一下好吗!!!!!

#13


vcmfc和ArthurTu两位大虾,我在驱动开发网也经常看到你们,想问一个私人问题,你们现在在什么类型的公司工作阿,待遇如何?呵呵呵呵呵

#14


vcmfc和ArthurTu两位,我在驱动开发网也经常看到你们,想问一个私人问题,你们现在在什么类型的公司工作阿,待遇如何?呵呵呵呵呵
-------------------------------------------
刚刚下岗。。。


我应该在DISPATCH_LEVEL如何访问PAGEG MEMORY
-------------------------------------------
不能

#15


to vcmfc(【痛苦的虫虫】)

"你不会强制转换??????"



强制转换当然可以,但会引起蓝屏(0X0E).你是怎么做的,不妨把相关的代码贴出来,大家看看你说的是否正确.
另外你所说的OSR的文章是不是这一篇"Sharing Memory Between Drivers and Applications".这篇文章所说的方法有一些局限性.

我们所讨论的问题是:
APP应能实时的从DRIVER取得数据(如果DRIVER有数据上传),但DRIVER上传的数据在时间和数量上是不确定的.DRIVER工作在DISPATCH_LEVEL.要求占用系统资源尽量少.APP开启的时候不能阻止系统正常重启或关机.


  
 

#16


to ArthurTu(猫王) :

我应该在DISPATCH_LEVEL如何访问PAGEG MEMORY
-------------------------------------------
不能

那么你所谓的共享内存是如何实现的?

#17


我所知道的也就是"Sharing Memory Between Drivers and Applications"。不知有什么局限性不能满足你的要求?

我们所讨论的问题是:
APP应能实时的从DRIVER取得数据(如果DRIVER有数据上传),但DRIVER上传的数据在时间和数量上是不确定的.DRIVER工作在DISPATCH_LEVEL.要求占用系统资源尽量少.APP开启的时候不能阻止系统正常重启或关机.
------------------------
用event的方法不能满足你的要求吗?够了吧?

“DRIVER工作在DISPATCH_LEVEL”,什么driver,居然能一直工作在dispatch level?“实时的从DRIVER取得数据”,这个“实时”怎么定义?

#18


to ArthurTu(猫王)
用event的方法,能贴出相关代码吗?
app产生的event是handle,但DRIVER里用的是PRKEVENT,两个声明完全不同.强制转换当然可以,但会引起蓝屏(0X0E).你是怎么做的??
洗耳恭听!!

#19


工作在dispatch level的DRIVER很多,如声卡,鼠标,键盘,硬盘,光驱....
即使一般的DRIVER,工作在dispatch level的情况也很多,如DPC,COMPLETEROUTE,SPINLOCK...

#20


为什么你的那些处理一定要在dispatch,DPC回调,workitem等,都可以延期到pass level,全在pass level,如果是在dispatch,APP如何访问你?,在如此高的IRQL,APP根本就不可能访问。


OSR:2002:

Sharing is Caring -- Sharing Events Between Kernel-User Mode 


用心搜索..............


你有没有看过全部的inside nt????,至少我全看过,有些虽然不懂,但有个印象,一需要我就知道在哪儿查...........


不好意思,口气是不太友好,主要近来太忙了,问题一大堆,烦死了..........


在北京.................

#21


我是说“一直”工作在dispatch level的DRIVER。

Probably the simplest mechanism is sharing one or more named events.  When an application calls CreateEvent(), the named event is automatically created in the Object Manager’s BaseNamedObjects directory.  A driver can open, and share, these event objects by calling IoCreateNotificationEvent(), and specifying the same name as was specified in user mode (except, of course, specifying “\BaseNamedObjects” as the directory).

#22


ArthurTu(猫王) &  vcmfc(【痛苦的虫虫】) 
谢谢你的指点,因为需要更多的人关注"WDM驱动程序和应用程序的通信方法"话题,所以重新开贴给分,请到
http://expert.csdn.net/Expert/topic/1609/1609281.xml?temp=.342663
取分.

#23


我所做的DRIVER基本上是鼠标驱动,鼠标驱动的回调函数(用于取数据)是工作在DISPATCH LEVEL.由于我的DRIVER不仅把数据传给系统,而且要传给我们特定的服务程序(USER MODE),
因此,服务程序不能一直打开设备等待数据,而需要实时的通信方式,占用系统资源少,不能影响到系统的正常运做.

其实上面的问题我已经解决,但总觉得不够好,所以开贴来让大家讨论这么一个普遍性的问题!
感谢大家发表高见,我会随时开贴给分.

#24


因此,服务程序不能一直打开设备等待数据,而需要实时的通信方式,占用系统资源少,不能影响到系统的正常运做.

1、不清楚你的服务程序是干什么,非要打开设备才能接收数据?
2、“实时”?到哪种程度?Windows下谈不上什么实时。
3、2K下user mode的app不大会影响OS的运作,出错了大不了OS就kill他,driver不出错就好。你是说“APP开启的时候不能阻止系统正常重启或关机.”?

#25


1、EVENT和PKEVENT的转换。

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);

2、我曾经做过进程启动实时监视的程序,我是这样做的:

[1]、在WDM中建立一个具有名字的Event对象,如下:

    //
    // 建立通知事件
    //
    UNICODE_STRING NotifyEventName;
    HANDLE hTempEvent;

    RtlInitUnicodeString(&NotifyEventName,L"\\BaseNamedObjects\\ProcMonEvent");
    pDeviceExtension->ProcessEvent = IoCreateNotificationEvent(&NotifyEventName,&hTempEvent);
    KeClearEvent(pDeviceExtension->ProcessEvent);

[2]、在App中使用OpenEvent()来打开那个Event,并建立一个新的线程来监视那个Event,如下:

//
// StartMonitor
//
bool __fastcall TThreadMonitor::StartMonitor()
{
    //
    // Stop Monitor first
    //
    if(IsMonitoring)
    {
        StopMonitor();
    }    

    hEvent = OpenEvent(SYNCHRONIZE,false,EventName.c_str());
    if(hEvent == NULL)
    {
        return false;
    }    

    ///
    DWORD dwTempThreadId;

    hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)MonitorThread,
                           (LPVOID)this,0,&dwTempThreadId
                           );
                           
    IsMonitoring = (hThread != NULL) ;

    return IsMonitoring;
}
//---------------------------------------------------------------------------
//
// 有新的进程建立时,WDM触发事件。
//
DWORD WINAPI MonitorThread(TThreadMonitor *CurrentThreadMonitor)
{
    DWORD dwResult;

    while(true)
    {
        dwResult = WaitForSingleObject(CurrentThreadMonitor->hEvent,INFINITE);

        //    
        // 停止监视
        //
        if(!CurrentThreadMonitor->IsMonitoring)
        {
            break;
        }    

        if(dwResult == WAIT_OBJECT_0)
        {
            CurrentThreadMonitor->ProcessMonitor->ProcessCreated();
        }
    }

    //
    // 在这里释放资源
    //
    CloseHandle(CurrentThreadMonitor->hEvent);
    CloseHandle(CurrentThreadMonitor->hThread);

    CurrentThreadMonitor->hEvent = NULL;
    CurrentThreadMonitor->hThread = NULL;

    return 1;
}
//---------------------------------------------------------------------------


[3]、当WDM需要通知那个APP时,它调用KeSetEvent()触发事件,这样APP也就得到通知了,可以做一些事了........这样算实时吗??????????

#26


slwqw2(亚洲之鹰)
你的出现应该可以少浪费好多口水:)

#27


:)

#28


To ArthurTu(猫王) 
1、不清楚你的服务程序是干什么,非要打开设备才能接收数据?
------------------------------------------------------------------------
对于从DRIVER读取数据或PENDING时,需要打开设备


2、“实时”?到哪种程度?Windows下谈不上什么实时。
--------------------------------------------------------------------------
要求像鼠标和键盘一样实时

3、2K下user mode的app不大会影响OS的运作,出错了大不了OS就kill他,driver不出错就好。你是说“APP开启的时候不能阻止系统正常重启或关机.”?
----------------------------------------------------------------------------
如果DeviceIoControl在系统关机时不能返回(例如PENDING IRP),则系统不能正常关机.

 

#29


谢谢  slwqw2(亚洲之鹰) 

你说的方法很好,谢谢!
另外如何实现在关闭设备后,还能与DRIVER通信,例如共享内存.

#30


转帖
: LornWolf(绝地苍狼) ( )  
 
  影射核心内存到用户模式进程

映射由核心模式分配的缓冲到一个特定用户进程的虚拟地址空间,这种方法非常简单。并能使驱动程序保留对这种内存最大控制权。

驱动程序可以使用任意标准的方法来分配要共享的缓冲,如果没有特殊的要求并且大小适度,可以将它分配在非分页池中。

驱 动 程 序 使 用 IoAllocateMdl() 分 配 一 个 MDL 来 描 述 这 个 缓 冲, 然 后 调 用MmBuildMdlForNonPagedPool()。这个函数修改MDL以描述内核模式中一个非分页内存区域。
当用来描述共享缓冲的MDL建立起来以后,驱动程序现在可以准备将缓冲映射到用户进程的地 址空间了,由MmMapLockedPagesSpecifyCache() 这个函数完成。

你必须要在你想要映射共享缓冲的进程上下文环境中调用MmMapLockedPagesSpecifyCache(),并且指定AccessMode参数为UserMode。这个函数返回由MDL映射的用户态虚拟地址。 驱动程序可以把这个值作为用户程序发送IOCTL请求时的返回值返回给用户程序。

PVOID
CreateAndMapMemory()
{
    PVOID buffer;    
    PMDL  mdl;
    PVOID userVAToReturn;

    //
    // Allocate a 4K buffer to share with the application
    //

    buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'MpaM');

    if(!buffer) {
        return(NULL);
    }

    //
    // Allocate and initalize an MDL that describes the buffer
    //

    mdl = IoAllocateMdl(buffer,

                        PAGE_SIZE,

                        FALSE,

                        FALSE,

                        NULL);

    if(!mdl) {
        ExFreePool(buffer);
        return(NULL);
    }

    //
    // Finish building the MDL -- Fill in the "page portion" 
    //

    MmBuildMdlForNonPagedPool(mdl);

#if NT_40

    //
    // Map the buffer into user space
    //
    // NOTE: This function bug checks if out of PTEs
    //

    userVAToReturn = MmMapLockedPages(mdl, UserMode);

#else

    //
    // The preferred V5 way to map the buffer into user space
    //

    userVAToReturn = 

         MmMapLockedPagesSpecifyCache(mdl,          // MDL

                                      UserMode,     // Mode

                                      MmCached,     // Caching

                                      NULL,         // Address

                                      FALSE,        // Bugcheck?

                                      NormalPagePriority); // Priority

    //
    // If we get NULL back, the request didn't work.
    // I'm thinkin' that's better than a bug check anyday.
    //

    if(!userVAToReturn) {
        IoFreeMdl(mdl);
        ExFreePool(buffer);
        return(NULL);
    }


#endif

    //
    // Store away both the mapped VA and the MDL address, so that 
    // later we can call MmUnmapLockedPages(StoredPointer, StoredMdl)
    //

    StoredPointer = userVAToReturn;
    StoredMdl = mdl;

    DbgPrint("UserVA = 0x%0x\n", userVAToReturn);

    return(userVAToReturn);



在映射完共享缓冲以后,可以在任意进程上下文环境中对它进行访问,并且可以在提升的IRQL*问(因为是在非分页内存中)。

如果使用这种方法,有一个情况必须注意:你必须保证驱动程序提供一个方法在用户程序退出的时候来取消映射。