再来看基于WDM的驱动程序,
#ifdef __cplusplus
extern
"
C
"
{
#endif
#include
<
wdm.h
>
#ifdef __cplusplus
}
#endif
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);
void
HelloWDMUnload(IN PDRIVER_OBJECT DriverObject);
extern
"
C
"
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath);
HelloWDM.cpp
#include "HelloWDM.h"
/************************************************************************
* 函数名称: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;
}
/************************************************************************
* 函数名称: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;
}
/************************************************************************
* 函数名称: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);
}
/************************************************************************
* 函数名称: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;
}
/************************************************************************
* 函数名称:HelloWDMPnp
* 功能描述:对即插即用IRP进行处理
* 参数列表:
fdo:功能设备对象
Irp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#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, //
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))
{ // 未知的子功能代码
status = DefaultPnpHandler(pdx, Irp); // some function we don't know about
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;
}
/************************************************************************
* 函数名称:HelloWDMDispatchRoutine
* 功能描述:对缺省IRP进行处理
* 参数列表:
fdo:功能设备对象
Irp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#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; // no bytes xfered
IoCompleteRequest( Irp, IO_NO_INCREMENT );
KdPrint(("Leave HelloWDMDispatchRoutine\n"));
return STATUS_SUCCESS;
}
/************************************************************************
* 函数名称:HelloWDMUnload
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
DriverObject:驱动对象
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject)
{
PAGED_CODE();
KdPrint(("Enter HelloWDMUnload\n"));
KdPrint(("Leave HelloWDMUnload\n"));
}
同前面一样,编译也是两种方式,第一种用DDK编译,准备两个脚本文件,makefile和Sources,其中Sources有所不同,如下所示:
TARGETNAME
=
HelloWDM
TARGETTYPE
=
DRIVER
DRIVERTYPE
=
WDM
TARGETPATH
=
OBJ
INCLUDES
=$(
BASEDIR
)\
inc
;\
$(
BASEDIR
)\
inc
\
ddk
;\
SOURCES
=
HelloWDM
.
cpp
\
另一种是用VC进行编译,有三点需要注意:
1, 选择c/c++选项卡,将原来的Project Options全删掉,换成下面的:
/
nologo
/
Gz
/
MLd
/
W3
/
WX
/
Z7
/
Od
/
D WIN32
=
100
/
D _X86_
=
1
/
D WINVER
=
0x500
/
D DBG
=
1
/
Fo
"
MyDriver_Check/
"
/
Fd
"
MyDriver_Check/
"
/
FD
/
c
2, 选择Link选项卡,将原来的Project Options全删掉,换成下面的:
wdm
.
lib
/
nologo
/
base:
"
0x10000
"
/
stack:
0x400000
,
0x1000
/
entry:
"
DriverEntry
"
/
subsystem
:console
/
incremental
:no
/
pdb:
"
MyDriver_Check/HelloWDM.pdb
"
/
debug
/
machine
:I386
/
nodefaultlib
/
out:
"
MyDriver_Check/HelloWDM.sys
"
/
pdbtype
:sept
/
subsystem
:native
/
driver
/
SECTION
:INIT
,
D
/
RELEASE
/
IGNORE:
4078
3, 修改include目录时,加入
D:
\
WINDDK
\
3790.1830
\
INC
\
DDK
\
WDM
\
W2K
否则会报错如下:
fatal error C1083: Cannot open include file: 'wdm
.
h': No such file or directory
最后是驱动的安装,WDM驱动的安装需要写一个inf文件,如下所示:
;
--------- Version Section ---------------------------------------------------
[Version]
Signature
=
"
$CHICAGO$
"
;
Provider
=
Phinecos_Device
DriverVer
=
20
/
2
/
2000
,
3.0
.
0.3
;
If
device
fits one of the standard classes
,
use
the name and GUID here
,
;
otherwise create your own
device
class and GUID as this example shows
.
Class
=
PhinecosDevice
ClassGUID
=
{EF2962F0-0D55-4bff-B8AA-2221EE8A79B0}
;
--------- SourceDiskNames and SourceDiskFiles Section -----------------------
;
These sections identify source disks and
files
for
installation
.
They are
;
shown here as an example
,
but commented out
.
[SourceDisksNames]
1
=
"
HelloWDM
"
,
Disk1
,,
[SourceDisksFiles]
HelloWDM
.
sys
=
1
,
MyDriver_Check
,
;
--------- ClassInstall
/
ClassInstall32 Section -------------------------------
;
Not
necessary
if
using a standard class
;
9X Style
[ClassInstall]
Addreg
=
Class_AddReg
;
NT Style
[ClassInstall32]
Addreg
=
Class_AddReg
[Class_AddReg]
HKR
,,,,
%DeviceClassName%
HKR
,,
Icon
,,
"
-5
"
;
--------- DestinationDirs Section -------------------------------------------
[DestinationDirs]
YouMark_Files_Driver
=
10
,
System32
\
Drivers
;
--------- Manufacturer and Models Sections ----------------------------------
[Manufacturer]
%MfgName%
=
Mfg0
[Mfg0]
;
PCI hardware Ids
use
the form
;
PCI
\
VEN_aaaa&DEV_bbbb&SUBSYS_cccccccc&REV_dd
;
改成你自己的ID
%DeviceDesc%
=
YouMark_DDI
,
PCI
\
VEN_9999&DEV_9999
;
---------- DDInstall Sections -----------------------------------------------
;
--------- Windows 9X -----------------
;
Experimentation has shown that DDInstall root names greater than
19
characters
;
cause problems in Windows
98
[YouMark_DDI]
CopyFiles
=
YouMark_Files_Driver
AddReg
=
YouMark_9X_AddReg
[YouMark_9X_AddReg]
HKR
,,
DevLoader
,,
*ntkern
HKR
,,
NTMPDriver
,,
HelloWDM
.
sys
HKR
,
"
Parameters
"
,
"
BreakOnEntry
"
,
0x00010001
,
0
;
--------- Windows NT -----------------
[YouMark_DDI
.
NT]
CopyFiles
=
YouMark_Files_Driver
AddReg
=
YouMark_NT_AddReg
[YouMark_DDI
.
NT
.
Services]
Addservice
=
HelloWDM
,
0x00000002
,
YouMark_AddService
[YouMark_AddService]
DisplayName
=
%SvcDesc%
ServiceType
=
1
;
SERVICE_KERNEL_DRIVER
StartType
=
3
;
SERVICE_DEMAND_START
ErrorControl
=
1
;
SERVICE_ERROR_NORMAL
ServiceBinary
=
%10
%
\
System32
\
Drivers
\
HelloWDM
.
sys
[YouMark_NT_AddReg]
HKLM
,
"
System\CurrentControlSet\Services\HelloWDM\Parameters
"
,\
"
BreakOnEntry
"
,
0x00010001
,
0
;
---------
Files
(
common
)
-------------
[YouMark_Files_Driver]
HelloWDM
.
sys
;
--------- Strings Section ---------------------------------------------------
[Strings]
ProviderName
=
"
Phinecos.
"
MfgName
=
"
Vista Soft
"
DeviceDesc
=
"
Hello World WDM!
"
DeviceClassName
=
"
Phinecos_Device
"
SvcDesc
=
"
Phinecos
"
这里有两种安装方式,一种是进入“控制面板”,选择添加硬件,加载进inf文件完成安装,如图所示:
另一种可选的安装测试方式是使用Driver Studio中的EzDriverInstaller工具来进行安装,如图所示: