最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

VS2008+开发驱动程序

IT圈 admin 25浏览 0评论

2023年12月5日发(作者:闾宁)

VS2008 开发驱动程序

XPJ(2010-2)

1. 前言

随着计算机科学技术的发展,驱动程序的开发悄然成为各个计算机应用领域(特别是编写与硬件相关程序)的程序员的关注的话题,对于那些迫切希望探究驱动程序开发奥秘的程序员来讲,面对铺天盖地,五花八门的各种图书资料,难免出现不知从何入手的问题,本文将带领你利用微软成熟的开发设计环境,自己动手开发出几类最简单的驱动程序,抛砖引玉,希望大家能够从中吸取到自己需要的知识,戳破驱动程序开发神秘的面纱,提升自身软件设计实力,为祖国的软件事业发展做出更大的贡献。

本人在学习驱动程序开发伊始,懵懵懂懂中也翻阅了不少前辈们的书籍,也在互联网上搜集了不少关于驱动开发方面的资料,出处无法一一列举,本文也将引用或者参考部分内容,在此感谢原著对本人的帮助,对前辈们献上我最崇高的敬意。

2. 开发环境搭建

2.1 软件平台搭建:

Microsoft Visual Studio 2008 , WDK7,VMware Workstation6.5.

安装VS2008及MSDN 。MSDN 可以帮助你更好使用VS2008,在出现问题找不到答案时,可以仔细阅读一下MSDN ,会提供一些必要的帮助。并且可以通过MSDN免费得到WDK7的下载连接。VS2008安装步骤略。

下载,安装WDK7,即(Windows Driver Kits 7.0.0)。提示选择安装选项时,建议全部选择安装,WDK便自动安装WinDbg(Windows调试工具),用于使用虚拟机对驱动程序代码进行调试。安装步骤略。

安装VMware Workstation.建议选择安装6.0以上版本。安装步骤略。安装成功以后新建Windows虚拟机,笔者选择的是WindowsXP系统(其他Windows系统大体相同),并安装系统映像,使之成为可以正常工作的WindowsXP虚拟系统。

2.2 调试平台搭建:

软件平台搭建成功以后,调试平台的搭建需要以下几个步骤。

第一步,修改WindowsXP虚拟机的系统配置。

1. 修改虚拟机配置。在硬件中选择添加串口。在连接属性中选择“使用命名管道”。保留默认命名管道名称.pipecom_1。在串口端属性中选择“The end is the

server.”“The other end is an application. ”,。勾选I/0模式中的”Yield CPU on Polled”复选框。

2. 启动虚拟机进入WindowsXP系统,打开“我的电脑”窗口,在“工具”菜单里面选择“文件夹选项”并点击,在文件夹选项弹出窗口选择“查看”选项卡。在“高级选项”中去除“隐藏受保护的操作系统文件”复选框勾选。并选择“显示所有文件和文件夹“。确定后系统关闭弹出窗口。

3. 打开系统的安装分区,笔者电脑默认安装的C盘。在根目录下可以找到“”配置文件。双击打开文件。修改[boot loader]。Timeouts = 30.修改[Operating

systems],复制其中关于WindowsXP 的一行字符(如果是纯净系统只有一行系统描述,有些系统可能带有DOS安装工具的选项,我们只需要复制关于安装Windows系统的描述),添加一新行并粘贴复制描述字符串。在系统描述字符串里面添加“-Debug”以示和前面项目的区别,行末添加“/debug /debugport=COM1

/baudrate=115200” 。保存关闭文件。关闭系统。 4. 从开始菜单中选择“Debugging Tools for Windows(X86)”中的windbg并打开。

在file 菜单下的Symbol Search Path项点击,弹出Symbol Search Path对话框。在Symbol Path编辑框里面输入srv*c:windowssymbols*/download/symbols;cache*c:windowssymbols。并新建C:Windowssymbols文件夹。在file 菜单下选择Kernal

Debug选项,弹出Kernal Debugging对话框,选择COM选项卡,输入波特率为115200,端口名.pipecom_1 。勾选Pipe复选框。确定后WinDbg即处于等待管道连接状态。

5. 重新启动WindowsXP虚拟机。在引导列表(即可看到我们在第3步中添加的系统描述)中,选择带有“-Debug”选项(前面设置哪项)并回车。正常情况下,在启动一段时间后WinDbg即显示连接成功。选择WinDbg中的Debug菜单下break选项,如果虚拟机响应,WinDbg调试菜单和工具栏即变为有效状态,可以进行单步等其他操作。说明调试平台搭建成功。首次进行连接可能需要较长时间。

3. KDM驱动开发示例

3.1 项目属性配置

1. 打开VS2008,新建一个Visual C++ à Win32 à win32空项目。例如DDKDemo。

2. 打开VS2008 的“生成”菜单中的“配置管理器”选项。在活动解决方案配置中选择《新建》,新建一个Check空的解决方案配置。

3. 在解决方案管理器中,新建一个DDKDemo.h头文件,一个源文件。

4. 打开VS2008的“项目”菜单里面“属性”选项。即打开Test项目属性页。在项目属性页选择“配置属性”,打开十字图标。

5. 选择“CC++”并展开内部选项。

在“常规”选项中,在“附加包含目录”中添加wdk 引用头文件目录。并去除“从父级或项目默认设置继承”复选框的勾选。Wdk头文件目录如下:

D:WinDDK7600.16385.0incapi

D:WinDDK7600.16385.0inccrt

D:WinDDK7600.16385.0incddk

注意笔者的WDK安装目录在D盘。

在“调试信息格式”中选择 “C7 兼容(/Z7)”选项。

在“警告等级”中选择“3级(/W3)”。

在“将警告视为错误”中选择“是(/WX)”。

在“优化”选项中,在“优化”中选择“禁用(/Od)”。

在“预处理器”选项中,在“预处理器定义”中添加

“WIN32=100;_X86_=1;WINVER=0x501;DBG=1”。并去除“从父级或项目默认属性继承”复选框的勾选。

在“高级”选项中,选择“调用约定”为“__stdcall (/Gz)”。

6. 选择“链接器”并展开内部选项。

