📄 functions.c
字号:
/*
* 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 + -