驱动编程学习一
环境设置:
1、属性页->C/++->警告等级:等级3/W
2、属性页->C/C++-)将警告视为错误:否/x-
3、属性页->Inf2Cat->Run Inf2Cat:否
4、属性页->Driver settings->Target os Version:设置版本 windows 7 windows1e任选
5、属性页->Driver Settings->Target PlatForm:Desktop
6、属性页->StampInf->Endable Architecture:否
7、KdPrint类似于控制台的printf
8、DriverEntry类似于C/C++里的main
一、第一个简单的驱动编程
#include <ntifs.h>
//卸载驱动 void Unload(PDRIVER_OBJECT driver) {//因为参数driver没有使用,会出现警告。 IoDeleteDevice(driver->DeviceObject); KdPrint(("jw:进入卸载例程")); } //驱动入口点函数 NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING szReg) { KdPrint(("jw:我的第一个驱动,最简单的驱动+++++++++")); KdPrint(("jw:注册路径 = %wZ", szReg));//szReg注册表的路径 driver->DriverUnload = Unload;//注册卸载例程 //调用创建驱动设备函数 CreateDevice CreateDevice(driver); return STATUS_SUCCESS; };//最小的驱动 只有一行代码。
二、创建驱动设备对象
//创建驱动设备对象 NTSTATUS CreateDevice(PDRIVER_OBJECT driver) { NTSTATUS status; UNICODE_STRING MyDriver;//char*wchar* PDEVICE_OBJECT device = NULL; //这是一个指针 RtlInitUnicodeString(&MyDriver,L"\\DEVICE\VayDriver");//strcpy//ucscpy,初始化字符串对象 KdPrint(("jw:未创建设备前:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device)); status = IoCreateDevice(driver, 4,//sizeof(DEVICE_EXTENSION),自己定义的结构的大小 &MyDriver, // 设备名字 FILE_DEVICE_UNKNOWN,//设备的类型 FILE_DEVICE_SECURE_OPEN,////独占的话设置为TRUE,非独占设置为FALSE FALSE, &device);//device 返回设备对象 if (status == STATUS_SUCCESS) { KdPrint(("jw:驱动设备对象创建成功,ok \n")); } else { KdPrint(("jw:驱动设备对象创建失败,删除设备 \n")); IoDeleteDevice(device); } KdPrint(("jw:创建设备之后:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device)); return status; } //卸载驱动 void Unload(PDRIVER_OBJECT driver) {//因为参数driver没有使用,会出现警告。 IoDeleteDevice(driver->DeviceObject); KdPrint(("jw:进入卸载例程")); } //驱动入口点函数 NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING szReg) { KdPrint(("jw:我的第一个驱动,最简单的驱动+++++++++")); KdPrint(("jw:注册路径 = %wZ", szReg));//szReg注册表的路径 driver->DriverUnload = Unload;//注册卸载例程 //调用创建驱动设备函数 CreateDevice CreateDevice(driver); return STATUS_SUCCESS; };//最小的驱动 只有一行代码。
三、为设备对象创建符号链接
#define 符号链接名字 L"\\??\\mylinkName" #define 驱动设备名字 L"\\DEVICE\uzDriverName001" //创建驱动设备对象 NTSTATUS CreateDevice(PDRIVER_OBJECT driver) { NTSTATUS status; UNICODE_STRING uzDriverName;//char*wchar* PDEVICE_OBJECT device = NULL; //这是一个指针 RtlInitUnicodeString(&uzDriverName, 驱动设备名字);//strcpy//ucscpy,初始化字符串对象 KdPrint(("jw:未创建设备前:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device)); status = IoCreateDevice(driver, 4,//sizeof(DEVICE_EXTENSION),自己定义的结构的大小 &uzDriverName, // 设备名字 FILE_DEVICE_UNKNOWN,//设备的类型 FILE_DEVICE_SECURE_OPEN,////独占的话设置为TRUE,非独占设置为FALSE FALSE, &device);//device 返回设备对象 if (status == STATUS_SUCCESS) { KdPrint(("jw:驱动设备对象创建成功,ok \n")); //创建设备对象之后就可以为驱动对象绑定符号链接,就是为设备创建一个别名 UNICODE_STRING uzMyLinsName; //符号链接名字 RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串 status = IoCreateSymbolicLink(&uzMyLinsName, &uzDriverName); if (status == STATUS_SUCCESS) { KdPrint(("jw:创建符号链接 符号链接名= %wZ 成功\r\n", &uzMyLinsName)); }else{ IoDeleteSymbolicLink(&uzMyLinsName);//删除符号链接 KdPrint(("jw:创建符号链接失败 错误代码=%X \r\n", status));//错误就是状态码 } } else { KdPrint(("jw:驱动设备对象创建失败,删除设备 \n")); IoDeleteDevice(device); } KdPrint(("jw:创建设备之后:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device)); return status; }
//卸载驱动 void Unload(PDRIVER_OBJECT driver) {//因为参数driver没有使用,会出现警告。 //一定要在删除设备前 先删除符号链接 UNICODE_STRING uzMyLinsName; //符号链接名字 RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串 IoDeleteSymbolicLink(&uzMyLinsName); //删除设备对象 IoDeleteDevice(driver->DeviceObject); KdPrint(("jw:进入卸载例程")); } //驱动入口点函数 NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING szReg) { KdPrint(("jw:我的第一个驱动,最简单的驱动+++++++++")); KdPrint(("jw:注册路径 = %wZ", szReg));//szReg注册表的路径 driver->DriverUnload = Unload;//注册卸载例程 //调用创建驱动设备函数 CreateDevice CreateDevice(driver); return STATUS_SUCCESS; };//最小的驱动 只有一行代码。
四、访问驱动设备及IRP事件处理
#define 符号链接名字 L"\\??\\mylinkName" //这个是用户层访问的CreateFile #define 驱动设备名字 L"\\DEVICE\uzDriverName001" //这是内核访问的NtCreateFile //创建驱动设备对象 NTSTATUS CreateDevice(PDRIVER_OBJECT driver) { NTSTATUS status; UNICODE_STRING uzDriverName;//char*wchar* PDEVICE_OBJECT device = NULL; //这是一个指针 RtlInitUnicodeString(&uzDriverName, 驱动设备名字);//strcpy//ucscpy,初始化字符串对象 KdPrint(("jw:未创建设备前:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device)); status = IoCreateDevice(driver, 4,//sizeof(DEVICE_EXTENSION),自己定义的结构的大小 &uzDriverName, // 设备名字 FILE_DEVICE_UNKNOWN,//设备的类型 FILE_DEVICE_SECURE_OPEN,////独占的话设置为TRUE,非独占设置为FALSE FALSE, &device);//device 返回设备对象 if (status == STATUS_SUCCESS) { KdPrint(("jw:驱动设备对象创建成功,ok \n")); //创建设备对象之后就可以为驱动对象绑定符号链接,就是为设备创建一个别名 UNICODE_STRING uzMyLinsName; //符号链接名字 RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串 status = IoCreateSymbolicLink(&uzMyLinsName, &uzDriverName); if (status == STATUS_SUCCESS) { KdPrint(("jw:创建符号链接 符号链接名= %wZ 成功\r\n", &uzMyLinsName)); }else{ IoDeleteSymbolicLink(&uzMyLinsName);//删除符号链接 KdPrint(("jw:创建符号链接失败 错误代码=%X \r\n", status));//错误就是状态码 } } else { KdPrint(("jw:驱动设备对象创建失败,删除设备 \n")); IoDeleteDevice(device); } KdPrint(("jw:创建设备之后:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device)); return status; } //访问驱动设备及IRP事件处理 //https://learn.microsoft.com/zh-cn/windows-hardware/drivers/kernel/irp-major-function-codes NTSTATUS IRP_PROC(PDEVICE_OBJECT device, PIRP pirp)//irp回调函数 {//常用的三个处理 KdPrint(("jw:进入派遣函数")); PIO_STACK_LOCATION irpStack; ULONG CtlCode; ULONG InputBuffLength; irpStack = IoGetCurrentIrpStackLocation(pirp);//获取应用层传来的消息 switch (irpStack->MajorFunction) {//分发消息 case IRP_MJ_DEVICE_CONTROL: //DeviceIoControl { KdPrint(("jw:用户层调用了 DeviceIoControl")); break; } case IRP_MJ_CREATE: //CreateFile { KdPrint(("jw:用户层调用了 CreateFile ")); break; } case IRP_MJ_CLOSE: //CloseHandle { KdPrint(("jw:用户层调用了 CloseHandle")); } } pirp->IoStatus.Status = STATUS_SUCCESS; pirp->IoStatus.Information = 4; //返回给DeviceIoControl中的 倒数第二个参数lpBytesReturned IoCompleteRequest(pirp, IO_NO_INCREMENT); //调用方已完成所有I/O请求处理操作 并且不增加优先级 KdPrint(("jw:离开派遣函数 \r\n")); return STATUS_SUCCESS; }; //卸载驱动 void Unload(PDRIVER_OBJECT driver) {//因为参数driver没有使用,会出现警告。 //一定要在删除设备前 先删除符号链接 UNICODE_STRING uzMyLinsName; //符号链接名字 RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串 IoDeleteSymbolicLink(&uzMyLinsName); //删除设备对象 IoDeleteDevice(driver->DeviceObject); KdPrint(("jw:进入卸载例程")); } //驱动入口点函数 NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING szReg) { KdPrint(("jw:我的第一个驱动,最简单的驱动+++++++++")); KdPrint(("jw:注册路径 = %wZ", szReg));//szReg注册表的路径 driver->DriverUnload = Unload;//注册卸载例程 //irp处理 driver->MajorFunction[IRP_MJ_CREATE] = IRP_PROC; driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IRP_PROC; driver->MajorFunction[IRP_MJ_CLOSE] = IRP_PROC; //调用创建驱动设备函数 CreateDevice CreateDevice(driver);//创建驱动设备 return STATUS_SUCCESS; };//最小的驱动 只有一行代码。
另建一个对话框程序exe来调用上面的驱动例程,建立2个按钮
HANDLE g_sysHandle = NULL; #define 符号链接名字 L"\\??\\mylinkName" //这个是用户层访问的CreateFile
//第一个按钮事件
void C驱动用户层访问Dlg::OnBnClickedBtnCreate() { // 打开驱动设备对象,就是获取一个驱动设备的句柄 g_sysHandle = CreateFileW(符号链接名字, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); TRACE(TEXT("jw:sysHandle = %p Error = %d \r\n"), g_sysHandle, GetLastError()); } //第二个按钮事件 void C驱动用户层访问Dlg::OnBnClickedBtnUnload() { // 卸载打开的驱动句柄 TRACE(TEXT("jw:卸载打开的驱动句柄 \r\n")); CloseHandle(g_sysHandle);//只有释放掉此句柄,驱动才能正常卸载。或者当拥有此句柄的进程 关闭了 }
五、用户层与驱动进行通信
#include <ntifs.h> #define 符号链接名字 L"\\??\\mylinkName" //这个是用户层访问的CreateFile #define 驱动设备名字 L"\\DEVICE\uzDriverName001" //这是内核访问的NtCreateFile //创建驱动设备对象 NTSTATUS CreateDevice(PDRIVER_OBJECT driver) { NTSTATUS status; UNICODE_STRING uzDriverName;//char*wchar* PDEVICE_OBJECT device = NULL; //这是一个指针 RtlInitUnicodeString(&uzDriverName, 驱动设备名字);//strcpy//ucscpy,初始化字符串对象 KdPrint(("jw:未创建设备前:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device)); status = IoCreateDevice(driver, 4,//sizeof(DEVICE_EXTENSION),自己定义的结构的大小 &uzDriverName, // 设备名字 FILE_DEVICE_UNKNOWN,//设备的类型 FILE_DEVICE_SECURE_OPEN,////独占的话设置为TRUE,非独占设置为FALSE FALSE, &device);//device 返回设备对象 if (status == STATUS_SUCCESS) { KdPrint(("jw:驱动设备对象创建成功,ok \n")); //创建设备对象之后就可以为驱动对象绑定符号链接,就是为设备创建一个别名 UNICODE_STRING uzMyLinsName; //符号链接名字 RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串 status = IoCreateSymbolicLink(&uzMyLinsName, &uzDriverName); if (status == STATUS_SUCCESS) { KdPrint(("jw:创建符号链接 符号链接名= %wZ 成功\r\n", &uzMyLinsName)); }else{ IoDeleteSymbolicLink(&uzMyLinsName);//删除符号链接 KdPrint(("jw:创建符号链接失败 错误代码=%X \r\n", status));//错误就是状态码 } } else { KdPrint(("jw:驱动设备对象创建失败,删除设备 \n")); IoDeleteDevice(device); } KdPrint(("jw:创建设备之后:driver->DeviceObject=%p, device=%p \r\n", driver->DeviceObject, device)); return status; } //访问驱动设备及IRP事件处理 //https://learn.microsoft.com/zh-cn/windows-hardware/drivers/kernel/irp-major-function-codes NTSTATUS IRP_PROC(PDEVICE_OBJECT device, PIRP pirp)//irp回调函数 {//常用的三个处理 KdPrint(("jw:进入派遣函数")); PIO_STACK_LOCATION irpStack; ULONG CtlCode; ULONG InputBuffLength; irpStack = IoGetCurrentIrpStackLocation(pirp);//获取应用层传来的消息 switch (irpStack->MajorFunction) {//分发消息 case IRP_MJ_DEVICE_CONTROL: //DeviceIoControl { //case irpStack->Parameters.DeviceIoControl.IoControlCode: // //这里取出用户层传递过来的缓冲区的数据 char *pInbuf = (char *)pirp->AssociatedIrp.SystemBuffer; //取出缓冲区大小 KdPrint(("jw:pInbuf = %s \r\n", pInbuf)); KdPrint(("jw:用户层调用了 DeviceIoControl")); //返回数据给缓冲区 strcpy(pInbuf, "这个数据是驱动返回给用户层的。\r\n"); pirp->IoStatus.Status = STATUS_SUCCESS; pirp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength; //返回给DeviceIoControl中的 倒数第二个参数lpBytesReturned IoCompleteRequest(pirp, IO_NO_INCREMENT); //调用方已完成所有I/O请求处理操作 并且不增加优先级 break; } case IRP_MJ_CREATE: //CreateFile { KdPrint(("jw:用户层调用了 CreateFile ")); break; } case IRP_MJ_CLOSE: //CloseHandle { KdPrint(("jw:用户层调用了 CloseHandle")); } } KdPrint(("jw:离开派遣函数 \r\n")); return STATUS_SUCCESS; }; //卸载驱动 void Unload(PDRIVER_OBJECT driver) {//因为参数driver没有使用,会出现警告。//一定要在删除设备前 先删除符号链接 UNICODE_STRING uzMyLinsName; //符号链接名字 RtlInitUnicodeString(&uzMyLinsName, 符号链接名字);//初始化字符串 IoDeleteSymbolicLink(&uzMyLinsName); //删除设备对象 IoDeleteDevice(driver->DeviceObject); KdPrint(("jw:进入卸载例程")); } //驱动入口点函数 NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING szReg) { KdPrint(("jw:我的第一个驱动,最简单的驱动+++++++++")); KdPrint(("jw:注册路径 = %wZ", szReg));//szReg注册表的路径 driver->DriverUnload = Unload;//注册卸载例程 //irp处理 driver->MajorFunction[IRP_MJ_CREATE] = IRP_PROC; driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IRP_PROC; driver->MajorFunction[IRP_MJ_CLOSE] = IRP_PROC; //调用创建驱动设备函数 CreateDevice CreateDevice(driver);//创建驱动设备 return STATUS_SUCCESS; };//最小的驱动 只有一行代码。
用户层 在上面对话框工程中,再添加一个按钮

//传递一个字符串给驱动 #include <winioctl.h> #define IO_STRING CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803,METHOD_BUFFERED,FILE_ANY_ACCESS) //控制码测试 #define IO_IS_OK_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804,METHOD_BUFFERED,FILE_ANY_ACCESS) //控制码测试 #define IO_IS_OK_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805,METHOD_BUFFERED,FILE_ANY_ACCESS) //控制码测试 void C驱动用户层访问Dlg::OnBnClickedBtnClIo()//与驱动通信 { //打开设备,获取设备句柄 HANDLE sysHandle = CreateFileW(符号链接名字, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); //传递字符串到设备。 char testString[100] = "测试字符串 R3至R0 "; char retBuf[256] = { 0 }; DWORD dwRetSize = 0; BOOL br = DeviceIoControl(sysHandle,//CreateFileW 打开驱动设备 返回的句柄 IO_STRING,//控制码 CTL_CODE &testString, //输入缓冲区指针 驱动中在irp中的 IRP_MJ_DEVICE_CONTROL中处理放入缓冲区的数据 sizeof(testString), //输入缓冲区大小,直接写100也可以 retBuf,//返回缓冲区的地址 256, //返回缓冲区的大小 &dwRetSize, //返回字节数 NULL); //返回值 TRACE("jw:retBuf = %s \r\n", retBuf);// //另一种方式打印数据 char buf[1024] = { 0 }; sprintf_s(buf, "jw:retBuf = %s \r\n", retBuf); OutputDebugStringA(buf);//用调试输出 }
浙公网安备 33010602011771号