Windows 驱动开发笔记(三)

来源:互联网 发布:网络七层协议都有什么 编辑:程序博客网 时间:2024/06/11 08:51

Windows 驱动开发笔记(三)
一个驱动程序在加载之后第一个调用初始化例程。初始化例程负责向系统注册各种服务例程。这之后,各种服务例程就等待系统的调用了。用户不直接的调用对应的服务例程。而是通过系统的管理例程调用服务例程。用户的调用是被包装过的。那么,写一个驱动大概需要哪些例程呢?下面就简单的介绍一下:
驱动程序的组成:初始化例程、增加-设备例程、I/O处理例程组、启动I/O例程、中断服务例程、后继中断服务例程DPC、其它例程。
下面我们逐一介绍一下。
初始化例程:
这个例程是驱动的入口DriverEntry (IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)在系统加载驱动时,将被执行。他负责驱动程序的初始化。填充DriverObject数据结构。注册其它的服务例程。
增加-设备例程:
这个例程通常负责向系统申请一个设备对象。这个设备对象对应着一个物理的或逻辑的设备。一个驱动程序对象可以对应一个或多个设备对象。反过来说,多个设备可以共享一个驱动对象。这个例程通常调用ioCreateDevice函数来创建设备对象。这个例程通常写在一个函数里。这个函数注册到驱动对象里。对于既插即用设备。系统在探测到一个设备存在时。发出消息。通知驱动程序对象调用该例程来创建设备对象。对于非既插即用设备,他们通常在初始化例程中调用该例程。
I/O处理例程组:
I/O处理例程对应着用户的各种调用。如:打开设备、读取设备、写设备、关闭设备等功能。各一个I/O处理例程完成对应的调用操作。根据设备的要求编写各种I/O处理例程。I/O处理例程通常处理IRP的一个消息。他的调用有系统根据IRP来调用。
启动I/O例程:
对于一些要求具有一定I/O处理顺序的设备需要该例程来给任务排队。保证每次只处理一个IRP。避免并发的处理IRP。
中断服务例程:
当设备有中断请求时,需要编写该例程。完成中断处理。中断处理应该尽快地处理。不要占用大量的时间。避免阻碍低优先级的中断。为了能够尽快地处理中断。可以把任务分成两部分来执行。必要独占的在该例程中处理。可以被中断的放在DPC中完成处理。
后继中断服务例程DPC:
完成后继中断服务。该例程在比中断服务例程低的优先级中执行。
其它例程:
一些有特殊要求的处理。可以参考其它资料。
下面再介绍一个例子。说明怎样建立一个可以在设备列表中注册的程序。
这个程序是罗聪前辈写的。我在此借用。
HelloWDM.C

/***************************************************************
程序名称:Hello World for WDM
文件名称:HelloWDM.C
日期:2002-8-16
***************************************************************/
//一定要的头文件,声明了函数模块和变量:
#include "HelloWDM.h"

/***************************************************************
函数名称:DriverEntry()
功能描述:WDM程序入口
***************************************************************/

NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
//注册“添加设备”消息。由函数“HelloWDMAddDevice()”来处理:
DriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
//注册“即插即用”消息。由函数“HelloWDMPnp()”来处理:
DriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;

//返回一个NTSTATUS值STATUS_SUCCESS。几乎所有的驱动程序例程都必须返回一个NTSTATUS值,这些值在NTSTATUS.H DDK头文件中有详细的定义。
return STATUS_SUCCESS;
}


/***************************************************************
函数名称:HelloWDMAddDevice()
功能描述:处理“添加设备”消息
***************************************************************/
NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
//定义一个NTSTATUS类型的返回值:
NTSTATUS status;
//定义一个功能设备对象(Functional Device Object):
PDEVICE_OBJECT fdo;
//创建一个设备扩展对象dx,用于存储指向fdo的指针:
PDEVICE_EXTENSION dx;
//创建我们的功能设备对象,并储存到fdo中:
status = IoCreateDevice(
DriverObject, //驱动程序对象
sizeof(DEVICE_EXTENSION), //要求的设备扩展的大小
NULL, //设备名称,这里为NULL
FILE_DEVICE_UNKNOWN, //设备的类型,在标准头文件WDM.H或NTDDK.H中列出的FILE_DEVICE_xxx值之一
0, //各种常量用OR组合在一起,指示可删除介质、只读等。
FALSE, //如果一次只有一个线程可以访问该设备,为TRUE,否则为FALSE
&fdo); //返回的设备对象

