📄 functions.c
字号:
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: We are using OUR DeviceObject here so the filter driver is by-passed!
*/
NtStatus = IoCallDriver(pFileObject->DeviceObject, MyIrp);
}
else
{
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
KeReleaseMutex(&pExampleDeviceContext->kListMutex, FALSE);
}
return NtStatus;
}
/**********************************************************************
*
* Example_ReleasePipeContext
*
* This is called to close a pipe context
*
**********************************************************************/
NTSTATUS Example_ReleasePipeContext(PEXAMPLE_DEVICE_CONTEXT pExampleDeviceContext, PFILE_OBJECT pFileObject)
{
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
PEXAMPLE_LIST pExampleList = NULL, pExampleListFromIrp = (PEXAMPLE_LIST)pFileObject->FsContext;
BOOLEAN bNotFound = TRUE;
PDEVICE_OBJECT pTopOfStackDevice = NULL;
LARGE_INTEGER StartOffset = {0};
IO_STATUS_BLOCK StatusBlock = {0};
NtStatus = KeWaitForMutexObject(&pExampleDeviceContext->kListMutex, Executive, KernelMode, FALSE, NULL);
if(NT_SUCCESS(NtStatus))
{
pExampleList = pExampleDeviceContext->pExampleList;
if(pExampleListFromIrp)
{
if(pExampleList == pExampleListFromIrp)
{
bNotFound = FALSE;
pExampleListFromIrp->uiRefCount--;
if(pExampleListFromIrp->uiRefCount == 0)
{
PIRP MyIrp = NULL;
pExampleDeviceContext->pExampleList = pExampleList->pNext;
/*
* 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.
*
* We set the other parameters to NULL since we will set them manually anyway.
*/
pTopOfStackDevice = IoGetRelatedDeviceObject(pFileObject);
MyIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_INTERNAL_DEVICE_CONTROL, pTopOfStackDevice, NULL, 0, &StartOffset, &StatusBlock);
if(MyIrp)
{
PIO_STACK_LOCATION pMyIoStackLocation = IoGetNextIrpStackLocation(MyIrp);
pMyIoStackLocation->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
pMyIoStackLocation->Parameters.DeviceIoControl.IoControlCode = IOCTL_CLOSE_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(EXAMPLE_LIST);
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 = 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
{
do
{
if(pExampleListFromIrp == pExampleList->pNext)
{
bNotFound = FALSE;
pExampleListFromIrp->uiRefCount--;
if(pExampleListFromIrp->uiRefCount == 0)
{
PIRP MyIrp = NULL;
pExampleList->pNext = pExampleListFromIrp->pNext;
/*
* 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.
*
* We set the other parameters to NULL since we will set them manually anyway.
*/
pTopOfStackDevice = IoGetRelatedDeviceObject(pFileObject);
MyIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_INTERNAL_DEVICE_CONTROL, pTopOfStackDevice, NULL, 0, &StartOffset, &StatusBlock);
if(MyIrp)
{
PIO_STACK_LOCATION pMyIoStackLocation = IoGetNextIrpStackLocation(MyIrp);
pMyIoStackLocation->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
pMyIoStackLocation->Parameters.DeviceIoControl.IoControlCode = IOCTL_CLOSE_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(EXAMPLE_LIST);
pMyIoStackLocation->Parameters.DeviceIoControl.OutputBufferLength = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -