windows驱动分为:
- NT驱动(不支持即插即用)
- WDM驱动(支持即插即用)
NT驱动实例
//main.h
#pragma once
#pragma warning(disable:4100)
#ifdef _cplusplus
extern "C"
{
#endif
#include <NTDDK.h>
#ifdef _cplusplus
}
#endif // _cplusplus
#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#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]))
typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT pDevice;
UNICODE_STRING ustrDeviceName; //设备名称
UNICODE_STRING ustrSymLinkName; //符号链接名
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject);
VOID HelloDDKUnload(IN PDRIVER_OBJECT pDriverObject);
NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);
- Windows驱动开发中,所有程序的函数和变量都要被指明加载到分页内存还是非分页中
- 特殊函数DriverEntry必须要放到INIT标志内存中
- INIT标志的内存,只会在加载的时候载入内存,当驱动成功加载后,INIT标志内存将从内存总卸载掉
//main.cpp
#include "main.h"
#pragma INITCODE
extern "C" NTSTATUS DriverEntry(
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegisteyPath)
{
NTSTATUS status;
KdPrint(("Enter DriverEntry\n"));
//注册其他驱动调用函数入口
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"));
return status;
}
#pragma PAGEDCODE
NTSTATUS CreateDevice(
IN PDRIVER_OBJECT pDriverObject)
{
NTSTATUS status;
PDEVICE_OBJECT pDevObj;
PDEVICE_EXTENSION pDevExt;
//创建设备名称
UNICODE_STRING devName;
RtlInitUnicodeString(&devName, L"\\Device\\MyDDKDevice");
status = IoCreateDevice(pDriverObject,
sizeof(DEVICE_EXTENSION),
&devName,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&pDevObj);
if (!NT_SUCCESS(status))
return status;
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;
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);
IoDeleteDevice(pDevExt->pDevice);
pNextObj = pNextObj->NextDevice;
}
}
#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{
KdPrint(("Enter HelloDDKDispatchRoutine\n"));
NTSTATUS status = STATUS_SUCCESS;
//完成IRP
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
KdPrint(("Leave HelloDDKDispatchRouine\n"));
return status;
}
- KdPrint是一个宏,类似于TRACE,调试版本中将调用DbgPrint代替,发行版本中将什么也不做
- 设备对内存的操作分为两种:
BUFFERED_IO
和DO_DIRECT_IO
- 驱动程序包含两个名称:设备名(在内核态作为标识)、链接名(暴露给用户态作为标识)
- 由IO管理器调用卸载回调函数
WDM驱动实例
main.h
//main.h
#pragma once
#pragma warning(disable:4100)
#ifdef _cplusplus
extern "C"
{
#endif
#include <wdm.h>
#ifdef _cplusplus
}
#endif // _cplusplus
typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT fdo;
PDEVICE_OBJECT NextStackDevice; //设备对象
UNICODE_STRING ustrDeviceName; //设备名称
UNICODE_STRING ustrSymLinkName; //符号链接名
} DEVICE_EXTENSION, * PDEVICE_EXTENSION;
#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#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]))
NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject);
NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp);
void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject);
extern "C"
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
main.cpp
//main.cpp
#include "main.h"
#pragma INITCODE
extern "C" NTSTATUS DriverEntry(
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath)
{
KdPrint(("Enter DriverEntry\n"));
pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloWDMDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloWDMDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_READ] = HelloWDMDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMDispatchRoutine;
pDriverObject->DriverUnload = HelloWDMUnload;
KdPrint(("Leave DriverEntry\n"));
return STATUS_SUCCESS;
}
#pragma PAGEDCODE
NTSTATUS HelloWDMAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
PAGED_CODE();
KdPrint(("Enter HelloWDMAddDevice\n"));
NTSTATUS status;
PDEVICE_OBJECT fdo;
UNICODE_STRING devName;
RtlInitUnicodeString(&devName, L"\\Device\\MyWDMDevice");
status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
&devName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&fdo);
if (!NT_SUCCESS(status))
return status;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
pdx->fdo = fdo;
pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
UNICODE_STRING symLinkName;
RtlInitUnicodeString(&symLinkName, L"\\DosDevice\\HelloWDM");
pdx->ustrDeviceName = devName;
pdx->ustrSymLinkName = symLinkName;
status = IoCreateSymbolicLink(&symLinkName, &devName);
if (!NT_SUCCESS(status))
{
IoDeleteSymbolicLink(&pdx->ustrSymLinkName);
status = IoCreateSymbolicLink(&symLinkName, &devName);
if (!NT_SUCCESS(status))
{
return status;
}
}
fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
fdo->Flags &= ~DO_DEVICE_INITIALIZING;
KdPrint(("Leave HelloWDMAddDevice\n"));
return STATUS_SUCCESS;
}
#pragma PAGEDCODE
NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
{
PAGED_CODE();
KdPrint(("ENter HelloWDMPnp\n"));
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
static NTSTATUS(*fcntab[])(PDEVICE_EXTENSION pdx, PIRP Irp) =
{
DefaultPnpHandler, // IRP_MN_START_DEVICE
DefaultPnpHandler, // IRP_MN_QUERY_REMOVE_DEVICE
HandleRemoveDevice, // IRP_MN_REMOVE_DEVICE
DefaultPnpHandler, // IRP_MN_CANCEL_REMOVE_DEVICE
DefaultPnpHandler, // IRP_MN_STOP_DEVICE
DefaultPnpHandler, // IRP_MN_QUERY_STOP_DEVICE
DefaultPnpHandler, // IRP_MN_CANCEL_STOP_DEVICE
DefaultPnpHandler, // IRP_MN_QUERY_DEVICE_RELATIONS
DefaultPnpHandler, // IRP_MN_QUERY_INTERFACE
DefaultPnpHandler, // IRP_MN_QUERY_CAPABILITIES
DefaultPnpHandler, // IRP_MN_QUERY_RESOURCES
DefaultPnpHandler, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
DefaultPnpHandler, // IRP_MN_QUERY_DEVICE_TEXT
DefaultPnpHandler, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
DefaultPnpHandler, // IRP_MN_
DefaultPnpHandler, // IRP_MN_READ_CONFIG
DefaultPnpHandler, // IRP_MN_WRITE_CONFIG
DefaultPnpHandler, // IRP_MN_EJECT
DefaultPnpHandler, // IRP_MN_SET_LOCK
DefaultPnpHandler, // IRP_MN_QUERY_ID
DefaultPnpHandler, // IRP_MN_QUERY_PNP_DEVICE_STATE
DefaultPnpHandler, // IRP_MN_QUERY_BUS_INFORMATION
DefaultPnpHandler, // IRP_MN_DEVICE_USAGE_NOTIFICATION
DefaultPnpHandler, // IRP_MN_SURPRISE_REMOVAL
};
ULONG fcn = stack->MinorFunction;
if (fcn >= arraysize(fcntab)) //未知的IRP类别
{
status = DefaultPnpHandler(pdx, Irp); //对于未知的IRP类别,让DefaultPnpHandler处理
return status;
}
#if DBG
static char* fcnname[] =
{
"IRP_MN_START_DEVICE",
"IRP_MN_QUERY_REMOVE_DEVICE",
"IRP_MN_REMOVE_DEVICE",
"IRP_MN_CANCEL_REMOVE_DEVICE",
"IRP_MN_STOP_DEVICE",
"IRP_MN_QUERY_STOP_DEVICE",
"IRP_MN_CANCEL_STOP_DEVICE",
"IRP_MN_QUERY_DEVICE_RELATIONS",
"IRP_MN_QUERY_INTERFACE",
"IRP_MN_QUERY_CAPABILITIES",
"IRP_MN_QUERY_RESOURCES",
"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
"IRP_MN_QUERY_DEVICE_TEXT",
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
"",
"IRP_MN_READ_CONFIG",
"IRP_MN_WRITE_CONFIG",
"IRP_MN_EJECT",
"IRP_MN_SET_LOCK",
"IRP_MN_QUERY_ID",
"IRP_MN_QUERY_PNP_DEVICE_STATE",
"IRP_MN_QUERY_BUS_INFORMATION",
"IRP_MN_DEVICE_USAGE_NOTIFICATION",
"IRP_MN_SURPRISE_REMOVAL",
};
KdPrint(("PNP Request (%s)\n", fcnname[fcn]));
#endif //DBG
status = (*fcntab[fcn])(pdx, Irp);
KdPrint(("Leave HelloWDMPnp\n"));
return status;
}
#pragma PAGEDCODE
NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp)
{
PAGED_CODE();
KdPrint(("Enter DefaultPnpHandler\n"));
IoSkipCurrentIrpStackLocation(Irp);
KdPrint(("Leave DefaultPnpHandler\n"));
return IoCallDriver(pdx->NextStackDevice, Irp);
}
#pragma PAGEDCODE
NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
{
PAGED_CODE();
KdPrint(("Enter HandleRemoveDevice\n"));
Irp->IoStatus.Status = STATUS_SUCCESS;
NTSTATUS status = DefaultPnpHandler(pdx, Irp);
IoDeleteSymbolicLink(&pdx->ustrSymLinkName);
//调用IoDetachDevice()把fdo从设备链栈中断开
if (pdx->NextStackDevice)
IoDetachDevice(pdx->NextStackDevice);
//删除fdo
IoDeleteDevice(pdx->fdo);
KdPrint(("Leave HandleRemoveDevice\n"));
return status;
}
#pragma PAGEDCODE
NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
{
PAGED_CODE();
KdPrint(("Enter HelloWDMDispatchRoutine\n"));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
KdPrint(("Leave HelloWDMDispatchRoutine\n"));
return STATUS_SUCCESS;
}
#pragma PAGEDCODE
void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject)
{
PAGED_CODE();
KdPrint(("Enter HelloWdmUnload"));
KdPrint(("Leave HelloWdmUnload"));
}
DriverEntry
中添加了AddDevice
回调函数,此函数只会出现在WDM驱动中AddDevice
回调函数的作用是创建设备对象并由PNP(即插即用)管理器调用- 对PNP的IRP处理是NT驱动和WDM驱动的重大区别之一
- 在WDM驱动中,大部分卸载工作不在Unload回调中,而是放在了
IRP_MN_REMOVE_DEVICE
的IRP的处理函数中处理 PAGE_CODE
是一个宏,只在debug版本有效,当此例程所在中断请求级超过APC_LEVEL时,会产生一个断言,断言将使程序终止,并报告出错地址AddDevice
例程由PNP管理器负责调用,创建设备对象AddDevice
例程的参数,DriverObject
是由PNP管理器传递进来的初始化驱动对象(DriverEntry中的驱动对象),PhysicalDeviceObject
是PNP管理器传递进来的底层驱动设备对象(NT驱动中没有这个概念)