您的位置:首页 > 其它

NT驱动程序和WDM驱动程序的区别

2017-07-21 13:59 681 查看
1.Windows驱动程序分为两类,一类是不支持即插即用功能的NT式的驱动程序;另一类是支持即插即用功能的WDM式的驱动程序。

2.NT式的驱动程序要导入的头文件时NTDDK.H,而WDM式的驱动要导入的头文件为WDM.H.

3.DriverEntry需要放在INIT标志的内存中。INIT标志指明该函数只是在加载的时候需要载入内存,而当驱动程序加载成功后,该函数可以从内存中卸载掉。

4.C++编写驱动需要注意:

[cpp] view
plain copy

#ifdef __cplusplus

extern “C”

{

#endif

#include <NTDDK.H>

#ifdef __cplusplus

}

#endif

#pragma INITCODE extern “C” NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath){}

5.来看一个简单的NT式驱动

Driver.h:

[cpp] view
plain copy

#pragma once

#ifdef __cplusplus

extern "C"

{

#endif

#include <NTDDK.h>

#ifdef __cplusplus

}

#endif

#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);

driver.cpp

[cpp] view
plain copy

/************************************************************************

* 函数名称:DriverEntry

* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象

* 参数列表:

pDriverObject:从I/O管理器中传进来的驱动对象

pRegistryPath:驱动程序在注册表的中的路径

* 返回 值:返回初始化驱动状态

*************************************************************************/

#pragma INITCODE

extern "C" NTSTATUS DriverEntry (

IN PDRIVER_OBJECT pDriverObject,

IN PUNICODE_STRING pRegistryPath )

{

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;

}

/************************************************************************

* 函数名称:CreateDevice

* 功能描述:初始化设备对象

* 参数列表:

pDriverObject:从I/O管理器中传进来的驱动对象

* 返回 值:返回初始化状态

*************************************************************************/

#pragma INITCODE //指明此函数加载到INIT内存区域(即只在加载的时候需要载入内存,加载成功后可以从内存中卸载掉)

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),

&(UNICODE_STRING)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;

}

/************************************************************************

* 函数名称:HelloDDKUnload

* 功能描述:负责驱动程序的卸载操作

* 参数列表:

pDriverObject:驱动对象

* 返回 值:返回状态

*************************************************************************/

#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 );

}

}

/************************************************************************

* 函数名称:HelloDDKDispatchRoutine

* 功能描述:对读IRP进行处理

* 参数列表:

pDevObj:功能设备对象

pIrp:从IO请求包

* 返回 值:返回状态

*************************************************************************/

#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; // bytes xfered

IoCompleteRequest( pIrp, IO_NO_INCREMENT );

KdPrint(("Leave HelloDDKDispatchRoutine\n"));

return status;

}

驱动虽然有了设备名称,但是这种设备名只能在内核态可见,而对于应用程序时不可见的。因此,驱动需要暴露一个符号链接,该链接指向真正的设备名称。

编译好生成的sys文件,我们可以使用DriverMonitor加载,加载->启动->停止->卸载。

6.再来看看WDM式驱动有什么不同。头文件就直接忽略了。

DriverEntry入口函数:

[cpp] view
plain copy

/************************************************************************

* 函数名称:DriverEntry

* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象

* 参数列表:

pDriverObject:从I/O管理器中传进来的驱动对象

pRegistryPath:驱动程序在注册表的中的路径

* 返回 值:返回初始化驱动状态

*************************************************************************/

#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] =

pDriverObject->MajorFunction[IRP_MJ_CREATE] =

pDriverObject->MajorFunction[IRP_MJ_READ] =

pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMDispatchRoutine;

pDriverObject->DriverUnload = HelloWDMUnload;

KdPrint(("Leave DriverEntry\n"));

return STATUS_SUCCESS;

}

这里增加了一个设置AddDevice回调函数,此回调函数的作用是创建设备对象并由PNP(即插即用)管理器调用。并设置对IRP_MJ_PNP的IRP的回调函数。这都是NT和WDM驱动最大的不同点。而且在WDM驱动中,大部分卸载工作都不是由DriverUnload来处理,而是放在对IRP_MN_REMOVE_DEVICE的IRP的处理函数中处理。

下面是AddDevice回调函数的处理。

[cpp] view
plain copy

/************************************************************************

* 函数名称:HelloWDMAddDevice

* 功能描述:添加新设备

* 参数列表:

DriverObject:从I/O管理器中传进来的驱动对象

PhysicalDeviceObject:从I/O管理器中传进来的物理设备对象

* 返回 值:返回添加新设备状态

*************************************************************************/

#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),

&(UNICODE_STRING)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"\\DosDevices\\HelloWDM");

pdx->ustrDeviceName = devName;

pdx->ustrSymLinkName = symLinkName;

status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)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;

}

其中PAGED_CODE是一个DDK提供的宏,只在check版中有效。当此例程所在的中断请求及超过APC_LEVEL时,会产生一个断言。

本例对IRP_MN_REMOVE_DEVICE的处理。

[cpp] view
plain copy

/************************************************************************

* 函数名称:HandleRemoveDevice

* 功能描述:对IRP_MN_REMOVE_DEVICE IRP进行处理

* 参数列表:

fdo:功能设备对象

Irp:从IO请求包

* 返回 值:返回状态

*************************************************************************/

#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(&(UNICODE_STRING)pdx->ustrSymLinkName);

//调用IoDetachDevice()把fdo从设备栈中脱开:

if (pdx->NextStackDevice)

IoDetachDevice(pdx->NextStackDevice);

//删除fdo:

IoDeleteDevice(pdx->fdo);

KdPrint(("Leave HandleRemoveDevice\n"));

return status;

}

而对卸载例程的处理可以什么都不用做。

其他PNP的IRP如果不需要做处理,那么直接传递到底层驱动,并将底层驱动的结果返回。

[cpp] view
plain copy

/************************************************************************

* 函数名称:DefaultPnpHandler

* 功能描述:对PNP IRP进行缺省处理

* 参数列表:

pdx:设备对象的扩展

Irp:从IO请求包

* 返回 值:返回状态

*************************************************************************/

#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);

}

安装WDM式驱动需要一个inf文件。inf文件描述了WDM驱动程序的操作硬件设备的信息和驱动程序的一些信息。

可以直接右击这个inf文件进行安装即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: