VS2008 开发驱动程序(续)

4.       WDM驱动开发示例

4.1   项目属性配置

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

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

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

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

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

                           D:/WinDDK/7600.16385.0/inc/api

                           D:/WinDDK/7600.16385.0/inc/crt

                           D:/WinDDK/7600.16385.0/inc/ddk

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

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

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

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

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

在“预处理器”选项中,在“预处理器定义”中添加             WIN32=100;_X86_=1;WINVER=0x501;DBG=1”。并去除“从父级或项目默认属性继承”复选框的勾选。

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

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

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

                           D:/WinDDK/7600.16385.0/lib/Crt/i386

                           D:/WinDDK/7600.16385.0/lib/wxp/i386

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

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

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

在“调试”选项中,选择“生成调试信息”为“是 /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 <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                                                

*    :张帆

* 完成日期:2007-11-1

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

#include "WdmDemo.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"));

}

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]

WdmDemo.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,,WdmDemo.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/WdmDemo.sys

 

[YouMark_NT_AddReg]

HKLM, "System/CurrentControlSet/Services/HelloWDM/Parameters",/

"BreakOnEntry", 0x00010001, 0

 

 

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

 

[YouMark_Files_Driver]

WdmDemo.sys

 

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

 

[Strings]

ProviderName="Zhangfan."

MfgName="Zhangfan Soft"

DeviceDesc="Hello World WDM!"

DeviceClassName="Zhangfan_Device"

SvcDesc="Zhangfan"

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

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

本文原创,转载请注明出处。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值