当前位置:网站首页>驱动开发——第一个HelloDDK
驱动开发——第一个HelloDDK
2022-07-06 04:47:00 【ma_de_hao_mei_le】
友链
非即插即用驱动
helloddk.h
// 保证头文件只被编译一次
// 因为在实际项目中,一个头文件可能会被另一个头文件包含
// 比如b.h中包含了a.h
// 然后在c.c中有如下代码:
/*
#include<a.h>
#include<b.h>
*/
// 这样一来,a.h就被包含了两次
// 而#pragma once可以保证a.h只被编译一次
// 从而提高编译效率
#pragma once
// 下面的这段条件编译在C++项目中是非常常见的
// 它使得我们可以在C++项目中使用C中的头文件
#ifdef __cplusplus
extern "C"
{
#endif
#include <NTDDK.h>
#ifdef __cplusplus
}
#endif
// 分页标记、非分页标记和初始化内存块
#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
// INIT标志指明函数只是在加载的时候需要载入内存
// 在驱动程序成功加载之后,函数可以从内存中卸载掉
#define INITCODE code_seg("INIT")
#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")
#define arraysize(p) (sizeof(p)/sizeof((p)[0]))
// 定义机构体 _DEVICE_EXTENSION ,并起别名
// 设备扩展结构体
// 该结构体广泛应用于驱动程序中
// 根据不同程序的需要,用于补充定义设备的相关信息
typedef struct _DEVICE_EXTENSION {
PDEVICE_OBJECT pDevice;
UNICODE_STRING ustrDeviceName; // 设备名称
UNICODE_STRING ustrSymLinkName; // 符号链接名称
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
// 函数声明
// 这个IN关键字可能是用来说明参数是传入参数
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject);
VOID HelloDDKUnload(IN PDRIVER_OBJECT pDriverObject);
NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);
helloddk.cpp
#include "HelloDDK.h"
/*
初始化驱动程序,定位和申请硬件资源,创建内核对象
参数列表
pDriverObject:从IO管理器中传进来的驱动对象
pRegistryPath:驱动程序在注册表中的路径
返回值:
返回初始化驱动状态
*/
// 使用extern "C"对该函数进行修饰,这样在编译的时候会编译成[email protected]
// 如果没有这个修饰符的话,编译器会按照C++的符号名进行编译,链接的时候会报错
// 指明函数是加载到INIT内存区域中
#pragma INITCODE
extern "C" NTSTATUS DriverEntry(
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath)
{
NTSTATUS status;
// 运行在内核中的程序是没有console的,所以只能使用KdPrint宏来输出调试信息
// 这个宏只在调试版本中有作用(Free)
// 在发行版本中不执行任何操作(Checked)
KdPrint(("Enter DriverEntry\n"));
// 注册其他驱动调用函数入口
// 将我们自己定义的函数的地址传送给操作系统
// 操作系统会在合适的时候调用这些函数
// 通过下面的赋值操作
// 在驱动卸载的时候,HelloDDKUnload函数会被调用
// 在驱动程序创建、关闭和读写相关的IRP时,HelloDDKDispatchRoutine函数会被调用
pDriverObject->DriverUnload = HelloDDKUnload;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine;
// 创建驱动设备对象
status = CreateDevice(pDriverObject);
KdPrint(("DriverEntry end\n"));
// 返回CreateDevice的结果
return status;
}
// 定义CreateDevice函数
#pragma INITCODE
NTSTATUS CreateDevice(
IN PDRIVER_OBJECT pDriverObject)
{
NTSTATUS status;
PDEVICE_OBJECT pDevObj;
PDEVICE_EXTENSION pDevExt;
// 创建设备名称
// 构造Unicode字符串用来存储此设备对象的名称
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;
// 表明该设备为BUFFERED_IO设备
// 设备对内存的操作分为两种,一种是BUFFERED_IO,一种是DO_DIRECT_IO,后面解释
pDevObj->Flags = pDevObj->Flags | DO_BUFFERED_IO;
// 填写设备的扩展结构体
pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
pDevExt->pDevice = pDevObj;
pDevExt->ustrDeviceName = devName;
// 创建符号链接
// 设备名称只在内核态可见,用户程序是看不到的
// 因此需要暴露出一个符号连接,该符号链接指向真正的设备名称
UNICODE_STRING SymLinkName;
RtlInitUnicodeString(&SymLinkName, L"\\??\\HelloDDK");
pDevExt->ustrSymLinkName = SymLinkName;
// 创建成功则返回,否则调用IoDeleteDevice删除设备
status = IoCreateSymbolicLink(&SymLinkName, &devName);
if(!NT_SUCCESS(status))
{
IoDeleteDevice(pDevObj);
return status;
}
return STATUS_SUCCESS;
}
// 定义驱动卸载函数
#pragma PAGEDCODE
VOID HelloDDKUnload(IN PDRIVER_OBJECT pDriverObject)
{
PDEVICE_OBJECT pNextObj;
KdPrint(("Enter DriverUnload\n"));
// 从驱动对象中获得设备对象
pNextObj = pDriverObject->DeviceObject;
// 遍历设备对象
while(pNextObj != NULL)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextObj->DeviceExtension;
// 删除符号链接
UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
// 删除设备对象的符号链接
IoDeleteSymbolicLink(&pLinkName);
pNextObj = pNextObj->NextDevice;
IoDeleteDevice(pDevExt->pDevice);
}
}
// 定义默认派遣例程
#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutine(
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
KdPrint(("Enter HelloDDKDispatchRoutine\n"));
NTSTATUS status = STATUS_SUCCESS;
// 完成IRP
// 关于IRP的介绍,在后面会介绍
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
KdPrint(("Leave HelloDDKDispatchRoutine\n"));
return status;
}
source
TARGETNAME=HelloDDK
TARGETTYPE=DRIVER
TARGETPATH=OBJ
INCLUDES=$(BASEDIR)\inc;\
$(BASEDIR)\inc\ddk;\
SOURCES=helloddk.cpp\
边栏推荐
- Selection sort
- [FreeRTOS interrupt experiment]
- Easyrecovery靠谱不收费的数据恢复电脑软件
- Etcd database source code analysis -- etcdserver bootstrap initialization storage
- Bubble sort
- SQL注入漏洞(MSSQL注入)
- Fuzzy -- basic application method of AFL
- 也算是学习中的小总结
- Scala function advanced
- [Chongqing Guangdong education] Suzhou University English film and Television Appreciation reference materials
猜你喜欢
Redis - redis in action - redis actual combat - actual combat Chapter 1 - SMS login function based on redis - redis + token shared session application - with code
The ECU of 21 Audi q5l 45tfsi brushes is upgraded to master special adjustment, and the horsepower is safely and stably increased to 305 horsepower
Embedded development program framework
Visio draw fan
View workflow
A blog to achieve embedded entry
yolov5 tensorrt加速
Mysql database storage engine
MPLS experiment
捷码赋能案例:专业培训、技术支撑,多措并举推动毕业生搭建智慧校园毕设系统
随机推荐
Redis has four methods for checking big keys, which are necessary for optimization
Nestjs配置文件上传, 配置中间件以及管道的使用
Yyds dry goods inventory OSI & tcp/ip
Word cover underline
Why does MySQL need two-phase commit
优秀PM必须经历这3层蜕变!
也算是学习中的小总结
也算是學習中的小總結
[数学建模] 微分方程--捕鱼业的持续发展
C'est un petit résumé de l'étude.
Basic explanation of turtle module - draw curve
Platformio create libopencm3 + FreeRTOS project
It is also a small summary in learning
Selection of slow motion function
Lagrange polynomial
cdc 能全量拉去oracle 表嘛
动态规划(树形dp)
Guitar Pro 8.0最详细全面的更新内容及全部功能介绍
Redis 排查大 key 的4種方法,優化必備
Mysql database storage engine