一个简单的driverstudio+DDK的虚拟设备驱动程序

知道很多朋友都想学windows驱动,我也是个新手,看了WDM设备驱动开发,结合了DDK,终于写了个简单的虚拟设备驱动,其实可以单独用DriverStudio或DDK的,我之所以这样用主要是利用DriverStudio的调试方便,以及DDK的强大,不知道这样说是否正确哈,下面都是c程序,在此贴出我的源码以便大家相互学习相互进步哈,如有问题不吝请教哈

<ioctl.h>

#ifndef __Ioctl__h_
#define __Ioctl__h_

#define IOCTL_ZERO_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define IOCTL_REMOVE_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define IOCTL_GET_BUFFER_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN,0x802,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define IOCTL_GET_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN,0x803,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define IOCTL_UNRECOGNISED CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED,FILE_ANY_ACCESS)

#endif

<GUIDs.h>

#define WDMDevice_CLASS_GUID \
{ 0xba8cd386, 0x5478, 0x4772, { 0x90, 0xc0, 0xb6, 0xd0, 0x7, 0xac, 0xef, 0xbc } }


<OpWDM.h>

// OpWDM.h
//
// Generated by DriverWizard version DriverStudio 3.1.0 (Build 1722)
//

#ifdef __cplusplus
extern "C"
{
#endif

#include "wdm.h"
#ifdef __cplusplus
}
#endif

#include "GUIDs.h"
#include "reg.h"

#define EOL "\n"

// Spin lock to protect access to shared memory buffer
extern KSPIN_LOCK BufferLock; //定义自旋锁

extern PUCHAR Buffer;

// Function Prototypes

//NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT pdo);与下等同
NTSTATUS __stdcall AddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT pdo);

VOID __stdcall Unload(IN PDRIVER_OBJECT DriverObject);

NTSTATUS __stdcall Create(IN PDEVICE_OBJECT fdo,IN PIRP Irp);

NTSTATUS __stdcall Close(IN PDEVICE_OBJECT fdo,IN PIRP Irp);

NTSTATUS __stdcall Write(IN PDEVICE_OBJECT fdo,IN PIRP Irp);

NTSTATUS __stdcall Read(IN PDEVICE_OBJECT fdo,IN PIRP Irp);

NTSTATUS __stdcall Power(IN PDEVICE_OBJECT fdo,IN PIRP Irp);

NTSTATUS __stdcall Pnp(IN PDEVICE_OBJECT fdo,IN PIRP IRP);

NTSTATUS __stdcall DeviceControl(IN PDEVICE_OBJECT fdo,IN PIRP Irp);

NTSTATUS __stdcall SystemControl(IN PDEVICE_OBJECT fdo,IN PIRP Irp);

NTSTATUS __stdcall CompleteIrp(PIRP Irp,NTSTATUS status,ULONG info);


<reg.h>

typedef struct _USB_DEVICE_EXTENSION
{
PDEVICE_OBJECT fdo;
PDEVICE_OBJECT NextStackDevice;
UNICODE_STRING ifSymLinkName;
}USB_DEVICE_EXTENSION,*PUSB_DEVICE_EXTENSION;


<OpWDM.cpp>

#include "OpWDM.h"

GUID WDM_GUID = WDMDevice_CLASS_GUID;

//POOLTAG DefaultPoolTag('lrtC');
/
// Begin INIT section
#pragma code_seg("INIT")

/
/*内核模式函数和驱动程序中的函数在为x86平台编译时都使用__stdcall调用约定。这虽然对编程没有任何影响,但它有利于你调试程序。我有时使用extern "C"编译指令,这是因为有时候需要在C代码中使用了C++语法,C++语法允许在程序的任何地方声明变量而不仅仅是在左大括号后面。这个预编译指令将禁止编译器生成C++形式的外部函数名修饰,这样连接器就能找到该函数。使用这个指令编译后,驱动程序入口函数的外部名将为_DriverEntry@8
*/
extern "C"
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
DbgPrint("###Simple C++ Driver - DriverEntry\nCompiled at " __TIME__ " on " __DATE__ "\n");

NTSTATUS Status = STATUS_SUCCESS;

#if DBG
DbgPrint("checked\n");
#else
DbgPrint("free\n");
#endif

DbgPrint("DriverEntry RegistryPath:%S\n",RegistryPath->Buffer);

DriverObject->MajorFunction[IRP_MJ_CREATE] = Create;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = Close;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl;
DriverObject->MajorFunction[IRP_MJ_PNP] = Pnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = Power;
DriverObject->MajorFunction[IRP_MJ_READ] = Read;
DriverObject->MajorFunction[IRP_MJ_WRITE] = Write;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = SystemControl;
DriverObject->DriverExtension->AddDevice = AddDevice;


// Handle Unload to cleanup the C++ runtime
DriverObject->DriverUnload = Unload;

KeInitializeSpinLock(&BufferLock); //初始化自旋锁
//This routine must be called before an initial call to KeAcquireSpinLock, KeAcquireInStackQueuedSpinLock, or to any other support routine that requires a spin lock as an argument.
return Status;
}

// End INIT section
/
#pragma code_seg()

#pragma code_seg("PAGE")

VOID Unload(IN PDRIVER_OBJECT DriverObject)
{

//Free buffer (do not need to acquire spin lock)
if( Buffer!=NULL)
ExFreePool(Buffer);
// TODO: Free all allocated resources. Undo operations performed
// in DriverEntry.
}

NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT pdo)
{
DbgPrint("###AddDevice START\n");
NTSTATUS status;
PDEVICE_OBJECT pfdo = NULL;

//Create our Functional Device Object in fdo
status = IoCreateDevice(
DriverObject, //驱动程序对象
sizeof(USB_DEVICE_EXTENSION), //要求的设备扩展的大小
NULL, //设备名称
FILE_DEVICE_UNKNOWN, //设备类型
0, //各种常量用or结合在一起,指示可删除介质、只读等
FALSE, //如果一次只有一个线程可以访问该设备,为TRUE
&pfdo //返回的设备对象
);

if ( !NT_SUCCESS(status) )
return status;

//Remeber fdo in our device extension
PUSB_DEVICE_EXTENSION dx = (PUSB_DEVICE_EXTENSION)pfdo->DeviceExtension; //设置设备扩展
dx->fdo=pfdo;

//Register and enable our device interface
//设备接口注册
// status = IoRegisterDeviceInterface(pdo,&EhciDevice_CLASS_GUID,NULL,&dx->ifSymLinkName);
status = IoRegisterDeviceInterface(pdo, //设备PDO
&Ehci_GUID, //被注册的GUID
NULL, //引用字符串成为接口名称的一部分,所以可以用于区分同一设备的不同接口,通常为NULL
&dx->ifSymLinkName); //输出接口符号链接名,完成使用时,必须用RtlFreeUnicodeString释放这个Unicode字符串
if(!NT_SUCCESS(status))
{
IoDeleteDevice(pfdo);
return status;
}
IoSetDeviceInterfaceState(&dx->ifSymLinkName,TRUE); //使符号连接数有效

//Attach to the driver stack below us
dx->NextStackDevice = IoAttachDeviceToDeviceStack(pfdo,pdo); //连接两设备,返回指向被pfdo连接上的设备对象指针(可看成设备栈的连接点)

//Set fdo flags appropriately
pfdo->Flags &= ~DO_DEVICE_INITIALIZING; //设备对象正在初始化
pfdo->Flags |= DO_BUFFERED_IO; //读写操作使用缓冲方式(系统复制缓冲区)访问用户模式数据
pfdo->Flags |= DO_POWER_PAGABLE; //the driver is pageable and prevents it from getting power IRPs at IRQL >= DISPATCH_LEVEL

return STATUS_SUCCESS;
}

#pragma code_seg()


<WDMDispatch.cpp>

#include "WDM.h"
#include "Ioctl.h"

//Buffer and BuuferSize and guarding spin lock globals(in unpaged memory)
KSPIN_LOCK BufferLock;
PUCHAR Buffer = NULL;
ULONG BufferSize = 0;

NTSTATUS Create(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);//得到当前I/O栈单元

ULONG MinorFunction = IrpStack->MinorFunction; //查看副功能类
ULONG MajorFunction = IrpStack->MajorFunction; //查看主功能类

NTSTATUS Data = CompleteIrp(Irp,STATUS_SUCCESS,0); //调用完成例程
return Data;
}

NTSTATUS Close(IN PDEVICE_OBJECT fdo,IN PIRP Irp) //由CloseHandle触发
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);

ULONG MinorFunction = IrpStack->MinorFunction; //查看副功能类
ULONG MajorFunction = IrpStack->MajorFunction; //查看主功能类

NTSTATUS Data = CompleteIrp(Irp,STATUS_SUCCESS,0); //调用完成例程
return Data;
}

NTSTATUS Read(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);//得到当前I/O栈单元

ULONG MinorFunction = IrpStack->MinorFunction; //查看副功能类
ULONG MajorFunction = IrpStack->MajorFunction; //查看主功能类

NTSTATUS status = STATUS_SUCCESS;
LONG BytesTxd = 0;

//Get call parameters See Windows WDM P110
LONGLONG FilePointer = IrpStack->Parameters.Read.ByteOffset.QuadPart; //Specifies a 64-bit signed integer.
//typedef __int64 LONGLONG;
ULONG ReadLen = IrpStack->Parameters.Read.Length; //读出数据长度

//Get access to the shared buffer //须在DriverEntry里初始化 KeInitializeSpinLock(&BufferLock);
KIRQL irql;
KeAcquireSpinLock(&BufferLock,&irql); //获得自旋锁

//Check file pointer
if(FilePointer<0)
status = STATUS_INVALID_PARAMETER; //设置为无效参数
if(FilePointer >=(LONGLONG)BufferSize)
status = STATUS_END_OF_FILE;
// The end-of-file marker has been reached. There is no valid data in the file beyond this marker.
if(status == STATUS_SUCCESS)
{
//Get transfer count
if(((ULONG)FilePointer)+ReadLen > BufferSize)
{
BytesTxd = BufferSize - (ULONG)FilePointer;
if(BytesTxd < 0)BytesTxd = 0;
}
else
BytesTxd = ReadLen;

//Read from shared buffer
if(BytesTxd > 0 &&Buffer != NULL)
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,Buffer+FilePointer,BytesTxd);
//copies the contents of one buffer Buffer+FilePointer to another(Buffered I/O)
}

//Release shared buffer
KeReleaseSpinLock(&BufferLock,irql);
NTSTATUS Data = CompleteIrp(Irp,status,BytesTxd); //调用完成例程

return Data;
}

NTSTATUS Write(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);

ULONG MinorFunction = IrpStack->MinorFunction; //查看副功能类
ULONG MajorFunction = IrpStack->MajorFunction; //查看主功能类

NTSTATUS status = STATUS_SUCCESS;
LONG BytesTxd = 0;

//Get call parameters See Windows WDM P110 p108
LONGLONG FilePointer = IrpStack->Parameters.Write.ByteOffset.QuadPart; //Specifies a 64-bit signed integer.
//typedef __int64 LONGLONG;
ULONG WriteLen = IrpStack->Parameters.Write.Length; //读出数据长度

//Check file pointer
if(FilePointer<0)
status = STATUS_INVALID_PARAMETER; //设置为无效参数
else
{
//Get access to the shared buffer //须在DriverEntry里初始化 KeInitializeSpinLock(&BufferLock);
KIRQL irql;
KeAcquireSpinLock(&BufferLock,&irql); //获得自旋锁

BytesTxd = WriteLen;

//(Re)allocate buffer if neccesary
if(((ULONG)FilePointer)+WriteLen > BufferSize)
{
ULONG NewBufferSize = ((ULONG)FilePointer)+WriteLen;
PVOID NewBuffer = ExAllocatePool(NonPagedPool,NewBufferSize);
if(NewBuffer == NULL)
{
BytesTxd = BufferSize - (ULONG)FilePointer;
if(BytesTxd < 0)BytesTxd = 0;
}
else
{
RtlZeroMemory(NewBuffer,NewBufferSize);
if(Buffer != NULL)
{
RtlCopyMemory(NewBuffer,Buffer,BufferSize);
ExFreePool(Buffer);
}
Buffer = (PUCHAR)NewBuffer;
BufferSize = NewBufferSize;
}
}

//Write to shared memory
if(BytesTxd > 0 && Buffer !=NULL)
RtlCopyMemory(Buffer+FilePointer,Irp->AssociatedIrp.SystemBuffer,BytesTxd);
//copies the contents of one buffer Buffer+FilePointer to another(Buffered I/O)
//Irp->AssociatedIrp.SystemBuffer与传递下来的WriteFile中的应用程序传递给驱动程序的数据缓冲区地址关联
//Release shared buffer
KeReleaseSpinLock(&BufferLock,irql);
}

NTSTATUS Data = CompleteIrp(Irp,status,BytesTxd); //调用完成例程
return Data;
}

NTSTATUS DeviceControl(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);//得到当前I/O栈单元,

ULONG MinorFunction = IrpStack->MinorFunction; //查看副功能类
ULONG MajorFunction = IrpStack->MajorFunction; //查看主功能类

NTSTATUS status = STATUS_SUCCESS;
LONG BytesTxd = 0;

ULONG ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
ULONG InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;

//Get access to the shared buffer
KIRQL irql; //typedef UCHAR KIRQL;
KeAcquireSpinLock(&BufferLock,&irql);

switch(ControlCode)
{
//Zero Buffer
case Ehci_IOCTL_ZERO_BUFFER:
if(Buffer != NULL && BufferSize>0)
RtlZeroMemory(Buffer,BufferSize+1);
break;
/// Remove Buffer
case Ehci_IOCTL_REMOVE_BUFFER:
if( Buffer!=NULL)
{
ExFreePool(Buffer);
Buffer = NULL;
BufferSize = 0;
}
break;
/// Get Buffer Size as ULONG
case Ehci_IOCTL_GET_BUFFER_SIZE:
if( OutputLength<sizeof(ULONG))
status = STATUS_INVALID_PARAMETER;
else
{
BytesTxd = sizeof(ULONG);
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,&BufferSize,sizeof(ULONG));
}
break;
/// Get Buffer
case Ehci_IOCTL_GET_BUFFER:
if( OutputLength>BufferSize)
status = STATUS_INVALID_PARAMETER;
else
{
BytesTxd = OutputLength;
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,Buffer,BytesTxd);
}
break;
///Invalid request
default:
status = STATUS_INVALID_DEVICE_REQUEST;
}

//Release share buffer
KeReleaseSpinLock(&BufferLock,irql);

NTSTATUS Data = CompleteIrp(Irp,status,BytesTxd); //调用完成例程
return Data;
}

NTSTATUS SystemControl(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);

ULONG MinorFunction = IrpStack->MinorFunction; //查看副功能类
ULONG MajorFunction = IrpStack->MajorFunction; //查看主功能类

//just pass to lower driver
IoSkipCurrentIrpStackLocation(Irp);
PUSB_DEVICE_EXTENSION dx = (PUSB_DEVICE_EXTENSION)fdo->DeviceExtension;

NTSTATUS Data = IoCallDriver(dx->NextStackDevice,Irp); //调用完成例程
return Data;
}

//完成一个IRP必须先填充IoStatus块的Status和Information成员,然后调用IoCompleteRequest例程
NTSTATUS CompleteIrp(PIRP Irp,NTSTATUS status,ULONG info) //完成例程
{
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest(Irp,IO_NO_INCREMENT); //发送完成请求设置处理级别等待系统处理
//#define IO_NO_INCREMENT 0 //完成请求的处理级别优先权为0
//用于提升阻塞线程优先级的boost值不太好选择。一个较好的笨方法是指定IO_NO_INCREMENT值,当然,如果你有更好的值,可以不用这个值。
//如果事件唤醒的是一个处理时间敏感数据流的线程(如声卡驱动程序),那么应该使用适合那种设备的boost值(如IO_SOUND_INCREMENT)。重要的是,
//不要为一个愚蠢的理由去提高等待者的优先级。例如,如果你要同步处理一个IRP_MJ_PNP请求,那么在你要停下来等待低级驱动程序处理完该IRP时,
//你的完成例程应调用KeSetEvent。由于PnP请求对于处理器没有特殊要求并且也不经常发生,所以即使是声卡驱动程序也也应该把boost参数指定为IO_NO_INCREMENT。

return status;
}


