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

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\n",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\n",mdl_address));
KdPrint(("mdl_length:%d\n",mdl_length));
KdPrint(("mdl_offset:%d\n",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\n",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\n"));

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\n",user_address));

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

memset(user_address,0xAA,ulReadLength);

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

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

return status;

时间: 2024-11-08 19:10:15

应用程序与设备对象交换数据的三种方法的相关文章

OpenCV笔记(二)——查看Mat对象的数据的三种方法

我们有了Mat的对象之后,就可以开始对图像进行处理. 在图像的处理过程中,对数据的查看并且对其进行修改,这应当是比较频繁的操作了. 这里讲讲官方手册当中给出的三种方法. 第一种方法:使用指向Mat数据部分的指针. 代码如下: 1 Mat& ScanImageAndReduceC(Mat& I, const uchar* const table) 2 { 3 // accept only char type matrices 4 CV_Assert(I.depth() != sizeof(u

小程序跨页面传递data数据的三种方法

Q:小程序怎么把页面data里的数据传到另外的页面? 或者小程序怎么吧表单里的数据传到另外的页面?A:1.可以使用url传递数据. 例如在A页面中传递数据,需要注意的是,wx.switchTab中的url不能传参数. wx.navigateTo({url:‘../pageB/pageB?name=raymond&gender=male’}).在B页面中接收数据,通过onLoad的option:Page({onLoad:function(option){console.log(option.nam

Node.JS的表单提交及OnceIO中接受GET/POST数据的三种方法

OnceIO 是 OnceDoc 企业私有内容(文档)管理系统的底层Web框架,它可以实现模板文件.静态文件的全缓存,运行起来完全不需要I/O操作,并且支持客户端缓存优化,GZIP压缩等(只压缩一次),拥有非常好的性能,为您节约服务器成本.它的模块化功能,可以让你的Web进行分布式存储,在一个扩展包里即可包含前端.后端和数据库定义,只需通过添加/删除目录的方式就可实现功能删减,实现真正的模块化扩展.目前 OnceIO 已经开源,本文主要介绍node.js语言中的表单提交及OnceIO中接受GET

【转】delphi程序只允许运行一个实例的三种方法:

一.        创建互斥对象 在工程project1.dpr中创建互斥对象 Program project1 Uses Windows,Form, FrmMain in 'FrmMain.pas' {MainForm}; {$R *.res} var hAppMutex: THandle; //声明互斥变量 begin hAppMutex := CreateMutex(nil, false,’projectname’); //创建互斥对象projectname工程名称 if ( (hAppM

用旭日图展示数据的三种方法

什么是旭日图? 旭日图(Sunburst Chart)是一种现代饼图,它超越传统的饼图和环图,能表达清晰的层级和归属关系,以父子层次结构来显示数据构成情况.旭日图中,离远点越近表示级别越高,相邻两层中,是内层包含外层的关系. 在实际项目中使用旭日图,可以更细分溯源分析数据,真正了解数据的具体构成.而且,旭日图不仅数据直观,而且图表用起来特别炫酷,分分钟拉高数据汇报的颜值!很多数据场景都适合用旭日图,比如,在销售汇总报告中,方便看到每个店铺的销售业绩分布(如下图): 做旭日图的三种方法 1. 用E

去除DataTable重复数据的三种方法

其中要避免目标库插入重复数据.这重复数据可能是源数据库本身就有重复数据,还有就是已经插入避免重复插入. 过滤自身重复数据解决方案 第一种:采用DataView.ToTable()方法 DataView.ToTable 方法 .NET Framework 2.0 其根据现有 DataView 中的行,创建并返回一个新的 DataTable. 重载列表 名称 说明 DataView.ToTable () 根据现有 DataView 中的行,创建并返回一个新的 DataTable. 由 .NET Co

php获取POST数据的三种方法

方法一,$_POST $_POST或$_REQUEST存放的是PHP以key=>value的形式格式化以后的数据. $_POST方式是通过 HTTP POST 方法传递的变量组成的数组,是自动全局变量.如使用$_POST['name']就可以接收到网页表单以及网页异步方式post过来的数据,即$_POST只能接收文档类型为Content-Type: application/x-www-form-urlencoded提交的数据. 方法二,使用file_get_contents("php://

交换变量的三种方法及简单分析

交换两个变量的思路主要有两种:借助或不借助临时变量.具体操作时又有以下三种简单算法: 1.借助临时变量的算法 #include <stdio.h> int main(void) { int a, b, t; scanf("%d%d", &a, &b); t = a; a = b; b = t; printf("a = %d, b = %d\n", a, b); return 0; } 2.不借助临时变量的算法1(通过加减运算) #incl

什么是ViewData的, ViewBag和TempData? - MVC为当前和后续请求之间传递数据的三种方法

原文出处:http://www.codeproject.com/Articles/476967/WhatplusisplusViewData-cplusViewBagplusandplusTem ASP.NET MVC提供3种选择ViewData,ViewBag,TempData来从controller到View及后续请求传输数据. ViewData和ViewBag很相似,而TempData有所不同. 让我们来讨论或总结三者的要点: ViewBag 和 ViewData的区别: ViewData