[WDM][翻译]A simple demo for WDM Driver develop
原文地址:http://www.codeproject.com/system/WDM_Driver_development.asp
引言(Introduction)
我们可以很容易找到许多研究应用程序层面上问题比如可换肤对话框、MFC、ATL、线程、进程、注册表等等的文章,但是你很难找到附带有完整源代码的关于驱动程序开发的文章,导致这种现象的根源在于大多数的驱动程序是为特定的硬件开发的,没有相关领域的知识,你几乎永远不能也不可能接触到它们。我相信许多软件工程师第一次涉足内核模式编程时内心都是十分“恐惧”的,而且从DDK学习到编程阶段整个过程中能找到的资源是极端匮乏的,因此,我决定和大家分享我在Windows平台上开发驱动程序的一些经验。本文着重于快速介绍WDM驱动程序的架构、介绍伴随Windows而来的两种I/O模式:直接I/O(Direct I/O)和缓冲I/O(Buffered I/O)、如何与驻留在系统内核地址空间中的驱动程序通讯并且如何向其读写数据。
阅读演示程序是不需要任何硬件相关的背景知识,这些演示程序都是一些伪驱动程序(我更愿意叫它纯软件驱动),也就是说这些驱动程序并不与计算机上的任何物理设备相关。
你可以把那些在演示程序中定义的成员函数用作未来开发驱动程序的样板。
背景(Background)
你必须是一个经验丰富的软件工程师,而且想涉足内核编程领域。
创建你自己的WDM驱动程序:伪驱动程序 教程
在开始之前,你必须声明成员函数以及相关结构,最重要的驱动程序需要的数据结构就是:DEVICE_EXTENSION!
typedef struct tagDEVICE_EXTENSION {
PDEVICE_OBJECT DeviceObject; // device object this driver creates
// next-layered device object in this device stack
PDEVICE_OBJECT NextDeviceObject;
DEVICE_CAPABILITIES pdc; // device capability
IO_REMOVE_LOCK RemoveLock; // removal control locking structure
LONG handles; // # open handles
PVOID DataBuffer; // Internal Buffer for Read/Write I/O
UNICODE_STRING Device_Description; // Device Description
SYSTEM_POWER_STATE SysPwrState; // Current System Power State
DEVICE_POWER_STATE DevPwrState; // Current Device Power State
PIRP PowerIrp; // Current Handling Power-Related IRP
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
下面的代码片断展示了如何开始创建一个合法的WDM驱动程序。
在WDM驱动程序中,有些成员是必需而有些成员是可选的。在一个合法的WDM驱动程序中一般都有下面这些成员过程,DriverEntry最重要的任务就是向内核注册这些成员过程。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
RtlInitUnicodeString(&Global_sz_Drv_RegInfo, RegistryPath->Buffer);

// Initialize function pointers
DriverObject->DriverUnload = DriverUnload;
DriverObject->DriverExtension->AddDevice = AddDevice;
DriverObject->MajorFunction[IRP_MJ_CREATE] = PsdoDispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = PsdoDispatchClose;
DriverObject->MajorFunction[IRP_MJ_READ] = PsdoDispatchRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = PsdoDispatchWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PsdoDispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_POWER] = PsdoDispatchPower;
DriverObject->MajorFunction[IRP_MJ_PNP] = PsdoDispatchPnP;

return STATUS_SUCCESS;
}
NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
ULONG DeviceExtensionSize;
PDEVICE_EXTENSION p_DVCEXT;
PDEVICE_OBJECT ptr_PDO;
NTSTATUS status;

