Develop File System Mini Filter Driver Step By Step
minispy Minifilter Sample
              
            Description
              
            The minispy sample is a tool to monitor and log any I/O
              and transaction activity that occurs in the system. This sample is similar to
              the FileSpy legacy filter; however, unlike FileSpy, minispy has been implemented as a minifilter.
              
Theory
              of Operation
                
            minispy consists of both user-mode and kernel-mode components. The kernel-mode
              component registers callback functions that correspond to various I/O and
              transaction operations with the filter manager. These callback functions help minispy record any I/O and transaction activity occurring
              in the system. When a user can request the recorded information, the recorded
              information is passed to the user-mode component,
              which can either output it on screen or log it to a file on disk.
              
To
              observe I/O activity on a device, you must explicitly attach minispy to that device by using the minispy user-mode component. Similarly, you can request minispy to stop logging data for a particular device.
              
Implementation
              and Design
                
            You
              should use this sample if you are developing a minifilter.
              
Building
              the Sample
                
            
              
              1. 
              
              Open the appropriate WDK free or check build environment to set
                basic environment variables that the build utility needs.
                
              
              2. 
              
              Navigate to the directory that contains the device source code
                (for example, CD src\filesys\miniFilter\minispy).
                
              
              3. 
              
              Run build -ceZor use the BCZ macro.
                This behavior calls the Microsoft make routines that produce log files
                called Buildxxx_yyy_zzz.log, Buildxx_yyy_zzz.wrn,
                and Buildxxx_yyy_zzz.err if there are
                any warnings or errors. xxx stands for "fre"
                or "chk" depending on the environment you
                choose, yyy stands for the operating
                system version (for example, "Wlh" for
                Windows Vista), and zzz stands for the
                platform version (for example, "x86" for x86-based, "IA64"
                for Itanium-based, or "AMD64" for x64-based).
                
If
              the build succeeds, the driver, minispy.sys, will be placed in a
              platform-specific subdirectory of your %TargetPath% directory that is specified
              in the sources file.
              
Installation
              
            End User
              
The minispy minifilter comes
              with an INF file that will install the minifilter. To
              install the minifilter, do the following:
              
              
              1. 
              
              Make sure that minispy.exe, minspy.sys, and minispy.inf are in the same directory.
                
              
              2. 
              
              In Windows Explorer, right-click minispy.inf, and click Install.
                
This
              installation will make the necessary registry updates to register the metadata
              service and place minispy.sys in the %SystemRoot%\system32\drivers directory.
              
To
              load this minifilter, run fltmc load minispy or net start minispy.
              
              
Writing a DriverEntry Routine for a Minifilter Driver
              
Every file
              system minifilter driver must have a DriverEntry routine. The DriverEntry routine is called when the minifilter driver is loaded.
              
The DriverEntry routine performs global initialization, registers the minifilter driver, and initiates filtering. This routine runs in a system thread context
              at IRQL PASSIVE_LEVEL.
              
The DriverEntry routine is defined as follows:
              
NTSTATUS 
              (*PDRIVER_INITIALIZE) ( 
              IN PDRIVER_OBJECT DriverObject, 
              IN PUNICODE_STRING RegistryPath 
              ); 
              
              
              
              
DriverEntry has two input parameters. The first, DriverObject,
              is the driver object that was created when the minifilter driver was loaded. The second, RegistryPath, is a pointer to a counted Unicode
              string that contains a path to the minifilter driver's registry key.
              
A minifilter driver's DriverEntry routine must perform the
              following steps, in order:
              
              
              1. 
              
              Perform any needed global initialization for the minifilter driver.
                
              
              2. 
              
              Register the minifilter driver by calling FltRegisterFilter.
                
              
              3. 
              
              Initiate filtering by calling FltStartFiltering.
                
              
              4. 
              
              Return an appropriate NTSTATUS value.
                
Registering the Minifilter Driver
              
            Every minifilter driver must call FltRegisterFilter from its DriverEntry routine to add itself to
              the global list of registered minifilter drivers and
              to provide the filter manager with a list of callback routines and other
              information about the driver.
              
In
              the MiniSpy sample, the minifilter driver is registered as shown in the following code
              example:
              
              status = FltRegisterFilter(
              DriverObject, //Driver
              &FilterRegistration, //Registration
              &MiniSpyData.FilterHandle); //RetFilter
              
              
              
              
FltRegisterFilter has two input parameters. The
              first, Driver, is the driver object pointer that the minifilter driver received as the DriverObject input
              parameter to its DriverEntry routine. The
              second, Registration, is a pointer to an FLT_REGISTRATION structure that
              contains entry points to the minifilter driver's
              callback routines.
              
In
              addition, FltRegisterFilter has an output
              parameter, RetFilter, that receives an opaque filter pointer for the minifilter driver. This filter pointer is a required input
              parameter for many FltXxx support
              routines, including FltStartFiltering and FltUnregisterFilter.
              
Initiating Filtering
              
            After
              calling FltRegisterFilter, a minifilter driver's DriverEntry routine typically calls FltStartFiltering to
              begin filtering I/O operations.
              
Every minifilter driver must call FltStartFiltering from its DriverEntry routine to notify the
              filter manager that the minifilter driver is ready to
              begin attaching to volumes and filtering I/O requests. After the minifilter driver calls FltStartFiltering,
              the filter manager treats the minifilter driver as a
              fully active minifilter driver, presenting it with
              I/O requests and notifications of volumes to attach to.
              The minifilter driver must be prepared to begin
              receiving these I/O requests and notifications even before FltStartFiltering returns.
              
In
              the MiniSpy sample driver, FltStartFiltering is called as shown in the following code example:
              
              if( !NT_SUCCESS( status )) {
              FltUnregisterFilter( MiniSpyData.FilterHandle );
              }
              
              
              
              
If
              the call to FltStartFiltering does not return
              STATUS_SUCCESS, the minifilter driver must call FltUnregisterFilter to unregister itself.
              
Returning Status from a Minifilter DriverEntry Routine
              
            A minifilter driver's DriverEntry routine normally returns STATUS_SUCCESS. But if minifilter initialization fails, the DriverEntry routine should return an appropriate error NTSTATUS value.
              
If
              the DriverEntry routine returns a status value
              that is not a success NTSTATUS value, the system responds by unloading the minifilter driver. The minifilter driver's FilterUnloadCallback routine is not called. For this reason, the DriverEntry routine must free any memory that was allocated for
              system resources before returning a status value that is not a success NTSTATUS
              value.
              
              
              
//---------------------------------------------------------------------------
              
//                      ROUTINES
              
//---------------------------------------------------------------------------
              
              
NTSTATUS
              
DriverEntry
              (
              
    __in PDRIVER_OBJECT
              DriverObject,
              
    __in PUNICODE_STRING
              RegistryPath
              
    )
              
/*++
              
              
Routine Description:
              
              
    This
              routine is called when a driver first loads.  Its purpose is to
              
    initialize global state and then register with FltMgr to start
              filtering.
              
              
Arguments:
              
              
    DriverObject - Pointer to driver object created by the system to
              
        represent this driver.
              
    RegistryPath - Unicode string identifying where the parameters for this
              
        driver are located in the registry.
              
              
Return Value:
              
              
    Status of the operation.
              
              
--*/
              
{
              
    PSECURITY_DESCRIPTOR sd;
              
    OBJECT_ATTRIBUTES oa;
              
    UNICODE_STRING uniString;
              
    NTSTATUS status =
              STATUS_SUCCESS;
              
              
    try {
              
              
        //
              
        // Initialize global data structures.
              
        //
              
              
        MiniSpyData.LogSequenceNumber = 0;
              
        MiniSpyData.MaxRecordsToAllocate = DEFAULT_MAX_RECORDS_TO_ALLOCATE;
              
        MiniSpyData.RecordsAllocated = 0;
              
        MiniSpyData.NameQueryMethod = DEFAULT_NAME_QUERY_METHOD;
              
              
        MiniSpyData.DriverObject = DriverObject;
              
              
        InitializeListHead( &MiniSpyData.OutputBufferList );
              
        KeInitializeSpinLock( &MiniSpyData.OutputBufferLock );
              
              
        ExInitializeNPagedLookasideList( &MiniSpyData.FreeBufferList,
              
                                         NULL,
              
                                         NULL,
              
                                         0,
              
                                         RECORD_SIZE,
              
                                         SPY_TAG,
              
                                         0 );
              
              
#if MINISPY_VISTA
              
              
        //
              
        //  Dynamically
              import FilterMgr APIs for transaction support
              
        //
              
              
#pragma warning(push)
              
#pragma warning(disable:4055) // type cast
              from data pointer to function pointer
              
        MiniSpyData.PFltSetTransactionContext = (PFLT_SET_TRANSACTION_CONTEXT)
              FltGetRoutineAddress( "FltSetTransactionContext" );
              
        MiniSpyData.PFltGetTransactionContext = (PFLT_GET_TRANSACTION_CONTEXT)
              FltGetRoutineAddress( "FltGetTransactionContext" );
              
        MiniSpyData.PFltEnlistInTransaction = (PFLT_ENLIST_IN_TRANSACTION)
              FltGetRoutineAddress( "FltEnlistInTransaction" );
              
#pragma warning(pop)
              
              
#endif
              
              
        //
              
        // Read the custom parameters for MiniSpy from the registry
              
        //
              
              
        SpyReadDriverParameters(RegistryPath);
              
              
        //
              
        //  Now that our
              global configuration is complete, register with FltMgr.
              
        //
              
              
        status = FltRegisterFilter( DriverObject,
              
                                    &FilterRegistration,
              
                                    &MiniSpyData.Filter );
              
              
        if (!NT_SUCCESS( status )) {
              
              
           leave;
              
        }
              
              
              
        status  =
              FltBuildDefaultSecurityDescriptor( &sd,
              
                                                     FLT_PORT_ALL_ACCESS );
              
              
        if (!NT_SUCCESS( status )) {
              
            leave;
              
        }
              
              
        RtlInitUnicodeString( &uniString, MINISPY_PORT_NAME );
              
              
        InitializeObjectAttributes( &oa,
              
                                    &uniString,
              
                                    OBJ_KERNEL_HANDLE
              | OBJ_CASE_INSENSITIVE,
              
                                    NULL,
              
                                    sd );
              
              
        status = FltCreateCommunicationPort( MiniSpyData.Filter,
              
                                             &MiniSpyData.ServerPort,
              
                                             &oa,
              
                                             NULL,
              
                                             SpyConnect,
              
                                             SpyDisconnect,
              
                                             SpyMessage,
              
                                             1 );
              
              
        FltFreeSecurityDescriptor( sd );
              
              
        if (!NT_SUCCESS( status )) {
              
            leave;
              
        }
              
              
        //
              
        //  We are now
              ready to start filtering
              
        //
              
              
        status = FltStartFiltering( MiniSpyData.Filter );
              
              
    } finally {
              
              
        if (!NT_SUCCESS( status ) ) {
              
              
             if (NULL != MiniSpyData.ServerPort) {
              
                 FltCloseCommunicationPort( MiniSpyData.ServerPort );
              
             }
              
              
             if (NULL != MiniSpyData.Filter) {
              
                 FltUnregisterFilter( MiniSpyData.Filter );
              
             }
              
              
             ExDeleteNPagedLookasideList( &MiniSpyData.FreeBufferList );
              
        }
              
    }
              
              
    return status;
              
}
              