在“常规”选项中,修改“输出文件”的文件扩展名为 .sys 添加“附加库目录”

D:WinDDK7600.16385.0libCrti386

D:WinDDK7600.16385.0libwxpi386

并去除“从父级或项目默认设置继承”复选框的勾选。

在“输入”选项中,添加“附加依赖项”并去除“从父级或项目默认设置继承”复选框的勾选。 在“清单文件”选项中,选择“生成清单”为否。

在“调试”选项中,选择“生成调试信息”为“是 (/Debug)”。

在“系统”选项中,选择“子系统”为“本机 (/SUBSYSTEM:NATIVE)”。选择“驱动程序”为“驱动程序(/DRIVER)”。

在“高级”中,添加“入口点”为DriverEntry。选择“随即基址”为“默认值”。选择“数据执行保护”为默认值。选择“目标计算机”为“MachineX86(/MACHINE:X86)”。

在“命令行”选项中,添加“/SECTION:INIT,D /IGNORE:4078”。

3.2 示例代码简介

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

** 文件名:DDKDemo.h

** 注释:这是一个KDM的测试程序--用于对设备驱动程序本质进行必要的了解

** 作者:XPJ

** 创建时间:2009-11-10

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

#pragma once

//KDM驱动程序头文件

extern "C"

{

#include

}

//定义几个函数段属性宏

#define PAGEDCODE code_seg("PAGED")

#define LOCKEDPAGE code_seg()

//定义设备扩展结构,用于保存设备属性

typedef struct _DEVICE_EXTENSION

{

PDEVICE_OBJECT pDeviceObject;

UNICODE_STRING ustrDeviceName;

UNICODE_STRING ustrSymbolicName;

}DEVICE_EXTENSION,*PDEVICE_EXTENSION;

//辅助创建设备函数声明

NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject);

//驱动卸载回调函数

VOID DDKUnload(IN PDRIVER_OBJECT pDriverObject);

//驱动投递函数

//设备对象指针

//设备名

#define INITCODE code_seg("INIT")

//分页内存段

//非分页内存段

//初始化内存段

//符合连接名 NTSTATUS DDKDispatchRoutine(IN PDEVICE_OBJECT pDeviceObject,

IN PIRP pIrp);

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

** 文件名:

** 注释:DDKDemo实现文件

** 作者:XPJ

** 创建时间:2009-11-10

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

#include "DDKDemo.h"

#pragma INITCODE

extern "C" NTSTATUS DriverEntry(

/*++

功能描述:驱动入口函数。

参数:

返回值:

--*/

{

NTSTATUS status;

DbgPrint(("Hello,My Windows!Enter DriverEntry!n"));

//添加一个调试断点,用于使用WinDbg进行源代码调试

DbgBreakPoint();

//注册其他驱动回调函数入口

pDriverObject->DriverUnload=DDKUnload;

pDriverObject->MajorFunction[IRP_MJ_CREATE]=DDKDispatchRoutine;

pDriverObject->MajorFunction[IRP_MJ_CLOSE]=DDKDispatchRoutine;

pDriverObject->MajorFunction[IRP_MJ_WRITE]=DDKDispatchRoutine;

pDriverObject->MajorFunction[IRP_MJ_READ]=DDKDispatchRoutine;

//创建设备

成功返回:STATUS_SUCCESS

pDriverObject:驱动对象指针。

pRegistryPath:驱动注册表项路径字符串。

IN PDRIVER_OBJECT pDriverObject,

IN PUNICODE_STRING ustrRegistryPath) status=CreateDevice(pDriverObject);

DbgPrint(("DriverEntry end!n"));

return status;

}

#pragma INITCODE

NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject)

/*++

功能描述:辅助创建设备对象函数。

参数:

返回值:成功

--*/