RtlInitUnicodeString(&Global_sz_DeviceName, L"");
// Get DEVICE_EXTENSION required memory space
DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
// Create Device Object
status = IoCreateDevice(DriverObject,
DeviceExtensionSize,
&Global_sz_DeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&ptr_PDO);
if (NT_SUCCESS(status))
{
ptr_PDO->Flags &= ~DO_DEVICE_INITIALIZING;
ptr_PDO->Flags |= DO_BUFFERED_IO; //For Buffered I/O
// ptr_PDO->Flags |= DO_DIRECT_IO; //For Direct I/O
p_DVCEXT = ptr_PDO->DeviceExtension;
p_DVCEXT->DeviceObject = ptr_PDO;
RtlInitUnicodeString(

/*
// Other initialization tasks go here
*/

// Store next-layered device object
// Attach device object to device stack
p_DVCEXT->NextDeviceObject =
IoAttachDeviceToDeviceStack(ptr_PDO, PhysicalDeviceObject);
}

return status;
}
引言(Introduction)
我们可以很容易找到许多研究应用程序层面上问题比如可换肤对话框、MFC、ATL、线程、进程、注册表等等的文章,但是你很难找到附带有完整源代码的关于驱动程序开发的文章,导致这种现象的根源在于大多数的驱动程序是为特定的硬件开发的,没有相关领域的知识,你几乎永远不能也不可能接触到它们。我相信许多软件工程师第一次涉足内核模式编程时内心都是十分“恐惧”的,而且从DDK学习到编程阶段整个过程中能找到的资源是极端匮乏的,因此,我决定和大家分享我在Windows平台上开发驱动程序的一些经验。本文着重于快速介绍WDM驱动程序的架构、介绍伴随Windows而来的两种I/O模式:直接I/O(Direct I/O)和缓冲I/O(Buffered I/O)、如何与驻留在系统内核地址空间中的驱动程序通讯并且如何向其读写数据。
阅读演示程序是不需要任何硬件相关的背景知识,这些演示程序都是一些伪驱动程序(我更愿意叫它纯软件驱动),也就是说这些驱动程序并不与计算机上的任何物理设备相关。
你可以把那些在演示程序中定义的成员函数用作未来开发驱动程序的样板。
背景(Background)
你必须是一个经验丰富的软件工程师,而且想涉足内核编程领域。
创建你自己的WDM驱动程序:伪驱动程序 教程
在开始之前,你必须声明成员函数以及相关结构,最重要的驱动程序需要的数据结构就是:DEVICE_EXTENSION!
typedef struct tagDEVICE_EXTENSION {
PDEVICE_OBJECT DeviceObject; // device object this driver creates
// next-layered device object in this device stack
PDEVICE_OBJECT NextDeviceObject;
DEVICE_CAPABILITIES pdc; // device capability
IO_REMOVE_LOCK RemoveLock; // removal control locking structure
LONG handles; // # open handles
PVOID DataBuffer; // Internal Buffer for Read/Write I/O
UNICODE_STRING Device_Description; // Device Description
SYSTEM_POWER_STATE SysPwrState; // Current System Power State
DEVICE_POWER_STATE DevPwrState; // Current Device Power State
PIRP PowerIrp; // Current Handling Power-Related IRP
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

在WDM驱动程序中,有些成员是必需而有些成员是可选的。在一个合法的WDM驱动程序中一般都有下面这些成员过程,DriverEntry最重要的任务就是向内核注册这些成员过程。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
RtlInitUnicodeString(&Global_sz_Drv_RegInfo, RegistryPath->Buffer);
// Initialize function pointers
DriverObject->DriverUnload = DriverUnload;
DriverObject->DriverExtension->AddDevice = AddDevice;
DriverObject->MajorFunction[IRP_MJ_CREATE] = PsdoDispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = PsdoDispatchClose;
DriverObject->MajorFunction[IRP_MJ_READ] = PsdoDispatchRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = PsdoDispatchWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PsdoDispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_POWER] = PsdoDispatchPower;
DriverObject->MajorFunction[IRP_MJ_PNP] = PsdoDispatchPnP;
return STATUS_SUCCESS;
}

WDM驱动程序的一般工作流程
下面的代码片断演示了AddDevice过程的流程:AddDevice过程的最重要任务就是创建一个设备对象,并且将它挂到已经存在的设备堆栈上。
NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
ULONG DeviceExtensionSize;
PDEVICE_EXTENSION p_DVCEXT;
PDEVICE_OBJECT ptr_PDO;
NTSTATUS status;
RtlInitUnicodeString(&Global_sz_DeviceName, L"");
// Get DEVICE_EXTENSION required memory space
DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
// Create Device Object
status = IoCreateDevice(DriverObject,
DeviceExtensionSize,
&Global_sz_DeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&ptr_PDO);
if (NT_SUCCESS(status))
{
ptr_PDO->Flags &= ~DO_DEVICE_INITIALIZING;
ptr_PDO->Flags |= DO_BUFFERED_IO; //For Buffered I/O
// ptr_PDO->Flags |= DO_DIRECT_IO; //For Direct I/O
p_DVCEXT = ptr_PDO->DeviceExtension;
p_DVCEXT->DeviceObject = ptr_PDO;
RtlInitUnicodeString(
/*
// Other initialization tasks go here
*/
// Store next-layered device object
// Attach device object to device stack
p_DVCEXT->NextDeviceObject =
IoAttachDeviceToDeviceStack(ptr_PDO, PhysicalDeviceObject);
}
return status;
}
未完待续...


浙公网安备 33010602011771号