Writing
              a FilterUnloadCallback Routine for a Minifilter Driver
              
            A file system minifilter driver can optionally register a 
              
Minifilter drivers are not required to register a FilterUnloadCallback routine. However, we strongly
              recommend that a minifilter driver registers this callback routine, because if a minifilter driver
              does not register a FilterUnloadCallback routine, the driver cannot be unloaded.
              
To
              register this callback routine, the minifilter driver
              stores the address of a PFLT_FILTER_UNLOAD_CALLBACK-typed routine in the FilterUnloadCallback member of the 
                
The FilterUnloadCallback routine is defined as follows:
              
typedef NTSTATUS
              (*PFLT_FILTER_UNLOAD_CALLBACK) (
              FLT_FILTER_UNLOAD_FLAGS Flags
              );
              
              
              
              
The FilterUnloadCallback routine has one input parameter, Flags, which can be NULL or
              FLTFL_FILTER_UNLOAD_MANDATORY. The filter manager sets this parameter to
              FLTFL_FILTER_UNLOAD_MANDATORY to indicate that the unload operation is
              mandatory. For more information about this parameter, see 
                
A minifilter driver's FilterUnloadCallback routine must
              perform the following steps:
              
              
              ·         
              
              Close any open kernel-mode communication server port handles.
                
              
              ·         
              
              Call 
                
              
              ·         
              
              Perform any needed global cleanup.
                
              
              ·         
              
              Return an appropriate NTSTATUS value.
                
Closing the Communication Server Port
              
            If
              the minifilter driver previously opened a kernel-mode
              communication server port by calling 
                
If
              a user-mode application has an open connection to the communication server
              port, any client port for that connection will remain open after FltCloseCommunicationPort returns. However, the
              filter manager will close any client ports when the minifilter driver is unloaded.
              
Unregistering the Minifilter
              
            A minifilter driver's 
              
              
              ·         
              
              The minifilter driver's callback routines are unregistered.
                
              
              ·         
              
              The minifilter driver's instances are torn down, and the minifilter driver's 
                
              
              ·         
              
              If the minifilter driver set any contexts on volumes, instances, streams, or stream handles,
                these contexts are deleted. If the minifilter driver has registered a 
                  
If
              there are outstanding rundown references on the minifilter driver's opaque filter pointer, FltUnregisterFilter enters a wait state until they are removed.
              Outstanding rundown references usually happen because the minifilter driver has called 
                
Outstanding
              rundown references can also happen if the minifilter driver has called any routines that add a rundown reference to the minifilter driver's opaque filter pointer, such as 
                
Performing Global Cleanup
              
            A minifilter driver's 
              
              
              ·         
              
              Call 
                
              
              ·         
              
              Call 
                
              
              ·         
              
              Call 
                
              
              ·         
              
              Call 
                
Returning Status from a FilterUnloadCallback Routine
              
            A minifilter driver's 
              
To
              refuse an unload operation that is not mandatory, the minifilter driver should return an appropriate warning or error NTSTATUS value such as
              STATUS_FLT_DO_NOT_DETACH. For more information about mandatory unload
              operations, see Writing a FilterUnloadCallback Routine and 
              
If
              the FilterUnloadCallback routine returns a
              warning or error NTSTATUS value and the unload operation is not mandatory, the minifilter driver will not be unloaded.
              
NTSTATUS
              
SpyFilterUnload
              (
              
    __in FLT_FILTER_UNLOAD_FLAGS
              Flags
              
    )
              
/*++
              
              
Routine Description:
              
              
    This
              is called when a request has been made to unload the filter.  Unload
              
    requests from the Operation System (ex: "sc stop minispy" can
              not be
              
    failed.  Other unload
              requests may be failed.
              
              
    You
              can disallow OS unload request by setting the
              
    FLTREGFL_DO_NOT_SUPPORT_SERVICE_STOP flag in the FLT_REGISTARTION
              
    structure.
              
              
Arguments:
              
              
    Flags - Flags pertinent to this operation
              
              
Return Value:
              
              
    Always success
              
              
--*/
              
{
              
    UNREFERENCED_PARAMETER(
              Flags );
              
              
    PAGED_CODE();
              
              
    //
              
    //  Close the server port. This will stop
              new connections.
              
    //
              
              
    FltCloseCommunicationPort(
              MiniSpyData.ServerPort );
              
              
    FltUnregisterFilter(
              MiniSpyData.Filter );
              
              
    SpyEmptyOutputBufferList();
              
    ExDeleteNPagedLookasideList(
              &MiniSpyData.FreeBufferList );
              
              
    return STATUS_SUCCESS;
              
}
              
              
Writing Preoperation and Postoperation Callback Routines
              
            In
              its DriverEntry routine, a minifilter driver can register up to one 
                
Unlike
              a legacy file system filter driver, a minifilter driver can choose which types of I/O operations
              to filter. A minifilter driver can register a preoperation callback routine for a given type of I/O
              operation without registering a postoperation callback, and vice versa. The minifilter driver
              receives only those I/O operations for which it has registered a preoperation or postoperation callback routine.
              
A preoperation callback routine is
              similar to a dispatch routine in the legacy filter driver
                model. When the filter manager processes an I/O operation, it calls the preoperation callback
              routine of each minifilter driver in the minifilter driver instance stack that has registered one for this type of I/O
              operation. The topmost minifilter driver in the
              stack—that is, the one whose instance has the highest altitude—receives the
              operation first. When that minifilter driver finishes
              processing the operation, it returns the operation to the filter manager, which
              then passes the operation to the next-highest minifilter driver, and so on. When all minifilter drivers in the minifilter driver instance stack have processed the I/O operation—unless a minifilter driver has completed the I/O operation—the
              filter manager sends the operation to legacy filters and the file system.
              
A postoperation callback routine is
              similar to a completion routine in the legacy filter driver
                model. Completion processing for an I/O operation begins when the I/O
              manager passes the operation to the file system and legacy filters that have
              registered completion routines for the operation. After these completion
              routines have finished, the filter manager performs completion processing for
              the operation. The filter manager then calls the postoperation callback routine of each minifilter driver in the minifilter driver instance stack that has registered one for this type of I/O
              operation. The bottom minifilter driver in the
              stack—that is, the one whose instance has the lowest altitude—receives the
              operation first. When that minifilter driver finishes
              processing the operation, it returns it to the filter manager, which then
              passes the operation to the next-lowest minifilter driver, and so on.
              
Registering Preoperation and Postoperation Callback Routines
              
            To
              register 
                
Each
              FLT_OPERATION_REGISTRATION structure in the array, except for the last one,
              contains the following information:
              
              
              ·         
              
              The major function code for the
                operation
                
              
              ·         
              
              For read and write operations
                (IRP_MJ_READ and IRP_MJ_WRITE), a set of flags that specify whether to ignore
                cached I/O or paging I/O or both for IRP-based I/O operations
                
              
              ·         
              
              Entry points for up to one preoperation callback routine and one postoperation callback routine
                
The
              last element in the array must be {IRP_MJ_OPERATION_END}.
              
The
              following code example, which is taken from the
              Scanner sample minifilter driver, shows an array of
              FLT_OPERATION_REGISTRATION structures. The Scanner sample minifilter driver registers preoperation and postoperation callback routines for IRP_MJ_CREATE and preoperation callback routines for IRP_MJ_CLEANUP and IRP_MJ_WRITE operations.
              
              {IRP_MJ_CREATE,
              0,
              ScannerPreCreate,
              ScannerPostCreate},
              {IRP_MJ_CLEANUP,
              0, 
              ScannerPreCleanup,
              NULL},
              {IRP_MJ_WRITE,
              0, 
              ScannerPreWrite,
              NULL},
              {IRP_MJ_OPERATION_END}
              };
              
              
              
              
Filtering I/O Operations in a Minifilter Driver
              
            The
              following list describes several guidelines for filtering specific types of I/O
              operations in a file system minifilter driver:
              
              
              ·         
              
              The 
                
              
              ·         
              
              The 
                
              
              ·         
              
              Minifilter drivers must never fail IRP_MJ_CLEANUP or IRP_MJ_CLOSE
                operations. These operations can be pended, returned to the
                  filter manager, or completed with STATUS_SUCCESS. However, a preoperation callback routine must never fail these
                operations.
                
              
              ·         
              
              Minifilter drivers cannot register a postoperation callback routine for IRP_MJ_SHUTDOWN.
                
Writing Preoperation Callback Routines
              
            A file system minifilter driver uses one or more preoperation callback
              routines to filter I/O operations. 
                
A minifilter driver registers a preoperation callback routine for a particular type of I/O operation by storing the callback
              routine's entry point in the OperationRegistration member of the 
                
Minifilter drivers receive only those types of I/O
              operations for which they have registered a preoperation or postoperation callback routine. A minifilter driver can register a preoperation callback routine for a given type of I/O operation without registering a 
                
Every preoperation callback routine is
              defined as follows:
              
              (*PFLT_PRE_OPERATION_CALLBACK) ( 
              IN OUT PFLT_CALLBACK_DATA Data, 
              IN PCFLT_RELATED_OBJECTS FltObjects, 
              OUT PVOID *CompletionContext 
              ); 
              
              
              
              
Like
              a dispatch routine, a preoperation callback routine
              can be called at IRQL = PASSIVE_LEVEL or at IRQL = APC_LEVEL. Typically it is
              called at IRQL = PASSIVE_LEVEL, in the context of the thread that originated
              the I/O request. For fast I/O and file system filter (FsFilter)
              operations, the preoperation callback routine is
              always called at IRQL = PASSIVE_LEVEL. However, for an IRP-based operation, a minifilter driver's preoperation callback routine can be called in the context of a
              system worker thread if a higher filter or minifilter driver pends the operation for processing by the worker thread.
              
When
              the filter manager calls a minifilter driver's preoperation callback routine for a given I/O operation,
              the minifilter driver temporarily controls the I/O
              operation. The minifilter driver retains this control
              until it does one of the following:
              
              
              ·         
              
              Returns
                a status value other than FLT_PREOP_PENDING from the preoperation callback routine.
                  
              
              ·         
              
              Calls 
                
Passing an I/O Operation Down the Minifilter Driver
              Instance Stack
              
            When
              a minifilter driver's 
                
A minifilter driver's preoperation callback routine returns an I/O operation to the
              filter manager for further processing by returning one of the following status
              values:
              
              
              ·         
              
              FLT_PREOP_SUCCESS_NO_CALLBACK
                (all operation types)
                
              
              ·         
              
              FLT_PREOP_SUCCESS_WITH_CALLBACK
                (all operation types)
                
              
              ·         
              
              FLT_PREOP_SYNCHRONIZE
                (IRP-based I/O operations only)
                
Note Although FLT_PREOP_SYNCHRONIZE should be
              returned only for IRP-based I/O operations, you can return this status
              value for other operation types. If it is returned for
              an I/O operation that is not an IRP-based I/O operation, the filter manager
              treats this return value as if it were FLT_PREOP_SUCCESS_WITH_CALLBACK.
              
Alternatively,
              the work routine for an operation that was pended in a preoperation callback routine returns an I/O operation to the
              filter manager by passing one of the preceding status values in the CallbackStatus parameter when it calls 
                
Returning FLT_PREOP_SUCCESS_WITH_CALLBACK
              
            If
              a minifilter driver's 
                
Note If the minifilter driver's preoperation callback routine returns
              FLT_PREOP_SUCCESS_WITH_CALLBACK but the minifilter driver has not registered a postoperation callback routine
              for the operation, the system asserts on a checked build.
              
If
              the minifilter driver's preoperation callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK, it can return a
              non-NULL value in its CompletionContext output
              parameter. This parameter is an optional context pointer that is passed to the corresponding postoperation callback routine. The postoperation callback routine
              receives this pointer in its CompletionContext input parameter.
              
The
              FLT_PREOP_SUCCESS_WITH_CALLBACK status value can be returned for all types of I/O operations.
              
Returning FLT_PREOP_SUCCESS_NO_CALLBACK
              
            If
              a minifilter driver's 
                
If
              the minifilter driver's preoperation callback routine returns FLT_PREOP_SUCCESS_NO_CALLBACK, it must return NULL in
              its CompletionContext output parameter.
              
The
              FLT_PREOP_SUCCESS_NO_CALLBACK status value can be returned for all types of I/O operations.
              
Returning FLT_PREOP_SYNCHRONIZE
              
            If
              a minifilter driver's 
                
The
              filter manager calls the minifilter driver's postoperation callback routine in the same thread context
              as the preoperation callback, at IRQL <=
              APC_LEVEL. (Note that this thread context is not necessarily the context of the
              originating thread.)
              
Note If the minifilter driver's preoperation callback routine returns
              FLT_PREOP_SYNCHRONIZE, but the minifilter driver has
              not registered a postoperation callback routine for
              the operation, the system asserts on a checked build.
              
If
              the minifilter driver's preoperation callback routine returns FLT_PREOP_SYNCHRONIZE, it can return a non-NULL value
              in its CompletionContext output parameter.
              This parameter is an optional context pointer that is passed to the corresponding postoperation callback routine.
              The postoperation callback routine receives this
              pointer in its CompletionContext input
              parameter.
              
A minifilter driver's preoperation callback routine should return FLT_PREOP_SYNCHRONIZE only for IRP-based I/O
              operations. However, this status value can be returned for other operation types. If it is returned for an
              I/O operation that is not an IRP-based I/O operation, the filter manager treats
              this return value as if it were FLT_PREOP_SUCCESS_WITH_CALLBACK. To determine
              whether an operation is an IRP-based I/O operation, use the 
                
Minifilter drivers should not return
              FLT_PREOP_SYNCHRONIZE for create operations, because these operations are
              already synchronized by the filter manager. If a minifilter driver has registered preoperation and postoperation callback routines for IRP_MJ_CREATE
              operations, the post-create callback routine is called at IRQL = PASSIVE_LEVEL,
              in the same thread context as the pre-create callback routine.
              
Minifilter drivers must never return
              FLT_PREOP_SYNCHRONIZE for asynchronous read or write operations. Doing so can
              severely degrade both minifilter driver and system
              performance and can even cause deadlocks if, for example, the modified page
              writer thread is blocked. Before returning FLT_PREOP_SYNCHRONIZE for an
              IRP-based read or write operation, a minifilter driver should verify that the operation is synchronous by calling 
                
The
              following types of I/O operations cannot be synchronized:
              
              
              ·         
              
              Oplock file system control (FSCTL) operations (MajorFunction is IRP_MJ_FILE_SYSTEM_CONTROL; FsControlCode is 
                
              
              ·         
              
              Notify change directory
                operations (MajorFunction is
                IRP_MJ_DIRECTORY_CONTROL; MinorFunction is
                IRP_MN_NOTIFY_CHANGE_DIRECTORY.)
                
              
              ·         
              
              Byte-range lock requests (MajorFunction is IRP_MJ_LOCK_CONTROL; MinorFunction is IRP_MN_LOCK.)
                
FLT_PREOP_SYNCHRONIZE cannot be returned for any of these operations.
              
Completing an I/O Operation in a Preoperation Callback Routine
              
            To complete an I/O operation means to halt processing for the operation,
              assign it a final NTSTATUS value, and return it to the filter manager.
              
When
              a minifilter driver completes an I/O operation, the
              filter manager does the following:
              
              
              ·         
              
              Does not
                send the operation to minifilter drivers below the
                current minifilter driver, to legacy filters, or to
                the file system.
                  
              
              ·         
              
              Calls the 
                
              
              ·         
              
              Does not call the current minifilter driver's postoperation callback routine for the operation, if one exists.
                
A minifilter driver's 
              
              
              1. 
              
              Setting the callback data structure's IoStatus.Status field to the final NTSTATUS value for the operation.
                
              
              2. 
              
              Returning FLT_PREOP_COMPLETE.
                
A preoperation callback routine that completes an I/O
              operation cannot set a non-NULL completion context (in the CompletionContext output parameter).
              
A minifilter driver can also complete an operation in
              the work routine for a previously pended I/O operation by performing the
              following steps:
              
              
              1. 
              
              Setting the callback data structure's IoStatus.Status field to the final NTSTATUS value for the operation.
                
              
              2. 
              
              Passing FLT_PREOP_COMPLETE in the CallbackStatus parameter when the work routine calls 
                
When
              completing an I/O operation, a minifilter driver must
              set the callback data structure's IoStatus.Status field to the final NTSTATUS value for the operation, but this NTSTATUS value
              cannot be STATUS_PENDING or STATUS_FLT_DISALLOW_FAST_IO. For a cleanup or close
              operation, the field must be STATUS_SUCCESS. These operations cannot be completed with any other NTSTATUS value.
              
Completing
              an I/O operation is often referred to as succeeding or failing the operation, depending on the NTSTATUS value:
              
              
              ·         
              
              To succeed an I/O
                operation means to complete it with a success or informational NTSTATUS value,
                such as STATUS_SUCCESS.
                
              
              ·         
              
              To fail an I/O operation
                means to complete it with an error or warning NTSTATUS value, such as
                STATUS_INVALID_DEVICE_REQUEST or STATUS_BUFFER_OVERFLOW.
                
NTSTATUS
              values are defined in ntstatus.h.
              These values fall into four categories: success, informational, warning, and
              error.
              
Disallowing a Fast I/O Operation in a Preoperation Callback Routine
              
            In
              certain circumstances, a minifilter driver might
              choose to disallow a fast I/O operation instead of completing it. Disallowing a
              fast I/O operation prevents the fast I/O path from being used for the operation.
              
Like
              completing an I/O operation, disallowing a fast I/O operation means to halt
              processing on it and return it to the filter manager. However, disallowing a
              fast I/O operation is different from completing it. If a minifilter driver disallows a fast I/O operation that was issued by the I/O manager, the I/O manager may reissue the same operation as an
              equivalent IRP-based operation.
              
When
              a minifilter driver's 
                
              
              ·         
              
              Does not
                send the operation to minifilter drivers below the
                current minifilter driver, to legacy filters, or to
                the file system.
                  
              
              ·         
              
              Calls the 
                
              
              ·         
              
              Does not call the current minifilter driver's postoperation callback routine for the operation, if one exists.
                
A minifilter driver disallows a fast I/O operation by
              returning FLT_PREOP_DISALLOW_FASTIO from the preoperation callback routine for the operation.
              
The preoperation callback routine should not set the
              callback data structure's IoStatus.Status field, because the filter manager automatically sets this field to
              STATUS_FLT_DISALLOW_FAST_IO.
              
FLT_PREOP_DISALLOW_FASTIO can only be returned for fast I/O operations. To
              determine whether an operation is a fast I/O operation, see 
                
Minifilter drivers cannot return
              FLT_PREOP_DISALLOW_FASTIO for IRP_MJ_SHUTDOWN, IRP_MJ_VOLUME_MOUNT, or
              IRP_MJ_VOLUME_DISMOUNT operations.
              
Pending an I/O Operation in a Preoperation Callback Routine
              
            A minifilter driver's 
              
A minifilter driver's preoperation callback routine pends an I/O operation by performing the following steps:
              
              
              1. 
              
              Posting the I/O operation to a system work queue by calling a
                routine such as 
                  
              
              2. 
              
              Returning FLT_PREOP_PENDING.
                
A minifilter driver that must pend all (or most) incoming I/O operations should not use routines such as FltQueueDeferredIoWorkItem to pend operations,
              because calling this routine can cause the system work queues to be flooded.
              Instead, such a minifilter driver should use a
              cancel-safe queue. For more information about using cancel-safe queues, see 
                
Note
              that the call to FltQueueDeferredIoWorkItem will fail if any of the following conditions are true:
              
              
              ·         
              
              The operation is not an
                IRP-based I/O operation.
                
              
              ·         
              
              The operation is a paging I/O
                operation.
                
              
              ·         
              
              The TopLevelIrp field of the current thread is not NULL. (For more information about how to
                find the value of this field, see 
                  
              
              ·         
              
              The target instance for the I/O
                operation is being torn down.
                
If
              the minifilter driver's preoperation callback routine returns FLT_PREOP_PENDING, it must return NULL in the CompletionContext output parameter.
              
A minifilter driver can return FLT_PREOP_PENDING only
              for IRP-based I/O operations. To determine whether an operation is an IRP-based
              I/O operation, use the 
                
The
              work routine that dequeues and processes the I/O
              operation must call FltCompletePendedPreOperation to resume processing for the operation.
              
Writing Postoperation Callback Routines
              
            A file system minifilter driver uses one or more postoperation callback
              routines to filter I/O operations.
              
              
A minifilter driver registers a postoperation callback routine for a particular type of I/O operation in the same way it
              registers a 
                
Minifilter drivers receive only those types of I/O
              operations for which they have registered a preoperation or postoperation callback routine. A minifilter driver can register a preoperation callback routine for a given type of I/O operation without registering a postoperation callback, and vice versa.
              
Every postoperation callback routine is
              defined as follows:
              
              (*PFLT_POST_OPERATION_CALLBACK) ( 
              IN OUT PFLT_CALLBACK_DATA Data, 
              IN PCFLT_RELATED_OBJECTS FltObjects, 
              IN PVOID CompletionContext, 
              IN FLT_POST_OPERATION_FLAGS Flags 
              ); 
              
              
              
              
Like
              a completion routine, a postoperation callback
              routine is called at IRQL <= DISPATCH_LEVEL, in an arbitrary thread context.
              
Because
              it can be called at IRQL = DISPATCH_LEVEL, a postoperation callback routine cannot call kernel-mode routines that must be called at a
              lower IRQL, such as 
                
The
              following situations are several exceptions to the preceding rule:
              
              
              ·         
              
              If a minifilter driver's preoperation callback routine returns
                FLT_PREOP_SYNCHRONIZE for an IRP-based I/O operation, the corresponding postoperation callback routine is called at IRQL <=
                APC_LEVEL, in the same thread context as the preoperation callback routine.
                
              
              ·         
              
              The postoperation callback routine for a fast I/O operation is called at IRQL = PASSIVE_LEVEL, in
                the same thread context as the preoperation callback
                routine.
                
              
              ·         
              
              Post-create callback routines
                are called at IRQL = PASSIVE_LEVEL, in the context of the thread that
                originated the IRP_MJ_CREATE operation.
                
When
              the filter manager calls a minifilter driver's postoperation callback routine for a given I/O operation,
              the minifilter driver temporarily controls the I/O
              operation. The minifilter driver retains this control
              until it does one of the following:
              
              
              ·         
              
              Returns
                FLT_POSTOP_FINISHED_PROCESSING from the postoperation callback routine.
                  
              
              ·         
              
              Calls 
                
Performing Completion Processing for an
              I/O Operation
              
            A minifilter driver's 
              
In
              addition, when a minifilter driver instance is being
              torn down, the filter manager "drains" any I/O operations for which
              the instance has received a 
                
When
              the FLTFL_POST_OPERATION_DRAINING flag is set, the minifilter driver must not perform normal completion processing. Instead, it should
              perform only necessary cleanup, such as freeing memory that the minifilter driver allocated for the CompletionContext parameter in its preoperation callback routine, and
              return FLT_POSTOP_FINISHED_PROCESSING.
              
Ensuring that Completion Processing is Performed at Safe IRQL
              
            As
              noted in Writing Postoperation Callback Routines, the 
              
However,
              for IRP-based I/O operations that are not already synchronized, minifilter drivers can use to two techniques to ensure that
              completion processing is performed at IRQL <= APC_LEVEL.
              
The
              first technique is for the postoperation callback
              routine to pend the I/O operation until completion
              processing can be performed at IRQL <= APC_LEVEL. This technique is described in Pending an I/O Operation in a Postoperation Callback Routine.
            
The
              second technique is for the minifilter driver's postoperation callback routine to call 
                
Pending an I/O Operation in a Postoperation Callback Routine
              
            A minifilter driver's 
              
              
              1. 
              
              Calling 
                
              
              2. 
              
              Calling 
                
              
              3. 
              
              Returning FLT_POSTOP_MORE_PROCESSING_REQUIRED.
                
Note
              that the call to FltQueueDeferredIoWorkItem will fail if any of the following conditions are true:
              
              
              ·         
              
              The operation is not an
                IRP-based I/O operation.
                
              
              ·         
              
              The operation is a paging I/O
                operation.
                
              
              ·         
              
              The TopLevelIrp field of the current thread is not NULL. (For more information about how to
                find the value of this field, see 
                  
              
              ·         
              
              The target instance for the I/O
                operation is being torn down. (The filter manager
                indicates this situation by setting the FLTFL_POST_OPERATION_DRAINING flag in
                the Flags input parameter to the postoperation callback routine.)
                
Minifilter drivers must be prepared to handle this
              failure. If your minifilter driver cannot handle such
              failures, you should consider using the technique that is
                described in Returning FLT_PREOP_SYNCHRONIZE instead of pending the I/O operation.
            
After
              the minifilter driver's postoperation callback routine returns FLT_POSTOP_MORE_PROCESSING_REQUIRED, the filter
              manager will not perform any further completion processing for the I/O
              operation until the minifilter driver's work routine
              calls 
                
The
              work routine that dequeues and performs completion
              processing for the I/O operation must call FltCompletePendedPostOperation to return control of the operation to the filter manager.
              
Failing an I/O Operation in a Postoperation Callback Routine
              
            A minifilter driver's 
              
For
              example, a minifilter driver's post-create callback
              routine can fail a successful IRP_MJ_CREATE operation by performing the
              following steps:
              
              
              1. 
              
              Calling 
                
              
              2. 
              
              Setting the callback data structure's IoStatus.Status field to the final NTSTATUS value for the operation. This value must be a valid error NTSTATUS value, such as
                STATUS_ACCESS_DENIED.
                
              
              3. 
              
              Setting the callback data structure's IoStatus.Information field to zero.
                
              
              4. 
              
              Returning FLT_POSTOP_FINISHED_PROCESSING.
                
When
              setting the callback data structure's IoStatus.Status field to the final NTSTATUS value for the operation, the minifilter driver must specify a valid error NTSTATUS value. Note that minifilter drivers cannot specify STATUS_FLT_DISALLOW_FAST_IO; only the filter manager can use this NTSTATUS value.
              
Callers
              of FltCancelFileOpen must be running at IRQL
              <= APC_LEVEL. However, a minifilter driver can
              safely call this routine from a post-create callback routine, because, for
              IRP_MJ_CREATE operations, the postoperation callback
              routine is called at IRQL = PASSIVE_LEVEL, in the context of the thread that
              originated the create operation.
              
Modifying the Parameters for an I/O
              Operation
              
            A minifilter driver can modify the parameters for an
              I/O operation. For example, a minifilter driver's 
                
The
              parameters for an I/O operation are found in the
              callback data (
                
If
              a minifilter driver's preoperation callback routine modifies the parameters for an I/O operation, all minifilter drivers below that minifilter driver in the minifilter driver instance stack will receive the modified parameters
              in their preoperation and postoperation callback routines.
              
The
              modified parameters are not received by the current minifilter driver's postoperation callback routine or by any minifilter drivers above
              that minifilter driver in the minifilter driver instance stack. In all situations, a minifilter driver's preoperation and postoperation callback routines receive the same input parameter values for a given I/O
              operation.
              
After
              modifying the parameters for an I/O operation, the preoperation or postoperation callback routine must indicate that
              it has done so by calling 
                
If
              a minifilter driver's preoperation callback routine modifies the parameters for an I/O operation, all minifilter drivers below that minifilter driver in the minifilter driver instance stack will receive the modified parameters
              in the Data and FltObjects input
              parameters to their preoperation and postoperation callback routines. (Minifilter drivers cannot directly modify the contents of the 
                
Although
              any parameter changes that a minifilter driver's preoperation callback routine makes are not received by the minifilter driver's own postoperation callback routine, a preoperation callback routine is
              able to pass information about changed parameters to the minifilter driver's own postoperation callback routine. If the preoperation callback routine passes the I/O operation down
              the stack by returning FLT_PREOP_SUCCESS_WITH_CALLBACK or
              FLT_PREOP_SYNCHRONIZE, it can store information about changed parameter values
              into a minifilter driver–defined structure that is pointed to by the CompletionContext output parameter. The filter manager passes this structure pointer in the CompletionContext input parameter to the postoperation callback routine.
              
              
CONST
              FLT_OPERATION_REGISTRATION Callbacks[] = {
              
    { IRP_MJ_CREATE,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_CREATE_NAMED_PIPE,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_CLOSE,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_READ,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_WRITE,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_QUERY_INFORMATION,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_SET_INFORMATION,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_QUERY_EA,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_SET_EA,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_FLUSH_BUFFERS,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    {
              IRP_MJ_QUERY_VOLUME_INFORMATION,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    {
              IRP_MJ_SET_VOLUME_INFORMATION,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_DIRECTORY_CONTROL,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    {
              IRP_MJ_FILE_SYSTEM_CONTROL,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback
              },
              
              
    { IRP_MJ_DEVICE_CONTROL,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    {
              IRP_MJ_INTERNAL_DEVICE_CONTROL,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_SHUTDOWN,
              
      0,
              
      SpyPreOperationCallback,
              
      NULL },                           //post operation callback not supported
              
              
    { IRP_MJ_LOCK_CONTROL,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_CLEANUP,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_CREATE_MAILSLOT,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_QUERY_SECURITY,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_SET_SECURITY,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_QUERY_QUOTA,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback
              },
              
              
    { IRP_MJ_SET_QUOTA,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_PNP,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    {
              IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    {
              IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    {
              IRP_MJ_ACQUIRE_FOR_MOD_WRITE,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    {
              IRP_MJ_RELEASE_FOR_MOD_WRITE,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    {
              IRP_MJ_ACQUIRE_FOR_CC_FLUSH,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    {
              IRP_MJ_RELEASE_FOR_CC_FLUSH,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
/*    {
              IRP_MJ_NOTIFY_STREAM_FILE_OBJECT,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },*/
              
              
    {
              IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_NETWORK_QUERY_OPEN,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_MDL_READ,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_MDL_READ_COMPLETE,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_PREPARE_MDL_WRITE,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback
              },
              
              
    { IRP_MJ_MDL_WRITE_COMPLETE,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_VOLUME_MOUNT,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_VOLUME_DISMOUNT,
              
      0,
              
      SpyPreOperationCallback,
              
      SpyPostOperationCallback },
              
              
    { IRP_MJ_OPERATION_END }
              
};
              
              
const FLT_CONTEXT_REGISTRATION Contexts[]
              = {
              
              
#if MINISPY_VISTA
              
              
    { FLT_TRANSACTION_CONTEXT,
              
      0,
              
      SpyDeleteTxfContext,
              
      sizeof(MINISPY_TRANSACTION_CONTEXT),
              
      'ypsM' },
              
              
#endif //
              MINISPY_VISTA
              
              
    { FLT_CONTEXT_END }
              
};
              
              
//
              
//  This defines
              what we want to filter with FltMgr
              
//
              
              
CONST
              FLT_REGISTRATION FilterRegistration = {
              
              
    sizeof(FLT_REGISTRATION),               //  Size
              
    FLT_REGISTRATION_VERSION,               //  Version
              
    0,                                      //  Flags
              
              
    Contexts,                               //  Context
              
    Callbacks,                              //  Operation callbacks
              
              
    SpyFilterUnload,                        //  FilterUnload
              
              
    NULL,                                   //  InstanceSetup
              
    SpyQueryTeardown,                       //  InstanceQueryTeardown
              
    NULL,                                   //  InstanceTeardownStart
              
    NULL,                                   //  InstanceTeardownComplete
              
              
    NULL,                                   //  GenerateFileName
              
    NULL,                                   //  GenerateDestinationFileName
              
    NULL                                    //  NormalizeNameComponent
              
              
#if MINISPY_VISTA
              
              
    ,
              
    SpyKtmNotificationCallback              //  KTM notification callback
              
              
#endif //
              MINISPY_VISTA
              
              
};
              
              
 
 