{

NTSTATUS status;

PDEVICE_OBJECT pDeviceObject;

PDEVICE_EXTENSION pDeviceExtension;

DbgPrint(("Enter CreateDevice!n"));

//创建设备名称

UNICODE_STRING DeviceName;

RtlInitUnicodeString(&DeviceName,L"DeviceDDKDevice");

//创建设备

status=IoCreateDevice(pDriverObject,

{

}

return status;

sizeof(DEVICE_EXTENSION),

&(UNICODE_STRING)DeviceName,

FILE_DEVICE_UNKNOWN,

0,TRUE,

&pDeviceObject);

返回STATUS_SUCCESS

失败 返回错误信息

pDriverObject:驱动对象指针。

if(!NT_SUCCESS(status)) //添加扩展属性

pDeviceObject->Flags |= DO_BUFFERED_IO;

//创建符合连接

UNICODE_STRING SymbolicLinkName;

RtlInitUnicodeString(&SymbolicLinkName,L"??MyDDKDevice");

pDeviceExtension=(PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;

pDeviceExtension->pDeviceObject=pDeviceObject;

pDeviceExtension->ustrDeviceName=DeviceName;

pDeviceExtension->ustrSymbolicName=SymbolicLinkName;

status=IoCreateSymbolicLink(&SymbolicLinkName,&DeviceName);

if(!NT_SUCCESS(status))

{

}

DbgPrint(("CreateDevice end!n"));

return STATUS_SUCCESS;

}

#pragma PAGEDCODE

VOID DDKUnload(IN PDRIVER_OBJECT pDriverObject)

/*++

功能描述:驱动卸载函数。

参数:

返回值:无

--*/

{

PDEVICE_OBJECT pNextObject;

DbgPrint(("Enter DDKUnloadn"));

pNextObject=pDriverObject->DeviceObject;

while(pNextObject !=NULL)

pDriverObject:驱动对象指针。

IoDeleteDevice(pDeviceObject);

DbgPrint(("CreateDevice Failed!n"));

return status; {

}

}

#pragma PAGEDCODE

NTSTATUS DDKDispatchRoutine(IN PDEVICE_OBJECT pDeviceObject,

/*++

功能描述:驱动投递函数。该驱动所有IRP请求公有投递函数。

参数:

返回值:返回STATUS_SUCCESS

--*/

{

DbgPrint(("Enter DDKDispatchRoutine!n"));

NTSTATUS status=STATUS_SUCCESS;

pIrp->=status;

pIrp->ation=0;

IoCompleteRequest(pIrp,IO_NO_INCREMENT);

DbgPrint(("DDKDispatchRountine end!n"));

return status;

}

pDriverObject:驱动对象指针。

pIrp:IRP请求。

IN PIRP pIrp)

//遍历所有挂载设备

PDEVICE_EXTENSION

UNICODE_STRING SymLink=pDevExtension->ustrSymbolicName;

IoDeleteSymbolicLink(&SymLink);

pNextObject=pNextObject->NextDevice;

IoDeleteDevice(pDevExtension->pDeviceObject);

pDevExtension=(PDEVICE_EXTENSION)pNextObject->DeviceExtension;

3.3 安装调试示例

打开DDKDemo所在目录,进入Check文件夹,复制文件到虚拟机中。

驱动的安装可以有二种选择,一种使用安装工具进行安装,一种自己编写安装程序。对于初学者,可以从网上下载DriverMonitor驱动调试安装工具来安装自己生成的驱动程序。

打开WinDbg,在file菜单中打开Source Search Path项,在弹出的对话框的Source Path中添加DDKDemo目标文件夹全路径,即上述的Check文件夹的全路径。在Debug菜单中选择Source Mode为选择状态,启动Kernal Debug 内核调试。

在WindowsXP虚拟机中安装加载驱动程序,驱动程序被加载以后,虚拟机即在我们设置的断点中断,同时WinDbg处于激活状态。在WinDbg中选择单步执行,单步两下,WinDbg即可弹出附带源码的驱动程序调试窗口。现在你已经进入里系统驱动加载的过程中了,可以随意查看程序执行过程中的参变量的变化。接下来就是你自己施展才华时候了。呵呵~~期待着大家第一个驱动程序开发成功啊。

4. WDM驱动开发示例

4.1 项目属性配置

1. 打开VS2008,新建一个Visual C++ à Win32 à win32空项目。例如WdmDemo。2. 打开VS2008 的“生成”菜单中的“配置管理器”选项。在活动解决方案配置中选择《新建》,新建一个Check空的解决方案配置。

3. 在解决方案管理器中,新建一个WdmDemo.h头文件,一个源文件。

4. 打开VS2008的“项目”菜单里面“属性”选项。即打开WdmDemo项目属性页。在项目属性页选择“配置属性”,打开十字图标。

5. 选择“CC++”并展开内部选项。

在“常规”选项中,在“附加包含目录”中添加wdk 引用头文件目录。并去除“从父级或项目默认设置继承”复选框的勾选。Wdk头文件目录如下:

D:WinDDK7600.16385.0incapi

D:WinDDK7600.16385.0inccrt

D:WinDDK7600.16385.0incddk

注意笔者的WDK安装目录在D盘。

在“调试信息格式”中选择 “C7 兼容(/Z7)”选项。

在“警告等级”中选择“3级(/W3)”。

在“将警告视为错误”中选择“是(/WX)”。

在“优化”选项中,在“优化”中选择“禁用(/Od)”。

在“预处理器”选项中,在“预处理器定义”中添加

“WIN32=100;_X86_=1;WINVER=0x501;DBG=1”。并去除“从父级或项目默认属性继承”复选框的勾选。

在“高级”选项中,选择“调用约定”为“__stdcall (/Gz)”。

6. 选择“链接器”并展开内部选项。

在“常规”选项中,修改“输出文件”的文件扩展名为 .sys 添加“附加库目录”

D:WinDDK7600.16385.0libCrti386

D:WinDDK7600.16385.0libwxpi386

并去除“从父级或项目默认设置继承”复选框的勾选。

在“输入”选项中,添加“附加依赖项”并去除“从父级或项目默认设置继承”复选框的勾选。

在“清单文件”选项中,选择“生成清单”为否。

在“调试”选项中,选择“生成调试信息”为“是 (/Debug)”。

在“系统”选项中,选择“子系统”为“本机 (/SUBSYSTEM:NATIVE)”。选择“驱动程序”为“WDM (/DRIVER:WDM)”。 在“高级”中,添加“入口点”为DriverEntry。选择“随即基址”为“默认值”。选择“数据执行保护”为默认值。选择“目标计算机”为“MachineX86(/MACHINE:X86)”。

在“命令行”选项中,添加“/SECTION:INIT,D /IGNORE:4078”。

4.2 示例代码简介

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

* 文件名称:HelloWDM.h

* 作 者:张帆

* 完成日期:2007-11-1

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

#ifdef __cplusplus

extern "C"

{

#endif

#include

#ifdef __cplusplus

}

#endif

typedef struct _DEVICE_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);

PDEVICE_OBJECT fdo;

PDEVICE_OBJECT NextStackDevice;

UNICODE_STRING ustrDeviceName; // 设备名

UNICODE_STRING ustrSymLinkName; // 符号链接名

} DEVICE_EXTENSION, *PDEVICE_EXTENSION; extern "C"

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,

IN PUNICODE_STRING RegistryPath);

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

* 文件名称:

* 作 者:张帆

* 完成日期:2007-11-1

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

#include "WdmDemo.h"

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

* 函数名称:DriverEntry

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

* 参数列表:

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

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

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

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

#pragma INITCODE

extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,

{

}

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

* 函数名称:HelloWDMAddDevice

* 功能描述:添加新设备

* 参数列表:

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

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

KdPrint(("Leave DriverEntryn"));

return STATUS_SUCCESS;

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(("Enter DriverEntryn"));

IN PUNICODE_STRING pRegistryPath) * 返回值:返回添加新设备状态

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

#pragma PAGEDCODE

NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,

IN PDEVICE_OBJECT PhysicalDeviceObject)

{

if( !NT_SUCCESS(status))

{

}

IoDeleteSymbolicLink(&pdx->ustrSymLinkName);

status = IoCreateSymbolicLink(&symLinkName,&devName);

if( !NT_SUCCESS(status))

{

}

return status;

pdx->ustrDeviceName = devName;

pdx->ustrSymLinkName = symLinkName;

status =

NTSTATUS status;

PDEVICE_OBJECT fdo;

UNICODE_STRING devName;

RtlInitUnicodeString(&devName,L"DeviceMyWDMDevice");

status = IoCreateDevice(

DriverObject,

sizeof(DEVICE_EXTENSION),

&(UNICODE_STRING)devName,

FILE_DEVICE_UNKNOWN,

0,

FALSE,

&fdo);

return status;

PAGED_CODE();

KdPrint(("Enter HelloWDMAddDevicen"));

if( !NT_SUCCESS(status))

PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;

pdx->fdo = fdo;

pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);

UNICODE_STRING symLinkName;

RtlInitUnicodeString(&symLinkName,L"DosDevicesHelloWDM");

IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)devName);

}

fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;

fdo->Flags &= ~DO_DEVICE_INITIALIZING;

KdPrint(("Leave HelloWDMAddDevicen"));

return STATUS_SUCCESS;

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

* 函数名称:DefaultPnpHandler

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

* 参数列表:

pdx:设备对象的扩展

Irp:从IO请求包

* 返回值:返回状态

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

#pragma PAGEDCODE

NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp)

{

}

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

* 函数名称:HandleRemoveDevice

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

* 参数列表:

fdo:功能设备对象

Irp:从IO请求包

* 返回值:返回状态

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

#pragma PAGEDCODE

NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp)

{

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

Irp-> = STATUS_SUCCESS;

NTSTATUS status = DefaultPnpHandler(pdx, Irp);

IoDeleteSymbolicLink(&(UNICODE_STRING)pdx->ustrSymLinkName);

PAGED_CODE();

KdPrint(("Enter HandleRemoveDevicen"));

PAGED_CODE();

KdPrint(("Enter DefaultPnpHandlern"));

IoSkipCurrentIrpStackLocation(Irp);

KdPrint(("Leave DefaultPnpHandlern"));

return IoCallDriver(pdx->NextStackDevice, Irp); if (pdx->NextStackDevice)

IoDetachDevice(pdx->NextStackDevice);

//删除fdo:

IoDeleteDevice(pdx->fdo);

}

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

* 函数名称:HelloWDMPnp

* 功能描述:对即插即用IRP进行处理

* 参数列表:

fdo:功能设备对象

Irp:从IO请求包

* 返回值:返回状态

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

#pragma PAGEDCODE

NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,

IN PIRP Irp)

{

KdPrint(("Enter HelloWDMPnpn"));

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,

DefaultPnpHandler,

HandleRemoveDevice,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

// 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

//

PAGED_CODE();

KdPrint(("Leave HandleRemoveDevicen"));

return status;

};

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

// 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

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 HelloWDMPnpn"));

return status;

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

* 函数名称:HelloWDMDispatchRoutine

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

* 参数列表:

fdo:功能设备对象

Irp:从IO请求包

* 返回值:返回状态

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

#pragma PAGEDCODE

NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo,

{

}

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

* 函数名称:HelloWDMUnload

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

* 参数列表:

DriverObject:驱动对象

* 返回值:返回状态

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

#pragma PAGEDCODE

void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject)

{

PAGED_CODE();

KdPrint(("Enter HelloWDMUnloadn"));

PAGED_CODE();

KdPrint(("Enter HelloWDMDispatchRoutinen"));

Irp-> = STATUS_SUCCESS;

Irp->ation = 0; // no bytes xfered

IoCompleteRequest( Irp, IO_NO_INCREMENT );

KdPrint(("Leave HelloWDMDispatchRoutinen"));

return STATUS_SUCCESS;

IN PIRP Irp) KdPrint(("Leave HelloWDMUnloadn"));

}4.3 安装调试示例

WDM驱动程序安装需要一个.inf安装文件来支持其安装,其实它只是一个文本文件。如果我们需要创建一个这样的文件,只需要新建一个文本文件,然后更改扩展名为.inf即可。WDK开发驱动程序包中有个CheckInf的控制台的调试工具可以帮助我们检查inf文件的语法错误。inf示例如下:

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

[Version]

Signature="$CHICAGO$";

Provider=Zhangfan_Device

DriverVer=11/1/2007,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=ZhangfanDevice

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 = "WdmDemo",Disk1,,

[SourceDisksFiles]

= 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,System32Drivers

;--------- Manufacturer and Models Sections ----------------------------------

[Manufacturer]

%MfgName%=Mfg0

[Mfg0]

; PCI hardware Ids use the form

; PCIVEN_aaaa&DEV_bbbb&SUBSYS_cccccccc&REV_dd

;改成你自己的ID

%DeviceDesc%=YouMark_DDI, PCIVEN_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,,

HKR, "Parameters", "BreakOnEntry", 0x00010001, 0

; --------- Windows NT -----------------

[YouMark_]

CopyFiles=YouMark_Files_Driver

AddReg=YouMark_NT_AddReg

[YouMark_es]

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%

[YouMark_NT_AddReg]

HKLM, "SystemCurrentControlSetServicesHelloWDMParameters",

"BreakOnEntry", 0x00010001, 0

; --------- Files (common) -------------

[YouMark_Files_Driver]

;--------- Strings Section ---------------------------------------------------

[Strings]

ProviderName="Zhangfan."

MfgName="Zhangfan Soft"

DeviceDesc="Hello World WDM!"

DeviceClassName="Zhangfan_Device"

SvcDesc="Zhangfan"

第一次亦可直接复制进文本文件中进行创建。

WDM驱动的辅助安装程序为,可以从DriverStudio中提取,亦可从网上搜集。然后被EvDriverInstaller复制到虚拟机中,从“file”菜单中选择“Open”查找到.inf所在目录选择打开(注:驱动文件需和.inf文件放在同一目录下),然后在程序界面的右下方有三个按钮“Add New Device”,“Remove Device”,“Restart Device”,点击“Add New Device”程序自动根据.inf设置安装驱动程序。安装完毕后,可以在EvDriverInstaller程序中间的列表框中发现添加了一个项目一个问号图标及“Hello World WDM!”,同时打开我的电脑的“计算机管理”-》“设备管理器”,即可发现有个新的设备已经出现。名字为“Zhangfan_Device”。

2023年12月5日发(作者:闾宁)

VS2008 开发驱动程序

XPJ(2010-2)

1. 前言

随着计算机科学技术的发展,驱动程序的开发悄然成为各个计算机应用领域(特别是编写与硬件相关程序)的程序员的关注的话题,对于那些迫切希望探究驱动程序开发奥秘的程序员来讲,面对铺天盖地,五花八门的各种图书资料,难免出现不知从何入手的问题,本文将带领你利用微软成熟的开发设计环境,自己动手开发出几类最简单的驱动程序,抛砖引玉,希望大家能够从中吸取到自己需要的知识,戳破驱动程序开发神秘的面纱,提升自身软件设计实力,为祖国的软件事业发展做出更大的贡献。

本人在学习驱动程序开发伊始,懵懵懂懂中也翻阅了不少前辈们的书籍,也在互联网上搜集了不少关于驱动开发方面的资料,出处无法一一列举,本文也将引用或者参考部分内容,在此感谢原著对本人的帮助,对前辈们献上我最崇高的敬意。

2. 开发环境搭建

2.1 软件平台搭建:

Microsoft Visual Studio 2008 , WDK7,VMware Workstation6.5.

安装VS2008及MSDN 。MSDN 可以帮助你更好使用VS2008,在出现问题找不到答案时,可以仔细阅读一下MSDN ,会提供一些必要的帮助。并且可以通过MSDN免费得到WDK7的下载连接。VS2008安装步骤略。

下载,安装WDK7,即(Windows Driver Kits 7.0.0)。提示选择安装选项时,建议全部选择安装,WDK便自动安装WinDbg(Windows调试工具),用于使用虚拟机对驱动程序代码进行调试。安装步骤略。

安装VMware Workstation.建议选择安装6.0以上版本。安装步骤略。安装成功以后新建Windows虚拟机,笔者选择的是WindowsXP系统(其他Windows系统大体相同),并安装系统映像,使之成为可以正常工作的WindowsXP虚拟系统。

2.2 调试平台搭建:

软件平台搭建成功以后,调试平台的搭建需要以下几个步骤。

第一步,修改WindowsXP虚拟机的系统配置。

1. 修改虚拟机配置。在硬件中选择添加串口。在连接属性中选择“使用命名管道”。保留默认命名管道名称.pipecom_1。在串口端属性中选择“The end is the

server.”“The other end is an application. ”,。勾选I/0模式中的”Yield CPU on Polled”复选框。

2. 启动虚拟机进入WindowsXP系统,打开“我的电脑”窗口,在“工具”菜单里面选择“文件夹选项”并点击,在文件夹选项弹出窗口选择“查看”选项卡。在“高级选项”中去除“隐藏受保护的操作系统文件”复选框勾选。并选择“显示所有文件和文件夹“。确定后系统关闭弹出窗口。

3. 打开系统的安装分区,笔者电脑默认安装的C盘。在根目录下可以找到“”配置文件。双击打开文件。修改[boot loader]。Timeouts = 30.修改[Operating

systems],复制其中关于WindowsXP 的一行字符(如果是纯净系统只有一行系统描述,有些系统可能带有DOS安装工具的选项,我们只需要复制关于安装Windows系统的描述),添加一新行并粘贴复制描述字符串。在系统描述字符串里面添加“-Debug”以示和前面项目的区别,行末添加“/debug /debugport=COM1

/baudrate=115200” 。保存关闭文件。关闭系统。 4. 从开始菜单中选择“Debugging Tools for Windows(X86)”中的windbg并打开。

在file 菜单下的Symbol Search Path项点击,弹出Symbol Search Path对话框。在Symbol Path编辑框里面输入srv*c:windowssymbols*/download/symbols;cache*c:windowssymbols。并新建C:Windowssymbols文件夹。在file 菜单下选择Kernal

Debug选项,弹出Kernal Debugging对话框,选择COM选项卡,输入波特率为115200,端口名.pipecom_1 。勾选Pipe复选框。确定后WinDbg即处于等待管道连接状态。

5. 重新启动WindowsXP虚拟机。在引导列表(即可看到我们在第3步中添加的系统描述)中,选择带有“-Debug”选项(前面设置哪项)并回车。正常情况下,在启动一段时间后WinDbg即显示连接成功。选择WinDbg中的Debug菜单下break选项,如果虚拟机响应,WinDbg调试菜单和工具栏即变为有效状态,可以进行单步等其他操作。说明调试平台搭建成功。首次进行连接可能需要较长时间。

3. KDM驱动开发示例

3.1 项目属性配置

1. 打开VS2008,新建一个Visual C++ à Win32 à win32空项目。例如DDKDemo。

2. 打开VS2008 的“生成”菜单中的“配置管理器”选项。在活动解决方案配置中选择《新建》,新建一个Check空的解决方案配置。

3. 在解决方案管理器中,新建一个DDKDemo.h头文件,一个源文件。

4. 打开VS2008的“项目”菜单里面“属性”选项。即打开Test项目属性页。在项目属性页选择“配置属性”,打开十字图标。

5. 选择“CC++”并展开内部选项。

在“常规”选项中,在“附加包含目录”中添加wdk 引用头文件目录。并去除“从父级或项目默认设置继承”复选框的勾选。Wdk头文件目录如下:

D:WinDDK7600.16385.0incapi

D:WinDDK7600.16385.0inccrt

D:WinDDK7600.16385.0incddk

注意笔者的WDK安装目录在D盘。

在“调试信息格式”中选择 “C7 兼容(/Z7)”选项。

在“警告等级”中选择“3级(/W3)”。

在“将警告视为错误”中选择“是(/WX)”。

在“优化”选项中,在“优化”中选择“禁用(/Od)”。

在“预处理器”选项中,在“预处理器定义”中添加

“WIN32=100;_X86_=1;WINVER=0x501;DBG=1”。并去除“从父级或项目默认属性继承”复选框的勾选。

在“高级”选项中,选择“调用约定”为“__stdcall (/Gz)”。

6. 选择“链接器”并展开内部选项。

在“常规”选项中,修改“输出文件”的文件扩展名为 .sys 添加“附加库目录”

