下面说说内存映射。由于我们的程序需要传输大量的数据,如前所述,能尽量减少内存拷贝对于系统的性能都会有很大的提高。所以当有数据包要在用户态程序和驱动程序之间交互的时候,尽可能地避免直接拷贝大量数据。而应该使用内存映射的方法使用户态程序和驱动程序共用一段内存,这样就可以避免不少的内存拷贝。要进行内存映射,首先要申请一块不分页(NonPaged)的内存,这里由驱动程序来完成。然后为这块内存建立一个内存描述符。其实我们只要查看Ndis.h文件就可以知道,NDIS_BUFFER(缓冲区)和MDL(内存描述符)是同一个数据结构。当开始映射的时候,我们要调用MmBuildMdlForNonPagedPool对这个内存描述符进行处理,接下来,就可以调用函数MmMapLockedPagesSpecifyCache来实现内存映射了。传递给它的第二个参数是UserMode,表明需要映射到用户态的内存空间中。这个函数返回的是一个地址,这个地址在用户态程序中可以使用,把它传递给用户态的程序就可以了。内存映射时有一点要注重的就是进程上下文的问题,我在编写这段程序时就曾经犯过这个错误,在MiniportSendPackets处理完包裹后,顺便就进行了内存映射,并把这个用户态的地址保存起来,结果用户态的程序拿到这个地址后死活不能用,搞了好几天,才被提醒到进程上下文的问题。后来就在IOCTL的代码中实现这个,即当收到相应的IOCTL代码后,现场执行内存映射,然后把这个地址交给用户态程序,这才可以正常使用。当内存映射使用完毕时,在释放这段内存前,要调用MmUnmapLockedPages来解除内存映射。