64位驱动开发目录
第一章 MFC读写代码
第二章 驱动读写代码
提示:以下是本篇文章正文内容,下面案例可供参考
内核主要由各种驱动(在磁盘上是.sys文件)组成,这些驱动有的是windows系统自带的(例如ntfs.sys、tcpip.sys、win32k.sys),有的是由第三方软件厂商提供的。驱动加载之后,会生成对应的设备对象,并可以选择向R3提供一个可供访问和打开的符号链接。常见的盘符C、D、E等其实都是文件系统驱动创建的设备对象的符号链接,对应的符号链接分别是 “??\C:\” “??\D:\” “??\E:\”等。
应用程序可以根据内核驱动的符号链接名调用CreateFile()函数打开。在获得一个句柄(handle)之后,程序就可以调用应用层函数与内核驱动进行通信了,例如ReadFile()、WriteFile()及DeviceIoControl()等。
我们知道和IRP有关的系统缓冲区(pirp->Associatedlrp.SystemBuffer)是一个读写共享的缓冲区
一、MFC读写代码
这边用了个按钮
具体实现步骤如下:
第一步:在用户层(MFC工程项目里)选“资源视图”,在对话框里双击“读写数据”按钮,在里面添加如下代码:
void CD00910MFCDlg::OnBnClickedButton3IoWr()
{
// TODO: 在此添加控件通知处理程序代码
//a+b+c=结果
// TODO: 在此添加控件通知处理程序代码
DWORD dwRetSize = 0;//返回字节数
char buftest[256];
sprintf_s(buftest, "yjx:EXE R3 读写测试 控制码=%X\n", 读写测试);
OutputDebugStringA(buftest);
//int 传入数据[3] = {3,7,8};
#pragma pack(4)
struct 输入缓冲区
{
int a;
int b;
int c;
};
#pragma pack()
输入缓冲区 传入数据 = { 3,6,5 };
//数组示例
int OutBuf = 0 ;//输出缓冲区
DeviceIoControl(
DeviceHandle,//CreateFile打开驱动设备 返回的句柄
读写测试,//控制码 CTL_CODE
&传入数据,//输入缓冲区指针
sizeof(传入数据),//输入缓冲区大小
&OutBuf,//输出缓冲区
sizeof(OutBuf),//返回缓冲区大小
&dwRetSize, //返回字节数
NULL);
//sprintf_s(buftest, "yjx:%d+%d+%d=%d 读写测试-EXE", 传入数据[0], 传入数据[1], 传入数据[2], OutBuf);
sprintf_s(buftest, "yjx:%d+%d+%d=%d 读写测试-EXE sizeof(传入数据)=%d", 传入数据.a, 传入数据.b, 传入数据.c, OutBuf, sizeof(传入数据));
OutputDebugStringA(buftest);
}
二、驱动读写代码
第二步:在驱动层写相应的操作代码,这里我们可以把读写取数据的代码单独写到一个函数里,代码如下:
void IRP_IO_读写测试(PIRP pirp)
{
PIO_STACK_LOCATION irpStackL = IoGetCurrentIrpStackLocation(pirp);//获取应用层传来的参数;
int* 缓冲区 = (int*)pirp->AssociatedIrp.SystemBuffer;//和IRP有关的系统缓冲区
if (缓冲区)
{
int*p = (int*)缓冲区;
int 结果 = p[0] + p[1] + p[2];
KdPrint(("yjx:离开 IRP_IO_读写测试 (%d, %d, %d) 结果 = %d", p[0], p[1], p[2], 结果));
//结果
*(int*)缓冲区 = 结果;
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = sizeof(int);//返回给DeviceIoControl中的倒数第二个参数lpBytesReturned
IoCompleteRequest(pirp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作,并且不增加优先级
}
irpStackL;
}
2.然后在 IRP_CALL函数里直接调用,这里为了不影响上一节课的写入功能,使用了一个开关,可以根据控制码分别处理读数据和写数据功能。代码如下:
代码如下(示例):
NTSTATUS IRP_CALL(PDEVICE_OBJECT device, PIRP pirp)
{
device;
KdPrint(("yjx:进入派遣函数"));
PIO_STACK_LOCATION irpStackL;
irpStackL = IoGetCurrentIrpStackLocation(pirp);//获取应用层传来的参数
switch (irpStackL->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL://DeviceIoControl
{
UINT32 控制码 = irpStackL->Parameters.DeviceIoControl.IoControlCode;
if (控制码 == 读测试)
{
IRP_IO_读测试(pirp);
return STATUS_SUCCESS;
}
else if (控制码 == 写测试)
{
char* 缓冲区 = (char*)pirp->AssociatedIrp.SystemBuffer;//和IRP有关的系统缓冲区
KdPrint(("R0 yjx:用户层调用了DeviceIoControl 控制码=%X", 控制码));
KdPrint(("R0 yjx:用户层调用了DeviceIoControl 控制码=%X 缓冲区=%s", 控制码, 缓冲区));
}
else if (控制码 == 读写测试)
{
IRP_IO_读写测试(pirp);
return STATUS_SUCCESS;
}
break;
}
case IRP_MJ_CREATE://CreateFile
{
KdPrint(("yjx:用户层调用了CreateFile"));
break;
}
case IRP_MJ_CLOSE://CloseHandle
{
KdPrint(("yjx:用户层调用了CloseHandle"));
break;
}
}
pirp->IoStatus.Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 4;//返回给DeviceIoControl中的倒数第二个参数lpBytesReturned
IoCompleteRequest(pirp, IO_NO_INCREMENT);//调用方已完成所有I/O请求处理操作,并且不增加优先级
KdPrint(("yjx:离开派遣函数"));
return STATUS_SUCCESS;//返回0,表示成功
}
3.虚拟机调试结果
总结
以上就是64位驱动开发之R3与R0通信交换数据,读写数据测试的全部代码了。