D:WinDDK7600.16385.0libCrti386

D:WinDDK7600.16385.0libwxpi386

并去除“从父级或项目默认设置继承”复选框的勾选。

在“输入”选项中,添加“附加依赖项”并去除“从父级或项目默认设置继承”复选框的勾选。 在“清单文件”选项中,选择“生成清单”为否。

在“调试”选项中,选择“生成调试信息”为“是 (/Debug)”。

在“系统”选项中,选择“子系统”为“本机 (/SUBSYSTEM:NATIVE)”。选择“驱动程序”为“驱动程序(/DRIVER)”。

在“高级”中,添加“入口点”为DriverEntry。选择“随即基址”为“默认值”。选择“数据执行保护”为默认值。选择“目标计算机”为“MachineX86(/MACHINE:X86)”。

在“命令行”选项中,添加“/SECTION:INIT,D /IGNORE:4078”。

3.2 示例代码简介

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

** 文件名:DDKDemo.h

** 注释:这是一个KDM的测试程序--用于对设备驱动程序本质进行必要的了解

** 作者:XPJ

** 创建时间:2009-11-10

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

#pragma once

//KDM驱动程序头文件

extern "C"

{

#include

}

//定义几个函数段属性宏

#define PAGEDCODE code_seg("PAGED")

#define LOCKEDPAGE code_seg()

//定义设备扩展结构,用于保存设备属性

typedef struct _DEVICE_EXTENSION

{

PDEVICE_OBJECT pDeviceObject;

UNICODE_STRING ustrDeviceName;

UNICODE_STRING ustrSymbolicName;

}DEVICE_EXTENSION,*PDEVICE_EXTENSION;

//辅助创建设备函数声明

NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject);

//驱动卸载回调函数

VOID DDKUnload(IN PDRIVER_OBJECT pDriverObject);

//驱动投递函数

//设备对象指针

//设备名

#define INITCODE code_seg("INIT")

//分页内存段

//非分页内存段

//初始化内存段

//符合连接名 NTSTATUS DDKDispatchRoutine(IN PDEVICE_OBJECT pDeviceObject,

IN PIRP pIrp);

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

** 文件名:

** 注释:DDKDemo实现文件

** 作者:XPJ

** 创建时间:2009-11-10

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

#include "DDKDemo.h"

#pragma INITCODE

extern "C" NTSTATUS DriverEntry(

/*++

功能描述:驱动入口函数。

参数:

返回值:

--*/

{

NTSTATUS status;

DbgPrint(("Hello,My Windows!Enter DriverEntry!n"));

//添加一个调试断点,用于使用WinDbg进行源代码调试

DbgBreakPoint();

//注册其他驱动回调函数入口

pDriverObject->DriverUnload=DDKUnload;

pDriverObject->MajorFunction[IRP_MJ_CREATE]=DDKDispatchRoutine;

pDriverObject->MajorFunction[IRP_MJ_CLOSE]=DDKDispatchRoutine;

pDriverObject->MajorFunction[IRP_MJ_WRITE]=DDKDispatchRoutine;

pDriverObject->MajorFunction[IRP_MJ_READ]=DDKDispatchRoutine;

//创建设备

成功返回:STATUS_SUCCESS

pDriverObject:驱动对象指针。

pRegistryPath:驱动注册表项路径字符串。

IN PDRIVER_OBJECT pDriverObject,

IN PUNICODE_STRING ustrRegistryPath) status=CreateDevice(pDriverObject);

DbgPrint(("DriverEntry end!n"));

return status;

}

#pragma INITCODE

NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject)

/*++

功能描述:辅助创建设备对象函数。

参数:

返回值:成功

--*/

{

NTSTATUS status;

PDEVICE_OBJECT pDeviceObject;

PDEVICE_EXTENSION pDeviceExtension;

DbgPrint(("Enter CreateDevice!n"));

//创建设备名称

UNICODE_STRING DeviceName;

RtlInitUnicodeString(&DeviceName,L"DeviceDDKDevice");

//创建设备

status=IoCreateDevice(pDriverObject,

{

}

return status;

sizeof(DEVICE_EXTENSION),

&(UNICODE_STRING)DeviceName,

FILE_DEVICE_UNKNOWN,

0,TRUE,

&pDeviceObject);

返回STATUS_SUCCESS

失败 返回错误信息

pDriverObject:驱动对象指针。

if(!NT_SUCCESS(status)) //添加扩展属性

pDeviceObject->Flags |= DO_BUFFERED_IO;

//创建符合连接

UNICODE_STRING SymbolicLinkName;

RtlInitUnicodeString(&SymbolicLinkName,L"??MyDDKDevice");

pDeviceExtension=(PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;

pDeviceExtension->pDeviceObject=pDeviceObject;

pDeviceExtension->ustrDeviceName=DeviceName;

pDeviceExtension->ustrSymbolicName=SymbolicLinkName;

status=IoCreateSymbolicLink(&SymbolicLinkName,&DeviceName);

if(!NT_SUCCESS(status))

{

}

DbgPrint(("CreateDevice end!n"));

return STATUS_SUCCESS;

}

#pragma PAGEDCODE

VOID DDKUnload(IN PDRIVER_OBJECT pDriverObject)

/*++

功能描述:驱动卸载函数。

参数:

返回值:无

--*/

{

PDEVICE_OBJECT pNextObject;

DbgPrint(("Enter DDKUnloadn"));

pNextObject=pDriverObject->DeviceObject;

while(pNextObject !=NULL)

pDriverObject:驱动对象指针。

IoDeleteDevice(pDeviceObject);

DbgPrint(("CreateDevice Failed!n"));

return status; {

}

}

#pragma PAGEDCODE

NTSTATUS DDKDispatchRoutine(IN PDEVICE_OBJECT pDeviceObject,

/*++

功能描述:驱动投递函数。该驱动所有IRP请求公有投递函数。

参数:

返回值:返回STATUS_SUCCESS

--*/

{

DbgPrint(("Enter DDKDispatchRoutine!n"));

NTSTATUS status=STATUS_SUCCESS;

pIrp->=status;

pIrp->ation=0;

IoCompleteRequest(pIrp,IO_NO_INCREMENT);

DbgPrint(("DDKDispatchRountine end!n"));

return status;

}

pDriverObject:驱动对象指针。

pIrp:IRP请求。

IN PIRP pIrp)

//遍历所有挂载设备

PDEVICE_EXTENSION

UNICODE_STRING SymLink=pDevExtension->ustrSymbolicName;

IoDeleteSymbolicLink(&SymLink);

pNextObject=pNextObject->NextDevice;

IoDeleteDevice(pDevExtension->pDeviceObject);

pDevExtension=(PDEVICE_EXTENSION)pNextObject->DeviceExtension;

3.3 安装调试示例

打开DDKDemo所在目录,进入Check文件夹,复制文件到虚拟机中。

驱动的安装可以有二种选择,一种使用安装工具进行安装,一种自己编写安装程序。对于初学者,可以从网上下载DriverMonitor驱动调试安装工具来安装自己生成的驱动程序。

打开WinDbg,在file菜单中打开Source Search Path项,在弹出的对话框的Source Path中添加DDKDemo目标文件夹全路径,即上述的Check文件夹的全路径。在Debug菜单中选择Source Mode为选择状态,启动Kernal Debug 内核调试。

在WindowsXP虚拟机中安装加载驱动程序,驱动程序被加载以后,虚拟机即在我们设置的断点中断,同时WinDbg处于激活状态。在WinDbg中选择单步执行,单步两下,WinDbg即可弹出附带源码的驱动程序调试窗口。现在你已经进入里系统驱动加载的过程中了,可以随意查看程序执行过程中的参变量的变化。接下来就是你自己施展才华时候了。呵呵~~期待着大家第一个驱动程序开发成功啊。

4. WDM驱动开发示例

4.1 项目属性配置

1. 打开VS2008,新建一个Visual C++ à Win32 à win32空项目。例如WdmDemo。2. 打开VS2008 的“生成”菜单中的“配置管理器”选项。在活动解决方案配置中选择《新建》,新建一个Check空的解决方案配置。

3. 在解决方案管理器中,新建一个WdmDemo.h头文件,一个源文件。

4. 打开VS2008的“项目”菜单里面“属性”选项。即打开WdmDemo项目属性页。在项目属性页选择“配置属性”,打开十字图标。

5. 选择“CC++”并展开内部选项。

在“常规”选项中,在“附加包含目录”中添加wdk 引用头文件目录。并去除“从父级或项目默认设置继承”复选框的勾选。Wdk头文件目录如下:

D:WinDDK7600.16385.0incapi

D:WinDDK7600.16385.0inccrt

D:WinDDK7600.16385.0incddk

注意笔者的WDK安装目录在D盘。

在“调试信息格式”中选择 “C7 兼容(/Z7)”选项。

在“警告等级”中选择“3级(/W3)”。

在“将警告视为错误”中选择“是(/WX)”。

在“优化”选项中,在“优化”中选择“禁用(/Od)”。

在“预处理器”选项中,在“预处理器定义”中添加

“WIN32=100;_X86_=1;WINVER=0x501;DBG=1”。并去除“从父级或项目默认属性继承”复选框的勾选。

在“高级”选项中,选择“调用约定”为“__stdcall (/Gz)”。

6. 选择“链接器”并展开内部选项。

在“常规”选项中,修改“输出文件”的文件扩展名为 .sys 添加“附加库目录”

D:WinDDK7600.16385.0libCrti386

D:WinDDK7600.16385.0libwxpi386

并去除“从父级或项目默认设置继承”复选框的勾选。

在“输入”选项中,添加“附加依赖项”并去除“从父级或项目默认设置继承”复选框的勾选。

在“清单文件”选项中,选择“生成清单”为否。

在“调试”选项中,选择“生成调试信息”为“是 (/Debug)”。

在“系统”选项中,选择“子系统”为“本机 (/SUBSYSTEM:NATIVE)”。选择“驱动程序”为“WDM (/DRIVER:WDM)”。 在“高级”中,添加“入口点”为DriverEntry。选择“随即基址”为“默认值”。选择“数据执行保护”为默认值。选择“目标计算机”为“MachineX86(/MACHINE:X86)”。

在“命令行”选项中,添加“/SECTION:INIT,D /IGNORE:4078”。

4.2 示例代码简介

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

* 文件名称:HelloWDM.h

* 作 者:张帆

* 完成日期:2007-11-1

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

#ifdef __cplusplus

extern "C"

{

#endif

#include

#ifdef __cplusplus

}

#endif

typedef struct _DEVICE_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);

PDEVICE_OBJECT fdo;

PDEVICE_OBJECT NextStackDevice;

UNICODE_STRING ustrDeviceName; // 设备名

UNICODE_STRING ustrSymLinkName; // 符号链接名

} DEVICE_EXTENSION, *PDEVICE_EXTENSION; extern "C"

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,

IN PUNICODE_STRING RegistryPath);

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

* 文件名称:

* 作 者:张帆

* 完成日期:2007-11-1

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

#include "WdmDemo.h"

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

* 函数名称:DriverEntry

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

* 参数列表:

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

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

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

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

#pragma INITCODE

extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,

{

}

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

* 函数名称:HelloWDMAddDevice

* 功能描述:添加新设备

* 参数列表:

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

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

KdPrint(("Leave DriverEntryn"));

return STATUS_SUCCESS;

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(("Enter DriverEntryn"));

IN PUNICODE_STRING pRegistryPath) * 返回值:返回添加新设备状态

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

#pragma PAGEDCODE

NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,

IN PDEVICE_OBJECT PhysicalDeviceObject)

{

if( !NT_SUCCESS(status))

{

}

IoDeleteSymbolicLink(&pdx->ustrSymLinkName);

status = IoCreateSymbolicLink(&symLinkName,&devName);

if( !NT_SUCCESS(status))

{

}

return status;

pdx->ustrDeviceName = devName;

pdx->ustrSymLinkName = symLinkName;

status =

NTSTATUS status;

PDEVICE_OBJECT fdo;

UNICODE_STRING devName;

RtlInitUnicodeString(&devName,L"DeviceMyWDMDevice");

status = IoCreateDevice(

DriverObject,

sizeof(DEVICE_EXTENSION),

&(UNICODE_STRING)devName,

FILE_DEVICE_UNKNOWN,

0,

FALSE,

&fdo);

return status;

PAGED_CODE();

KdPrint(("Enter HelloWDMAddDevicen"));

if( !NT_SUCCESS(status))

PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;

pdx->fdo = fdo;

pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);

UNICODE_STRING symLinkName;

RtlInitUnicodeString(&symLinkName,L"DosDevicesHelloWDM");

IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)devName);

}

fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;

fdo->Flags &= ~DO_DEVICE_INITIALIZING;

KdPrint(("Leave HelloWDMAddDevicen"));

return STATUS_SUCCESS;

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

* 函数名称:DefaultPnpHandler

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

* 参数列表:

pdx:设备对象的扩展

Irp:从IO请求包

* 返回值:返回状态

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

#pragma PAGEDCODE

NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp)

{

}

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

* 函数名称:HandleRemoveDevice

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

* 参数列表:

fdo:功能设备对象

Irp:从IO请求包

* 返回值:返回状态

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

#pragma PAGEDCODE

NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp)

{

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

Irp-> = STATUS_SUCCESS;

NTSTATUS status = DefaultPnpHandler(pdx, Irp);

IoDeleteSymbolicLink(&(UNICODE_STRING)pdx->ustrSymLinkName);

PAGED_CODE();

KdPrint(("Enter HandleRemoveDevicen"));

PAGED_CODE();

KdPrint(("Enter DefaultPnpHandlern"));

IoSkipCurrentIrpStackLocation(Irp);

KdPrint(("Leave DefaultPnpHandlern"));

return IoCallDriver(pdx->NextStackDevice, Irp); if (pdx->NextStackDevice)

IoDetachDevice(pdx->NextStackDevice);

//删除fdo:

IoDeleteDevice(pdx->fdo);

}

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

* 函数名称:HelloWDMPnp

* 功能描述:对即插即用IRP进行处理

* 参数列表:

fdo:功能设备对象

Irp:从IO请求包

* 返回值:返回状态

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

#pragma PAGEDCODE

NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,

IN PIRP Irp)

{

KdPrint(("Enter HelloWDMPnpn"));

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,

DefaultPnpHandler,

HandleRemoveDevice,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

// 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

//

PAGED_CODE();

KdPrint(("Leave HandleRemoveDevicen"));

return status;

};

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

DefaultPnpHandler,

// 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

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 HelloWDMPnpn"));

return status;

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

* 函数名称:HelloWDMDispatchRoutine

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

* 参数列表:

fdo:功能设备对象

Irp:从IO请求包

* 返回值:返回状态

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

#pragma PAGEDCODE

NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo,

{

}

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

* 函数名称:HelloWDMUnload

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

* 参数列表:

DriverObject:驱动对象

* 返回值:返回状态

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

#pragma PAGEDCODE

void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject)

{

PAGED_CODE();

KdPrint(("Enter HelloWDMUnloadn"));

PAGED_CODE();

KdPrint(("Enter HelloWDMDispatchRoutinen"));

Irp-> = STATUS_SUCCESS;

Irp->ation = 0; // no bytes xfered

IoCompleteRequest( Irp, IO_NO_INCREMENT );

KdPrint(("Leave HelloWDMDispatchRoutinen"));

return STATUS_SUCCESS;

IN PIRP Irp) KdPrint(("Leave HelloWDMUnloadn"));

}4.3 安装调试示例

WDM驱动程序安装需要一个.inf安装文件来支持其安装,其实它只是一个文本文件。如果我们需要创建一个这样的文件,只需要新建一个文本文件,然后更改扩展名为.inf即可。WDK开发驱动程序包中有个CheckInf的控制台的调试工具可以帮助我们检查inf文件的语法错误。inf示例如下:

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

[Version]

Signature="$CHICAGO$";

Provider=Zhangfan_Device

DriverVer=11/1/2007,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=ZhangfanDevice

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 = "WdmDemo",Disk1,,

[SourceDisksFiles]

= 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,System32Drivers

;--------- Manufacturer and Models Sections ----------------------------------

[Manufacturer]

%MfgName%=Mfg0

[Mfg0]

; PCI hardware Ids use the form

; PCIVEN_aaaa&DEV_bbbb&SUBSYS_cccccccc&REV_dd

;改成你自己的ID

%DeviceDesc%=YouMark_DDI, PCIVEN_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,,

HKR, "Parameters", "BreakOnEntry", 0x00010001, 0

; --------- Windows NT -----------------

[YouMark_]

CopyFiles=YouMark_Files_Driver

AddReg=YouMark_NT_AddReg

[YouMark_es]

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%

[YouMark_NT_AddReg]

HKLM, "SystemCurrentControlSetServicesHelloWDMParameters",

"BreakOnEntry", 0x00010001, 0

; --------- Files (common) -------------

[YouMark_Files_Driver]

;--------- Strings Section ---------------------------------------------------

[Strings]

ProviderName="Zhangfan."

MfgName="Zhangfan Soft"

DeviceDesc="Hello World WDM!"

DeviceClassName="Zhangfan_Device"

SvcDesc="Zhangfan"

第一次亦可直接复制进文本文件中进行创建。

WDM驱动的辅助安装程序为,可以从DriverStudio中提取,亦可从网上搜集。然后被EvDriverInstaller复制到虚拟机中,从“file”菜单中选择“Open”查找到.inf所在目录选择打开(注:驱动文件需和.inf文件放在同一目录下),然后在程序界面的右下方有三个按钮“Add New Device”,“Remove Device”,“Restart Device”,点击“Add New Device”程序自动根据.inf设置安装驱动程序。安装完毕后,可以在EvDriverInstaller程序中间的列表框中发现添加了一个项目一个问号图标及“Hello World WDM!”,同时打开我的电脑的“计算机管理”-》“设备管理器”,即可发现有个新的设备已经出现。名字为“Zhangfan_Device”。

发布评论

评论列表 (0)

  1. 暂无评论