⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 functions.c

📁 This the fourth edition of the Writing Device Drivers articles. This article will introduce the idea
💻 C
📖 第 1 页 / 共 5 页
字号:
/**********************************************************************
 * 
 *  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 + -