• 应用程序与设备对象交换数据的三种方法


    1.缓冲区设备读写
    伪代码:
    创建设备及指定设备标记
    NTSTATUS status;
    PDEVICE_OBJECT pDevObj;
    PDEVICE_EXTENSION pDevExt;

    //创建设备名称
    UNICODE_STRING devName;
    RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice");

    //创建设备
    status = IoCreateDevice( pDriverObject,
    sizeof(DEVICE_EXTENSION),
    &(UNICODE_STRING)devName,
    FILE_DEVICE_UNKNOWN,
    0, TRUE,
    &pDevObj );
    if (!NT_SUCCESS(status))
    return status;
    //指定设备标记为缓冲区读写
    pDevObj->Flags |= DO_BUFFERED_IO;



    读取操作
    NTSTATUS status = STATUS_SUCCESS;

    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
    //要读取的大小 在IO堆栈的Parameters.Read.Length中
    ULONG ulReadLength = stack->Parameters.Read.Length;

    pIrp->IoStatus.Status = status;

    pIrp->IoStatus.Information = ulReadLength; // bytes xfered
    //直接操作pIrp->AssociatedIrp.SystemBuffer即可操作应用的虚拟内存
    memset(pIrp->AssociatedIrp.SystemBuffer,0xAA,ulReadLength);

    IoCompleteRequest( pIrp, IO_NO_INCREMENT );
    return status;
    2.直接读写
    伪代码:
    创建设备及指定设备标记
    NTSTATUS status;
    PDEVICE_OBJECT pDevObj;
    PDEVICE_EXTENSION pDevExt;

    //创建设备名称
    UNICODE_STRING devName;
    RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice");

    //创建设备
    status = IoCreateDevice( pDriverObject,
    sizeof(DEVICE_EXTENSION),
    &(UNICODE_STRING)devName,
    FILE_DEVICE_UNKNOWN,
    0, TRUE,
    &pDevObj );
    if (!NT_SUCCESS(status))
    return status;
    //指定设备的标记为直接读写的方式
    pDevObj->Flags |= DO_DIRECT_IO;



    读取的代码
    PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
    NTSTATUS status = STATUS_SUCCESS;

    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);

    ULONG ulReadLength = stack->Parameters.Read.Length;
    KdPrint(("ulReadLength:%d ",ulReadLength));

    ULONG mdl_length = MmGetMdlByteCount(pIrp->MdlAddress);
    //这里得到的用户模式下 缓冲区的地址 2GB以下的地址
    PVOID mdl_address = MmGetMdlVirtualAddress(pIrp->MdlAddress);
    ULONG mdl_offset = MmGetMdlByteOffset(pIrp->MdlAddress);

    KdPrint(("mdl_address:0X%08X ",mdl_address));
    KdPrint(("mdl_length:%d ",mdl_length));
    KdPrint(("mdl_offset:%d ",mdl_offset));

    if (mdl_length!=ulReadLength)
    {
    //MDL的长度应该和读长度相等,否则该操作应该设为不成功
    pIrp->IoStatus.Information = 0;
    status = STATUS_UNSUCCESSFUL;
    }else
    {
    //用MmGetSystemAddressForMdlSafe得到MDL在内核模式下的映射 这里的地址应该属于2G-4G中
    PVOID kernel_address = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
    KdPrint(("kernel_address:0X%08X ",kernel_address));
    memset(kernel_address,0XAA,ulReadLength);
    pIrp->IoStatus.Information = ulReadLength; // bytes xfered
    }

    pIrp->IoStatus.Status = status;

    IoCompleteRequest( pIrp, IO_NO_INCREMENT );
    KdPrint(("Leave HelloDDKRead "));

    return status;
    3.其他方式读写
    创建设备代码 如果使用这种方式 则不指定任何标记
    NTSTATUS status;
    PDEVICE_OBJECT pDevObj;
    PDEVICE_EXTENSION pDevExt;

    //创建设备名称
    UNICODE_STRING devName;
    RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice");

    //创建设备
    status = IoCreateDevice( pDriverObject,
    sizeof(DEVICE_EXTENSION),
    &(UNICODE_STRING)devName,
    FILE_DEVICE_UNKNOWN,
    0, TRUE,
    &pDevObj );
    if (!NT_SUCCESS(status))
    return status;



    写入代码
    PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
    NTSTATUS status = STATUS_SUCCESS;

    //得到当前堆栈
    PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
    //得到读的长度
    ULONG ulReadLength = stack->Parameters.Read.Length;
    //得到读的偏移量
    ULONG ulReadOffset = (ULONG)stack->Parameters.Read.ByteOffset.QuadPart;
    //得到用户模式地址
    PVOID user_address = pIrp->UserBuffer;

    KdPrint(("user_address:0X%0X ",user_address));

    __try
    {
    KdPrint(("Enter __try block "));
    //判断空指针是否可写,显然会导致异常
    ProbeForWrite(user_address,ulReadLength,4);

    memset(user_address,0xAA,ulReadLength);

    //由于在上面引发异常,所以以后语句不会被执行!
    KdPrint(("Leave __try block "));
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
    KdPrint(("Catch the exception "));
    KdPrint(("The program will keep going "));
    status = STATUS_UNSUCCESSFUL;
    }

    pIrp->IoStatus.Status = status;
    pIrp->IoStatus.Information = ulReadLength; // bytes xfered
    IoCompleteRequest( pIrp, IO_NO_INCREMENT );

    return status;

  • 相关阅读:
    aspcms产品详情页调取相关产品
    构造函数中返回一个对象对结果有什么影响
    跨域的几种方法及案例代码
    localStorage兼容方案
    H5 拖放事件详解
    由作用域安全的构造函数想到的
    valueOf和toString的区别
    网页布局--自适应
    【MongoDB系列】简介、安装、基本操作命令
    【JavaWeb】之Servlet
  • 原文地址:https://www.cnblogs.com/zwt1234/p/4615255.html
Copyright © 2020-2023  润新知