<WDMPnp.h>

#include "WDMPnp.h"


#pragma code_seg("PAGE")

NTSTATUS Pnp(IN PDEVICE_OBJECT fdo,IN PIRP IRP)
{
PUSB_DEVICE_EXTENSION dx = (PUSB_DEVICE_EXTENSION)fdo->DeviceExtension; //得到设备扩展

//Remember minor function
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(IRP); //得到当前I/O栈单元,参考Windows WDM P113

ULONG MinorFunction = IrpStack->MinorFunction; //查看副功能类
ULONG MajorFunction = IrpStack->MajorFunction; //查看主功能类

//Just pass to lower driver
IoSkipCurrentIrpStackLocation(IRP); //The IoSkipCurrentIrpStackLocation macro modifies the system's IO_STACK_LOCATION array pointer,
//so that when the current driver calls the next-lower driver, that driver receives the same IO_STACK_LOCATION
//structure that the current driver received
//如果在IoCallDriver前调用此函数说明低层驱动将收到与此层相同的IO_STACK_LOCATION(非复制),它只是在内部建立IRP,
//使得下一个驱动程序对IoGetCurrentIrpStackLocation的调用返回与此看到的相同的栈单元
//这个宏的作用就是使堆栈指针少前进一步,而IoCallDriver函数会使堆栈指针向前一步,中和的结果就是堆栈指针不变

NTSTATUS status = IoCallDriver(dx->NextStackDevice,IRP); //不等待IRP完成,传递IRP到下一个底层驱动程序

//IoGetCurrentIrpStackLocation,IoSkipCurrentIrpStackLocation和IoCallDriver的联合使用实现了IRP传递

if(MinorFunction == IRP_MN_REMOVE_DEVICE)
{
IoSetDeviceInterfaceState(&dx->ifSymLinkName,FALSE); //禁止设备接口
RtlFreeUnicodeString(&dx->ifSymLinkName); //释放内存缓冲区
if(dx->NextStackDevice)
IoDetachDevice(dx->NextStackDevice); //把pfdo从设备栈脱开
IoDeleteDevice(fdo); //删除pfdo和它的设备扩展
}

return status;
}

NTSTATUS Power(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
{
PUSB_DEVICE_EXTENSION dx = (PUSB_DEVICE_EXTENSION)fdo->DeviceExtension;

PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG MinorFunction = IrpStack->MinorFunction; //查看副功能类
ULONG MajorFunction = IrpStack->MajorFunction; //查看主功能类

//Just pass to lower driver
PoStartNextPowerIrp(Irp); //简单地把一个IRP沿设备栈向下传递(没有完成例程),则在跳过或复制当前IRP之前调用此函数

IoSkipCurrentIrpStackLocation(Irp); //见前

return PoCallDriver(dx->NextStackDevice,Irp);//电源管理特有的调用函数等同IoCallDriver
//PoStartNextPowerIrp,IoSkipCurrentIrpStackLocation,PoCallDriver联合使用方式
}

#pragma code_seg()

<WDM.inf>

;; WDM.inf

;; ********* PLEASE READ ***********
;; The wizard cannot create exact INF files for all buses and device types.
;; You may have to make changes to this file in order to get your device to
;; install. In particular, hardware IDs and logical configurations require
;; intervention.
;;
;; The Windows DDK documentation contains an excellent INF reference.

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

[Version]
Signature="$Windows 95$"

; 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=CompuwareUnknown
ClassGUID={ff696f80-8def-11d2-9449-00105a075f6b}
Provider=%ProviderName%


;--------- 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 = "Install Disk",Disk1,,

;[SourceDisksFiles]
;WDM.sys = 1,,

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值