//NT_SUCCESS宏用于测试IoCreateDevice内核是否成功完成。不要忘记检查对内核的所有调用是否成功。NT_ERROR宏不等同于!NT_SUCCESS,最好使用!NT_SUCCESS,因为除了错误外,它还截获警告信息。
if( !NT_SUCCESS(status))
return status;

//创建一个设备扩展对象dx,用于存储指向fdo的指针:
dx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
dx->fdo = fdo;

//用IoAttachDeviceToDeviceStack函数把HelloWDM设备挂接到设备栈:
dx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);

//设置fdo的flags。有两个“位”是必须改变的,一个是必须清除DO_DEVICE_INITIALIZING标志,如果在DriverEntry例程中调用IoCreateDevice(),就不需要清除这个标志位。还有一个是必须设置DO_BUFFER_IO标志位:
fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
fdo->Flags &= ~DO_DEVICE_INITIALIZING;

//返回值:
return STATUS_SUCCESS;
}


/***************************************************************
函数名称:HelloWDMPnp()
功能描述:处理“即插即用”消息
***************************************************************/
NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,
IN PIRP Irp)
{
//创建一个设备扩展对象dx,用于存储指向fdo的指针:
PDEVICE_EXTENSION dx=(PDEVICE_EXTENSION)fdo->DeviceExtension;
//定义返回设备值
NTSTATUS status;
//首先要通过函数IoGetCurrentIrpStackLocation()得到当前的IRP,并由此得到Minor Function:
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG MinorFunction = IrpStack->MinorFunction;

//然后把这个Minor Function传递给下一个设备栈:
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver( dx->NextStackDevice, Irp);

//处理“即插即用”次功能代码:
//当Minor Function等于IRP_MN_REMOVE_DEVICE时,说明有设备被拔出或卸下,这时要取消资源分配并删除设备:
if( MinorFunction==IRP_MN_REMOVE_DEVICE)
{
//取消设备接口:
IoSetDeviceInterfaceState(&dx->ifSymLinkName, FALSE);
RtlFreeUnicodeString(&dx->ifSymLinkName);

//调用IoDetachDevice()把fdo从设备栈中脱开:
if (dx->NextStackDevice)
IoDetachDevice(dx->NextStackDevice);
//删除fdo:
IoDeleteDevice(fdo);
}

//返回值:
return status;
}

HelloWDM.h文件

/***************************************************************
程序名称:Hello World for WDM
文件名称:HelloWDM.h
日期:2002-8-16
***************************************************************/

#include "ntddk.h"

typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT fdo;
PDEVICE_OBJECT NextStackDevice;
UNICODE_STRING ifSymLinkName;

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject);

NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,IN PIRP Irp);



makefile文件,内容不变

#
# DO NOT EDIT THIS FILE!!! Edit ./sources. if you want to add a new source
# file to this component. This file merely indirects to the real make file
# that is shared by all the driver components of the Windows NT DDK
#

!INCLUDE $(NTMAKEENV)/makefile.def

sources文件

TARGETNAME=HelloWDM
TARGETPATH=obj
TARGETTYPE=DRIVER

SOURCES= Hellowdm.c

象上面的例子一样编译执行!产生一个HelloWDM.sys的文件。

为了能安装这个驱动还需要一个INF安装文件。

helloWDM.inf 文件


;; The Win2K DDK documentation contains an excellent INF reference.

;--------- Version Section ---------------------------------------------------

[Version]
Signature="$CHICAGO$"
Provider=LC_Device
DriverVer=8/21/2002,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=Unknown
ClassGUID={ff646f80-8def-11d2-9449-00105a075f6b}

;--------- 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,objfre/i386,

;--------- 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
;
%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="Flying L Co.,Ltd."
MfgName="LC Soft"
DeviceDesc="Hello World WDM!"
DeviceClassName="LC_Device"
SvcDesc="???"

好了我们可以安装这个设备了。打开控制面板,双击“添加/删除硬件”,选择“添加/排除设备故障”->“添加新设备”->“否,我想从列表选择硬件”->“其它设备”->“从磁盘安装”,选择 HelloWDM.INF 所在的路径,然后安装。
完成后可以在设备列表中看到该设备了。
后面的试验就给这个例程增加功能和用户应用。

原创粉丝点击