📄 hellowdm.cpp
字号:
/***************************************************************
程序名称:Hello World for WDM
文件名称:HelloWDM.cpp
作者:罗聪
日期:2002-8-16
***************************************************************/
//一定要的头文件,声明了函数模块和变量:
#include "HelloWDM.h"
#include "Ioctl.h"
KSPIN_LOCK BufferLock;
PUCHAR Buffer = NULL;
ULONG BufferSize = 0;
/***************************************************************
函数名称:DriverEntry()
功能描述:WDM程序入口
***************************************************************/
//extern "C"是必须的,表示“用C链接”。如果你的文件名是HelloWDM.c的话,这句可以省略。
extern "C"
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
DbgPrint("Starting DriverEntry()\n");
//指定“添加设备”消息由函数“HelloWDMAddDevice()”来处理:
DriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
DriverObject->DriverUnload = Wdm1Unload;
//指定“即插即用”消息由函数“HelloWDMPnp()”来处理:
DriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;
DriverObject->MajorFunction[IRP_MJ_CREATE] = Wdm1Create;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = Wdm1Close;
DriverObject->MajorFunction[IRP_MJ_READ] = Wdm1Read;
DriverObject->MajorFunction[IRP_MJ_WRITE] = Wdm1Write;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Wdm1DeviceControl;
KeInitializeSpinLock(&BufferLock);
DbgPrint("DriverEntry completed");
//返回一个NTSTATUS值STATUS_SUCCESS。几乎所有的驱动程序例程都必须返回一个NTSTATUS值,这些值在NTSTATUS.H DDK头文件中有详细的定义。
return STATUS_SUCCESS;
}
NTSTATUS Wdm1Create(IN PDEVICE_OBJECT fdo,
IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
DbgPrint( "Create File is %T", &(IrpStack->FileObject->FileName));
// Complete successfully
return CompleteIrp(Irp,STATUS_SUCCESS,0);
}
NTSTATUS Wdm1Close( IN PDEVICE_OBJECT fdo,
IN PIRP Irp)
{
DbgPrint("Wdm1Close");
// Complete successfully
return CompleteIrp(Irp,STATUS_SUCCESS,0);
}
NTSTATUS Wdm1DeviceControl( IN PDEVICE_OBJECT fdo,
IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
ULONG BytesTxd = 0;
ULONG ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
ULONG InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
DbgPrint("DeviceIoControl: Control code %x InputLength %d OutputLength %d",
ControlCode, InputLength, OutputLength);
// Get access to the shared buffer
KIRQL irql;
KeAcquireSpinLock(&BufferLock,&irql);
switch( ControlCode)
{
/////// Zero Buffer
case IOCTL_WDM1_ZERO_BUFFER:
// Zero the buffer
if( Buffer!=NULL && BufferSize>0)
RtlZeroMemory(Buffer,BufferSize);
break;
/////// Remove Buffer
case IOCTL_WDM1_REMOVE_BUFFER:
if( Buffer!=NULL)
{
ExFreePool(Buffer);
Buffer = NULL;
BufferSize = 0;
}
break;
/////// Get Buffer Size as ULONG
case IOCTL_WDM1_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 IOCTL_WDM1_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 shared buffer
KeReleaseSpinLock(&BufferLock,irql);
DbgPrint("DeviceIoControl: %d bytes written",(int)BytesTxd);
// Complete IRP
return CompleteIrp(Irp,status,BytesTxd);
}
NTSTATUS Wdm1Read(IN PDEVICE_OBJECT fdo,
IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
LONG BytesTxd = 0;
// Get call parameters
LONGLONG FilePointer = IrpStack->Parameters.Read.ByteOffset.QuadPart;
ULONG ReadLen = IrpStack->Parameters.Read.Length;
DbgPrint("Read %d bytes from file pointer %d",(int)ReadLen,(int)FilePointer);
// Get access to the shared buffer
KIRQL irql;
KeAcquireSpinLock(&BufferLock,&irql);
// Check file pointer
if( FilePointer<0)
status = STATUS_INVALID_PARAMETER;
if( FilePointer>=(LONGLONG)BufferSize)
status = STATUS_END_OF_FILE;
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);
}
// Release shared buffer
KeReleaseSpinLock(&BufferLock,irql);
DbgPrint("Read: %d bytes returned",(int)BytesTxd);
// Complete IRP
return CompleteIrp(Irp,status,BytesTxd);
}
NTSTATUS Wdm1Write( IN PDEVICE_OBJECT fdo,
IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
LONG BytesTxd = 0;
// Get call parameters
LONGLONG FilePointer = IrpStack->Parameters.Write.ByteOffset.QuadPart;
ULONG WriteLen = IrpStack->Parameters.Write.Length;
DbgPrint("Write %d bytes from file pointer %d",(int)WriteLen,(int)FilePointer);
if( FilePointer<0)
status = STATUS_INVALID_PARAMETER;
else
{
// Get access to the shared buffer
KIRQL irql;
KeAcquireSpinLock(&BufferLock,&irql);
BytesTxd = WriteLen;
// (Re)allocate buffer if necessary
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);
// Release shared buffer
KeReleaseSpinLock(&BufferLock,irql);
}
DbgPrint("Write: %d bytes written",(int)BytesTxd);
// Complete IRP
return CompleteIrp(Irp,status,BytesTxd);
}
NTSTATUS CompleteIrp( PIRP Irp, NTSTATUS status, ULONG info)
{
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return status;
}
/***************************************************************
函数名称:HelloWDMAddDevice()
功能描述:处理“添加设备”消息
***************************************************************/
NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
//定义一个NTSTATUS类型的返回值:
NTSTATUS status;
//定义一个功能设备对象(Functional Device Object):
PDEVICE_OBJECT fdo;
UNICODE_STRING ntDeviceName;
UNICODE_STRING win32DeviceName;
RtlInitUnicodeString(&ntDeviceName, L"\\Device\\Twdm1");
RtlInitUnicodeString(&win32DeviceName, L"\\DosDevices\\Twdm1");
DbgPrint("Starting AddDevice()\n");
//创建我们的功能设备对象,并储存到fdo中:
status = IoCreateDevice(
DriverObject, //驱动程序对象
sizeof(DEVICE_EXTENSION), //要求的设备扩展的大小
&ntDeviceName, //设备名称,这里为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))
{
DbgPrint("AddDevice(): IoCreateDevice failed!");
return status;
}
else
{
DbgPrint("AddDevice(): IoCreateDevice OK!");
}
status = IoCreateSymbolicLink( &win32DeviceName, &ntDeviceName );
if (!NT_SUCCESS(status))
{
DbgPrint("TWDM: IoCreateSymbolicLink() faild ! \n");
}
else
{
DbgPrint("TWDM: IoCreateSymbolicLink() ok ! \n");
}
//创建一个设备扩展对象dx,用于存储指向fdo的指针:
PDEVICE_EXTENSION 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;
DbgPrint("AddDevice() OK!\n");
//返回值:
return STATUS_SUCCESS;
}
/***************************************************************
函数名称:HelloWDMPnp()
功能描述:处理“即插即用”消息
***************************************************************/
NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo,
IN PIRP Irp)
{
//创建一个设备扩展对象dx,用于存储指向fdo的指针:
PDEVICE_EXTENSION dx=(PDEVICE_EXTENSION)fdo->DeviceExtension;
//首先要通过函数IoGetCurrentIrpStackLocation()得到当前的IRP,并由此得到Minor Function:
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG MinorFunction = IrpStack->MinorFunction;
//然后把这个Minor Function传递给下一个设备栈:
IoSkipCurrentIrpStackLocation(Irp);
NTSTATUS 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;
}
VOID Wdm1Unload(IN PDRIVER_OBJECT DriverObject)
{
// Free buffer (do not need to acquire spin lock)
if( Buffer!=NULL)
ExFreePool(Buffer);
DbgPrint("Wdm1Unload");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -