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

📄 functions.c

📁 This the fourth edition of the Writing Device Drivers articles. This article will introduce the idea
💻 C
📖 第 1 页 / 共 5 页
字号:

                                 /*
                                  * 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 = pExampleListFromIrp;
                                 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?
                                  */

                                 IoSetCompletionRoutine(MyIrp, Example_SampleCompletionRoutine, NULL, TRUE, TRUE, TRUE);

                                 /*
                                  *  After we have set up the IRP and the IO_STACK_LOCATION we then simply need to
                                  *  call the device object (Which is simply our own) along with the IRP.  This
                                  *  will simply invoke the appropriate function in the driver and nothing more.
                                  *
                                  *  It is still up to the driver to complete the IRP.  We cannot access the
                                  *  IRP after this call since the completion of the IRP should be handled with
                                  *  our completion routine which will then delete the IRP.
                                  *
                                  *  P.S. Notice we never set the FILE_OBJECT of this IO_STACK_LOCATION.  The FILE_OBJECT is essentially
                                  *  the handle.  We are basically making a contextless call into the driver.
                                  *
                                  *  Never pass down values in the IRP on the stack.  The IRP may be processed out of context.
                                  *  Technically we should have added a reference to the FILE_OBJECT since we passed it down
                                  *  however for simplicity we simply passed it down and didn't care.
                                  *
                                  *  NOTE: In the original code we didn't use IoGetRelatedDeviceObject() so we
                                  *        simply used OUR device object and bypassed the filter.  If we call
                                  *        this API we will get the top of the device stack and all devices
                                  *        attached in the stack will be called.
                                  */
                                 NtStatus = IoCallDriver(pTopOfStackDevice, MyIrp);
                             }
                             else
                             {
                                 NtStatus = STATUS_INSUFFICIENT_RESOURCES;
                             }
                         }
                      }
                      else
                      {
                          pExampleList = pExampleList->pNext;
                      }
    
                  } while(pExampleList && bNotFound == TRUE) ;
              }
         }

         if(bNotFound)
         {
             NtStatus = STATUS_UNSUCCESSFUL; /* Should Never Reach Here!!!!! */
         }



         KeReleaseMutex(&pExampleDeviceContext->kListMutex, FALSE);
    }
   
    
    return NtStatus;
}

/**********************************************************************
 * 
 *  Example_Close
 *
 *    This is called when an instance of this driver is closed (CloseHandle)
 *
 **********************************************************************/
NTSTATUS Example_Close(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_Close Called \r\n");

    NtStatus = Example_ReleasePipeContext((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_Close Exit 0x%0x \r\n", NtStatus);
    return NtStatus;
}


/**********************************************************************
 * 
 *  Example_IoControlInternal
 *
 *    These are IOCTL's which can only be sent by other drivers.
 *
 **********************************************************************/
NTSTATUS Example_IoControlInternal(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    NTSTATUS NtStatus = STATUS_NOT_SUPPORTED;
    PIO_STACK_LOCATION pIoStackIrp = NULL;
    UINT dwDataWritten = 0;

    DbgPrint("Example_IoControlInternal Called \r\n");
    
    /*
     * 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);    

    if(pIoStackIrp) /* Should Never Be NULL! */
    {
        DbgPrint("Example_IoControlInternal Called IOCTL = 0x%0x\r\n", pIoStackIrp->Parameters.DeviceIoControl.IoControlCode);
        switch(pIoStackIrp->Parameters.DeviceIoControl.IoControlCode)
        {
            case IOCTL_CREATE_NEW_RESOURCE_CONTEXT:
                 NtStatus = Example_CreateNewResource(Irp, pIoStackIrp, &dwDataWritten);
                 break;

            case IOCTL_CLOSE_RESOURCE_CONTEXT:
                 NtStatus = Example_DestroyResource(Irp, pIoStackIrp, &dwDataWritten);
                 break;
        }
    }
    /*
     * 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;
    Irp->IoStatus.Information = dwDataWritten;

    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    DbgPrint("Example_IoControlInternal Exit 0x%0x \r\n", NtStatus);
    return NtStatus;

}



/**********************************************************************
 * 
 *  Example_IoControl
 *
 *    This is called when an IOCTL is issued on the device handle (DeviceIoControl)
 *
 **********************************************************************/
NTSTATUS Example_IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    NTSTATUS NtStatus = STATUS_NOT_SUPPORTED;
    PIO_STACK_LOCATION pIoStackIrp = NULL;
    UINT dwDataWritten = 0;

    DbgPrint("Example_IoControl Called \r\n");
    
    /*
     * 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);    

    if(pIoStackIrp) /* Should Never Be NULL! */
    {
        DbgPrint("Example_IoControl Called IOCTL = 0x%0x\r\n", pIoStackIrp->Parameters.DeviceIoControl.IoControlCode);
        switch(pIoStackIrp->Parameters.DeviceIoControl.IoControlCode)
        {
            case IOCTL_EXAMPLE_SAMPLE_DIRECT_IN_IO:
                 NtStatus = Example_HandleSampleIoctl_DirectInIo(Irp, pIoStackIrp, &dwDataWritten);
                 break;

            case IOCTL_EXAMPLE_SAMPLE_DIRECT_OUT_IO:
                 NtStatus = Example_HandleSampleIoctl_DirectOutIo(Irp, pIoStackIrp, &dwDataWritten);
                 break;

            case IOCTL_EXAMPLE_SAMPLE_BUFFERED_IO:
                 NtStatus = Example_HandleSampleIoctl_BufferedIo(Irp, pIoStackIrp, &dwDataWritten);
                 break;

            case IOCTL_EXAMPLE_SAMPLE_NEITHER_IO:
                 NtStatus = Example_HandleSampleIoctl_NeitherIo(Irp, pIoStackIrp, &dwDataWritten);
                 break;
        }
    }

    /*
     * 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -