📄 adddevice.txt
字号:
//DriverObject参数指向一个驱动程序对象,就是你在DriverEntry例程中初始化的那个驱动程序对象。
//pdo参数指向设备堆栈底部的物理设备对象。
NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo)
{
//调用IoCreateDevice创建设备对象,并建立一个私有的设备扩展对象。
PDEVICE_OBJECT fdo;
NTSTATUS status = IoCreateDevice(DriverObject,//就是AddDevice的第一个参数。该参数用于在驱动
//程序和新设备对象之间建立连接,这样I/O管理器
//就可以向设备发送指定的IRP。
sizeof(DEVICE_EXTENSION),//设备扩展结构的大小。I/O管理器自
//动分配这个内存,并把设备对象中的
//DeviceExtension指针指向这块内存。
NULL, //它可以是命名该设备对象的UNICODE_STRING串的地址
FILE_DEVICE_UNKNOWN,//设备类型
FILE_DEVICE_SECURE_OPEN,//设备对象提供Characteristics标志
FALSE, //指出设备是否是排斥的
&fdo); //是存放设备对象指针的地址,IoCreateDevice函数使用该
//变量保存刚创建设备对象的地址
NTSTATUS status = IoCreateDevice(...); //如果IoCreateDevice由于某种原因失败,则它返回一个错
//误代码,不改变fdo中的值。如果IoCreateDevice函数返回
//成功代码,那么它同时也设置了fdo指针。然后我们进行到
//下一步,初始化设备扩展,做与创建新设备对象相关的其它
//工作,如果在这之后又发现了错误,那么在返回前应先释放刚
//创建的设备对象并返回状态码
if (!NT_SUCCESS(status))
return status;
...
if (<some other error discovered>)
{
IoDeleteDevice(fdo);
return status;
}
//如果我们使用设备名COM1,那么最终收到该IRP的将是\Device\Serial0的驱动程序。
//用户模式程序可以调用DefineDosDevice创建一个符号连接,如下例:
BOOL okay = DefineDosDevice(DDD_RAW_TARGET_PATH, "barf", "\\Device\\SECTEST_0");
//如果你需要在WDM驱动程序中创建一个符号连接,可以调用IoCreateSymbolicLink函数:
IoCreateSymbolicLink(linkname, targname);//linkname是要创建的符号连接名,targname是要连接的名字。
//设备命名 方法一使用带有硬编码性质的名称
UNICODE_STRING devname;
RtlInitUnicodeString(&devname, L"\\Device\\Simple0");
IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &devname, ...);
//方法二 串操作函数动态地合成一个名字
UNICODE_STRING devname;
static LONG lastindex = -1;/从私有设备类型得出的实例号应该是一个静态变量。
LONG devindex = InterlockedIncrement(&lastindex);
WCHAR name[32];
_snwprintf(name, arraysize(name), L"\\Device\\SIMPLE%2.2d", devindex);
RtlInitUnicodeString(&devname, name);
IoCreateDevice(...);
//定义设备扩展
typedef struct _DEVICE_EXTENSION { <--1
PDEVICE_OBJECT DeviceObject; <--2
PDEVICE_OBJECT LowerDeviceObject; <--3
PDEVICE_OBJECT Pdo; <--4
UNICODE_STRING ifname; <--5
IO_REMOVE_LOCK RemoveLock; <--6
DEVSTATE devstate; <--7
DEVSTATE prevstate;
DEVICE_POWER_STATE devpower;
SYSTEM_POWER_STATE syspower;
DEVICE_CAPABILITIES devcaps; <--8
...
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
//初始化设备扩展
PDEVICE_OBJECT fdo;
IoCreateDevice(..., sizeof(DEVICE_EXTENSION), ..., &fdo);
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
pdx->DeviceObject = fdo;
pdx->Pdo = pdo;
IoInitializeRemoveLock(&pdx->RemoveLock, ...);
pdx->devstate = STOPPED;
pdx->devpower = PowerDeviceD0;
pdx->syspower = PowerSystemWorking;
IoRegisterDeviceInterface(..., &pdx->ifname);
pdx->LowerDeviceObject = IoAttachDeviceToDeviceStack(...);
//初始化默认的DPC对象
IoCreateDevice(...);
IoInitializeDpcRequest(fdo, DpcForIsr);
//设置缓冲区对齐掩码方法一
PVOID address = ...;
SIZE_T ar = fdo->AlignmentRequirement;
address = (PVOID) ((SIZE_T) address & ~ar);
//方法二
PVOID address = ...;
SIZE_T ar = fdo->AlignmentRequirement;
address = (PVOID) (((SIZE_T) address + ar) & ~ar);
//设置初始电源状态
POWER_STATE state;
state.DeviceState = PowerDeviceD0;
PoSetPowerState(fdo, DevicePowerState, state);
//建立设备堆
PDEVICE_OBJECT fdo;
IoCreateDevice(..., &fdo);
pdx->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);
}
//清除DO_DEVICE_INITIALIZING标志
fdo->Flags &= ~DO_DEVICE_INITIALIZING;
当这个标志设置时,I/O管理器将拒绝任何打开该设备句柄的请求或向该设备对象
上附着其它设备对象的请求。在驱动程序完成初始化后,必须清除这个标志。
//注册设备接口
#include <initguid.h> <--1
#include "guids.h" <--2
...
NTSTATUS AddDevice(...)
{
...//IoRegisterDeviceInterface的第一个参数必须是设备PDO的地址。
//第二个参数指出与接口关联的GUID,第三个参数指出额外的接口细分类名。
//只有Microsoft的代码才使用名称细分类方案。第四个参数是一个UNICODE_STRING串的地址,
//该串用于接收设备对象的符号连接名。
IoRegisterDeviceInterface(pdo, &GUID_SIMPLE, NULL, &pdx->ifname); <--3
...
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -