加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

应用程序与驱动程序6种通信方式

(2011-04-18 17:08:30)
标签:

应用程序

驱动程序

6种

通信方式

直接

缓冲

其他

分类: Embedded_Wince

应用程序与驱动程序6种通信方式   

---来源于互联网,交流学习--- 

       应用程序与驱 动程序通信方式据我所知,细分可以分6种,ReadFile,WirteFile方式的缓冲区设备读写,直接方式读写,和其他方式读写。Io设备控制操作(即 DeviceControl)的缓冲内存模式IOCTL,直接内存方式的IOCTL,其他内存方式的IOCTL!当然还有一种就是创建文件,然后文件读写 也应该算是一种通信吧,这里不讨论这个!

下面是方式都是用ReadFile,WirteFile设备控制操作的方法基本上与上面3中相对应!

1、缓冲区方式设备读写:

在创建Device后,须要指定方式为Device的Flags有 DO_BUFFERED_IO!通过应用层Api函数ReadFile,WriteFile,等函数,ntoskrnl.exe创建Irp 后,ReadFile和WriteFile参数的缓冲区就在irp->AssociatedIrp.Systembuffer,同时要求读写的偏移 量,和长度都在PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp) 数据类型中的 stack->Parameters.Read.Length,stack->Parameters.Read.ByteOffset(该类 型为Large_Interge类型),

2、直接方式读写

在创建Device后,须要指定方式为Device的Flags有 DO_DIRECT_IO!通过应用层APi函数ReadFile,WriteFile等函数,ntoskrnl.exe创建的Irp 后,ReadFile和WriteFile参数的缓冲区将被锁住,然后操作系统将这段缓冲区在内核模式地址再次映射一遍,这样应用层的缓冲区和内存层的就 指向同一个物理内存!而内核模式用MDL数据结构记录这段内存,这个虚拟内存大小在 MmGetByteCount(pIrp->MdlAddress),首地址在 MmGetMdlVirtualAddress(pIrp->MdlAddress);偏移量为 MmGetMdlByteOffset(pIrp->MdlAddress)(这里的偏移量不是文件读写的偏移量,而是在MDL中的偏移量)然后文 件的长度还是stack->Parameters.Read.Length,这个值和 MmGetByteCount(pIrp->MdlAddress)是一样的,要不然就出错了,而真正的读写偏移量还是在 stack->Parameters.Read.ByteOffset!这里无论是读还是写,都要得到MDL在内核模式下的映射,因此还要用 MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority)将其转化 为内核模式,然后可以读写该地址,就会转化到应用层相应的内存!!

3、其他方式读写

这种方式很少用到,在创建Device后,Flags既不标志 DO_BUFFERED_IO也不标志DO_DIRECT_IO,ReadFile和WriteFile提供的缓冲区内存地址,可以再IRP的 pIrp->UserBuffer字段得到,而长度和偏移量还是在stack->Paameters.Read中,但是用这种方法须要注意的 是ReadFile可能把空指针地址或者非法地址传递给驱动程序,因此驱动程序使用用户模式地址钱须要检查是否可读或者可写,可以用 ProbeForWrite或者ProbeForWrite函数和try模块。

这里有个问题困扰着我,就是应用层用GetFileSize函数时用第一种方法处 理该Irp时结果是正确的,就是冲pIrp->AssociatedIrp.SystemBuffer;得到 PFILE_STANDARD_INFORMATION结构指针,然后讲该结构的EndOfFile设置为你自己文件的长度,然后结束该 IRP,GetFileSize就能得到正确的文件长度,但是用方法三就是的时候用GetFileSize,我同样用 pIrp->UserBufer得到PFILE_STANDARD_INFORMATION结构指针,然后设置后,在GetFileSize里面去 得不到正确的长度!!这个是为什么?还有就是该Irp的CurrentStackLocation-stack,该字段里面的 stack->Parameters.QueryFile.Length指的是什么,显示的都是24,无论文长度为多少,还是用哪种方法都市24, 很郁闷!!!

下面是方式都是用IO设备控制操作的方法基本上与上面3中相对应!

对于IO设备控制操作,不知道为什么可以用设置DO_DIRECT_IO后就能对 三种方式都适用,而且stack->Parameters.Read.Length/Write.Length 都是对应应用层的DeviceIoControl函数中的第6个参数也就是输出缓冲区!DeviceIoControl函数的输入输出缓冲区长度都再 stack->Parameters.DeviceioControl.InputBufferLength/OutputBufferLength 中

4、缓冲内存IOCTL,在DeviceIoControl函数第二个参数的时候, 使用CTL_CODE来产生该常数,其中Method字段设置为METHOD_BUFFERED,在内核模式中输入缓冲区很输出缓冲区都为 pIrp->AssociatedIrp.SystemBuffer,

5、直接方式IOCTL,在DeviceIoControl函数第二个参数的时候, 使用CTL_CODE来产生该常数,其中Method字段设置为METHOD_IN_DIRECT/METHOD_OUT_DIRECT(最好使用第一 个,因为第一个对所有的打开设备方式都通用)!对于第4中的区别是输入缓冲区还在pIrp->AssocatedIrp.Systembuffer 中,但是输出缓冲区却是pIrp->MdlAddress,因此在内核对输出的写应该写在 MmGetSystemAddressForMdlSafe(pIrp->MdlAddress)中,

6、其他方式IOCTL,在DeviceIoControl函数第二个参数的时候, 使用CTL_CODE来产生该常数,其中Method字段设置为MEHTOD_NEITHER,输入缓冲区为 stack->Parameters.DeviceIoControl.Tyep3InputBuffer;输出缓冲区为 pIrp->Userbuffer

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有