📄 functions.c
字号:
/**********************************************************************
*
* Toby Opferman
*
* Driver Example
*
* This example is for educational purposes only. I license this source
* out for use in learning how to write a device driver.
*
* Driver Functionality
**********************************************************************/
#define _X86_
#include <wdm.h>
#include "example.h"
#include <public.h>
/*
* Internal IOCTL's.
*
*/
#define IOCTL_CREATE_NEW_RESOURCE_CONTEXT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
#define IOCTL_CLOSE_RESOURCE_CONTEXT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED,FILE_READ_DATA | FILE_WRITE_DATA)
#define MIN(a,b) ((a) < (b) ? (a) : (b))
/**********************************************************************
* Internal Functions
**********************************************************************/
BOOLEAN Example_WriteData(PEXAMPLE_LIST pExampleList, PCHAR pData, UINT uiLength, UINT *pdwStringLength);
BOOLEAN Example_ReadData(PEXAMPLE_LIST pExampleList, PCHAR pData, UINT uiLength, UINT *pdwStringLength);
BOOLEAN Example_IsStringTerminated(PCHAR pString, UINT uiLength, UINT *pdwStringLength);
NTSTATUS Example_HandleSampleIoctl_DirectInIo(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp, UINT *pdwDataWritten);
NTSTATUS Example_HandleSampleIoctl_DirectOutIo(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp, UINT *pdwDataWritten);
NTSTATUS Example_HandleSampleIoctl_BufferedIo(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp, UINT *pdwDataWritten);
NTSTATUS Example_HandleSampleIoctl_NeitherIo(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp, UINT *pdwDataWritten);
NTSTATUS Example_CreatePipeContext(PEXAMPLE_DEVICE_CONTEXT pExampleDeviceContext, PFILE_OBJECT pFileObject);
NTSTATUS Example_ReleasePipeContext(PEXAMPLE_DEVICE_CONTEXT pExampleDeviceContext, PFILE_OBJECT pFileObject);
NTSTATUS Example_CreateNewResource(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp, UINT *pdwDataWritten);
NTSTATUS Example_DestroyResource(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp, UINT *pdwDataWritten);
NTSTATUS Example_SampleCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
NTSTATUS Example_SampleCompletionRoutineWithIoManager(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
#pragma alloc_text(PAGE, Example_SampleCompletionRoutineWithIoManager)
#pragma alloc_text(PAGE, Example_IoControlInternal)
#pragma alloc_text(PAGE, Example_CreateNewResource)
#pragma alloc_text(PAGE, Example_DestroyResource)
#pragma alloc_text(PAGE, Example_Create)
#pragma alloc_text(PAGE, Example_Close)
#pragma alloc_text(PAGE, Example_IoControl)
#pragma alloc_text(PAGE, Example_ReadDirectIO)
#pragma alloc_text(PAGE, Example_ReadBufferedIO)
#pragma alloc_text(PAGE, Example_ReadNeither)
#pragma alloc_text(PAGE, Example_WriteDirectIO)
#pragma alloc_text(PAGE, Example_WriteBufferedIO)
#pragma alloc_text(PAGE, Example_WriteNeither)
#pragma alloc_text(PAGE, Example_UnSupportedFunction)
#pragma alloc_text(PAGE, Example_WriteData)
#pragma alloc_text(PAGE, Example_ReadData)
#pragma alloc_text(PAGE, Example_HandleSampleIoctl_DirectInIo)
#pragma alloc_text(PAGE, Example_HandleSampleIoctl_DirectOutIo)
#pragma alloc_text(PAGE, Example_HandleSampleIoctl_NeitherIo)
#pragma alloc_text(PAGE, Example_HandleSampleIoctl_DirectInIo)
#pragma alloc_text(PAGE, Example_CreatePipeContext)
#pragma alloc_text(PAGE, Example_ReleasePipeContext)
#pragma alloc_text(PAGE, Example_IsStringTerminated)
#pragma alloc_text(PAGE, Example_SampleCompletionRoutine)
/**********************************************************************
*
* Example_Create
*
* This is called when an instance of this driver is created (CreateFile)
*
**********************************************************************/
NTSTATUS Example_Create(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION pIoStackIrp = NULL;
/*
* Each time the IRP is passed down the driver stack a new stack location is added
* specifying certain parameters for the IRP to the driver.
*/
pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
DbgPrint("Example_Create Called \r\n");
NtStatus = Example_CreatePipeContext((PEXAMPLE_DEVICE_CONTEXT)DeviceObject->DeviceExtension, pIoStackIrp->FileObject);
/*
* This does not always need to be completed in this manner. The I/O Manager is friendly
* and in the simple case (as this driver is implemented) the IRP will be completed
* by IoCompleteRequest() and the Status will be set to the return value.
*
* What will not be set however is the "Information" field, it cannot be set to how many bytes
* were read or written obviously because the I/O Manager does not know, only your device
* driver does.
*
* There are cases where you will need to complete the IRP and set the status however
* our simple driver does not require that.
*
* In the Write operation the "bytes written" is really only used as an informant to
* the application. The Read operation is a bit different. For example, some types of buffering
* it may not matter if you set the number of bytes read. For example "Neither" you write
* directly into the user mode buffer so the user mode gets the data even if you don't
* tell it the amount. However if you remember how buffered I/O works? It makes a copy
* in memory. If the I/O manager doesn't know the size then it can't copy it back to the
* user mode buffer.
*
*
* IO_NO_INCREMENT - What is this? If an IRP request is taking a long time you may want to help
* the scheduler to re-schedule the thread as soon as possible. For example perhaps it issued
* a network request and went to sleep. Then on another thread the network request completes
* You may want to use one of the pre-defined constants or your own to increment the priority of
* that thread to be rescheduled being since it hasn't been scheduled in a while.
*
*/
Irp->IoStatus.Status = NtStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
DbgPrint("Example_Create Exit 0x%0x \r\n", NtStatus);
return NtStatus;
}
/**********************************************************************
*
* Example_CreatePipeContext
*
* This is called to create or find a pipe context
*
**********************************************************************/
NTSTATUS Example_CreatePipeContext(PEXAMPLE_DEVICE_CONTEXT pExampleDeviceContext, PFILE_OBJECT pFileObject)
{
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
PEXAMPLE_LIST pExampleList = NULL;
BOOLEAN bNeedsToCreate = FALSE;
NtStatus = KeWaitForMutexObject(&pExampleDeviceContext->kListMutex, Executive, KernelMode, FALSE, NULL);
if(NT_SUCCESS(NtStatus))
{
pExampleList = pExampleDeviceContext->pExampleList;
bNeedsToCreate = TRUE;
if(pExampleList)
{
do
{ /*
* We want to use the unicode string that was used to open the driver to
* identify "pipe contexts" and match up applications that open the same name
* we do this by keeping a global list of all open instances in the device
* extension context.
* We then use reference counting so we only remove an instance from the list
* after all instances have been deleted. We also put this in the FsContext
* of the IRP so all IRP's will be returned with this so we can easily use
* the context without searching for it.
*/
if(RtlCompareUnicodeString(&pExampleList->usPipeName, &pFileObject->FileName, TRUE) == 0)
{
bNeedsToCreate = FALSE;
pExampleList->uiRefCount++;
pFileObject->FsContext = (PVOID)pExampleList;
NtStatus = STATUS_SUCCESS;
}
else
{
pExampleList = pExampleList->pNext;
}
} while(pExampleList && bNeedsToCreate) ;
}
if(bNeedsToCreate)
{
PIRP MyIrp = NULL;
/*
* In this example, we simply moved the previous code into the private IOCTL's.
* We will allocate an IRP and sent it to our own driver. This task could be done
* with another device obviously but in this case we are doing it with our own. As
* you can see we could easily have issued any major IRP function it's not limited
* to private IOCTLs. Also, this is a simple implementation and there is a little
* matter of "pending IRP's" that has been left out for simplicity. It doesn't matter
* much however since this is our driver and we control all end points.
*
* The first parameter is the number of IO_STACK_LOCATION's that are allocated for this
* IRP. We use the "StackSize" of the DeviceObject which tells the minimum number
* needed to send a request down this device stack. The initial value is 1 and then
* any device driver which then attaches to the device stack of this driver will then
* add to this number. If some higher level driver wants to allocate an IRP and do
* some processing on it as well as apart of this IRP stack then it should keep
* that in mind when allocating the IRP and ensuring the correct number of stack
* locations is allocated.
*
* The second parameter is to determine whether this IRP should be charged to the
* quota of the current process.
*
* IoBuildSynchronousFsdRequest & IoBuildAsynchronousFsdRequest actually do what
* we are doing here execpt they do it for you in one function call. There is a slight
* difference as well though as SynchronousFsdRequest will do a little more so the I/O
* Manager is aware and will cal IoFreeIrp for you where BuildAsyncrhonous will not.
*
* Other than that, IoBuildSynchronousFsdRequest actually calls IoBuildAsynchronousFsdRequest
* if you look at these in a debugger.
*
* IoBuildDeviceIoControlRequest Also does this for you, infact even more since it also sets up
* the IO_STACK_LOCATION with the correct Major IRP function and IOCTL code.
*/
MyIrp = IoAllocateIrp(pFileObject->DeviceObject->StackSize, FALSE);
if(MyIrp)
{
PIO_STACK_LOCATION pMyIoStackLocation = IoGetNextIrpStackLocation(MyIrp);
pMyIoStackLocation->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
pMyIoStackLocation->Parameters.DeviceIoControl.IoControlCode = IOCTL_CREATE_NEW_RESOURCE_CONTEXT;
/*
* METHOD_BUFFERED
*
* Input Buffer = Irp->AssociatedIrp.SystemBuffer
* Ouput Buffer = Irp->AssociatedIrp.SystemBuffer
*
* Input Size = Parameters.DeviceIoControl.InputBufferLength
* Output Size = Parameters.DeviceIoControl.OutputBufferLength
*
* Since we are now doing the same job as the I/O Manager,
* to follow the rules our IOCTL specified METHOD_BUFFERED
*/
pMyIoStackLocation->Parameters.DeviceIoControl.InputBufferLength = sizeof(FILE_OBJECT);
pMyIoStackLocation->Parameters.DeviceIoControl.OutputBufferLength = 0;
/*
* This is not really how you use IOCTL's but this is simply an example using
* an existing implementation. We will simply set our File Object as the SystemBuffer.
* Then the IOCTL handler will know it's a pFileObject and implement the code that we
* had here previously.
*/
MyIrp->AssociatedIrp.SystemBuffer = pFileObject;
MyIrp->MdlAddress = NULL;
/*
* A Completion Routine notifies that the IRP has been completed. This is when
* we will then clean up all memory associated with the IRP and infact actually
* remove the returned data or whatever else we need to do.
*
* Parameter 1 - the IRP
* Parameter 2 - Our Completion Routine
* Parameter 3 - a context that you create in Non-Paged memory (IRQL <= DISPATCH_LEVEL)
* Parameter 4 - Sucess - Invoke this call on success?
* Parameter 5 - Error - Inovke this call on error?
* Parameter 6 - Cancel - Invoke this call on cancel?
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -