关于METHOD_BUFFERED驱动通信方式

"缓冲"方法(METHOD_BUFFERED)
备注:在下面的讨论中,"输入"表示数据从用户模式的应用程序到驱动程序,"输出"表示数据从驱动程序到应用程序。

对于读取请求,I/O 管理器分配一个与用户模式的缓冲区大小相同的系统缓冲区。IRP 中的 SystemBuffer 字段包含系统地址。 UserBuffer 字段包含初始的用户缓冲区地址。当完成请求时,I/O 管理器将驱动程序已经提供的数据从系统缓冲区复制到用户缓冲区。对于写入请求,会分配一个系统缓冲区并将 SystemBuffer 设置为地址。用户缓冲区的内容会被复制到系统缓冲区,但是不设置 UserBuffer。对于 IOCTL 请求,会分配一个容量大小足以包含输入缓冲区或输出缓冲区的系统缓冲区,并将 SystemBuffer 设置为分配的缓冲区地址。输入缓冲区中的数据复制到系统缓冲区。UserBuffer 字段设置为用户模式输出缓冲区地址。内核模式驱动程序应当只使用系统缓冲区,且不应使用 UserBuffer 中存储的地址。

对于 IOCTL,驱动程序应当从系统缓冲区获取输入并将输出写入到系统缓冲区。当完成请求时,I/O 系统将输出数据从系统缓冲区复制到用户缓冲区。

 

2K中的源码实现是这样的:

        irpSp->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID) NULL;

        try {

            if (InputBufferLength || OutputBufferLength) {
                irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota( poolType, (InputBufferLength > OutputBufferLength) ? nputBufferLength : OutputBufferLength );

                if (ARGUMENT_PRESENT( InputBuffer )) {
                    RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, InputBuffer, InputBufferLength );
                }
                irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
                irp->UserBuffer = OutputBuffer;
                if (ARGUMENT_PRESENT( OutputBuffer )) {
                    irp->Flags |= IRP_INPUT_OPERATION;
                }
            } else {
                irp->Flags = 0;
                irp->UserBuffer = (PVOID) NULL;
            }
可以看出ExAllocatePoolWithQuota先分配了一块系统内存,把用户态输入缓冲区的数据拷贝到系统内存irp->AssociatedIrp.SystemBuffer 中。而irp->UserBuffer 则保存了当前的输出缓冲区。

 

所以我们可以用irp->UserBuffer来传递具有多个参数的驱动 IOCTL请求的第二个参数来使用。

 Param1Buffer = Irp->AssociatedIrp.SystemBuffer;

 Param2Buffer = Irp->UserBuffer;

最后还是要把要输出的数据放到Irp->AssociatedIrp.SystemBuffer中输出。Irp->AssociatedIrp.SystemBuffer中的数据会复制到Irp->UserBuffer。

 

这种使用方式要注意Irp->UserBuffer作为输出缓冲区时,最好不要直接赋值。除非Irp->UserBuffer=Irp->AssociatedIrp.SystemBuffer

你可能感兴趣的:(IO,null,存储,buffer,input)