Download EaseFilter Filter Driver SDK Setup File Download EaseFilter Filter Driver SDK Zip File
A context is a
structure that is defined by the minifilter driver and that can be associated with a filter manager object. Minifilter drivers can create and set contexts for the
following objects:
·
Files
(Windows Vista and later only.)
·
Instances
·
Volumes
·
Streams
·
Stream handles (file objects)
·
Transactions
(Windows Vista and later only.)
Except for volume
contexts, which must be allocated from nonpaged pool, contexts can be allocated from paged or nonpaged pool.
The filter manager
deletes contexts automatically when the objects that they are
attached to are deleted, when a minifilter driver instance is detached from a volume, or when the minifilter driver is unloaded.
Registering Context Types
When a minifilter driver calls FltRegisterFilter from its DriverEntry routine, it must register
each type of context that it uses.
To register context
types, the minifilter driver creates a
variable-length array of FLT_CONTEXT_REGISTRATION structures and stores a
pointer to the array in the ContextRegistration member of the FLT_REGISTRATION structure that the minifilter driver passes in the Registration parameter of FltRegisterFilter.
The order of the elements in this array does not matter. However, the last
element in the array must be {FLT_CONTEXT_END}.
For each context type
that the minifilter driver uses, it must supply at
least one context definition in the form of an FLT_CONTEXT_REGISTRATION
structure. Each FLT_CONTEXT_REGISTRATION structure defines the type, size, and
other information for the context.
When the minifilter driver creates a new context by calling FltAllocateContext, the filter manager uses the Size parameter of the FltAllocateContext routine,
as well as the Size and Flags members of the
FLT_CONTEXT_REGISTRATION structure, to select the context definition to be used.
For fixed-size contexts,
the Size member of the FLT_CONTEXT_REGISTRATION structure specifies the
size, in bytes, of the portion of the context stucture that is defined by the minifilter driver. The maximum size for a context is MAXUSHORT (64 KB). Zero is a valid
size value. The filter manager implements fixed-size contexts using lookaside lists. The filter manager creates two lookaside lists for each size value: one paged and one nonpaged.
For variable-size
contexts, the Size member must be set to
FLT_VARIABLE_SIZED_CONTEXTS. The filter manager allocates variable-size
contexts directly from paged or nonpaged pool.
In the Flags member of the FLT_CONTEXT_REGISTRATION structure, the
FLTFL_CONTEXT_REGISTRATION_NO_EXACT_SIZE_MATCH flag can be
specified. If the minifilter driver uses
fixed-size contexts and this flag is specified, the
filter manager allocates a context from the lookaside list if the context's size is greater than or equal to the requested size.
Otherwise, the context's size must be equal to the requested size.
For a given context
type, the minifilter driver can supply up to three
fixed-size context definitions, each with a different size, and one
variable-size definition. For more information, see FLT_CONTEXT_REGISTRATION.
The minifilter driver can optionally supply a context cleanup callback
routine to be called before the context is freed. For more information,
see PFLT_CONTEXT_CLEANUP_CALLBACK.
A minifilter driver can optionally define its own callback routines for allocating and freeing
contexts, instead of relying on the filter manager to perform these tasks.
However, this is very rarely necessary. For more information, see
PFLT_CONTEXT_ALLOCATE_CALLBACK and PFLT_CONTEXT_FREE_CALLBACK.
The following code
example, which is taken from the CTX sample minifilter driver, shows an array of
FLT_CONTEXT_REGISTRATION structures that are used to register instance, file,
stream, and file object (stream handle) contexts.
const FLT_CONTEXT_REGISTRATION contextRegistration[] = {
{ FLT_INSTANCE_CONTEXT, //ContextType
0, //Flags
CtxContextCleanup, //ContextCleanupCallback
CTX_INSTANCE_CONTEXT_SIZE, //Size
CTX_INSTANCE_CONTEXT_TAG }, //PoolTag
{ FLT_FILE_CONTEXT, //ContextType
0, //Flags
CtxContextCleanup, //ContextCleanupCallback
CTX_FILE_CONTEXT_SIZE, //Size
CTX_FILE_CONTEXT_TAG }, //PoolTag
{ FLT_STREAM_CONTEXT, //ContextType
0, //Flags
CtxContextCleanup, //ContextCleanupCallback
CTX_STREAM_CONTEXT_SIZE, //Size
CTX_STREAM_CONTEXT_TAG }, //PoolTag
{ FLT_STREAMHANDLE_CONTEXT, //ContextType
0, //Flags
CtxContextCleanup, //ContextCleanupCallback
CTX_STREAMHANDLE_CONTEXT_SIZE, //Size
CTX_STREAMHANDLE_CONTEXT_TAG }, //PoolTag
{ FLT_CONTEXT_END }
};
Once
a minifilter driver has registered the context types
that it uses, it can create a context by calling FltAllocateContext.
This routine selects the appropriate context definition to use according to the
criteria described in Registering Context Types.
In
the following code example, taken from the CTX sample minifilter driver, the CtxInstanceSetup routine calls FltAllocateContext to create an instance context:
status = FltAllocateContext(
FltObjects->Filter, //Filter
FLT_INSTANCE_CONTEXT, //ContextType
CTX_INSTANCE_CONTEXT_SIZE, //ContextSize
NonPagedPool, //PoolType
&instanceContext); //ReturnedContext
In
the CTX sample, the following context definition is
registered for instance contexts:
{ FLT_INSTANCE_CONTEXT, //ContextType
0, //Flags
CtxContextCleanup, //ContextCleanupCallback
CTX_INSTANCE_CONTEXT_SIZE, //Size
CTX_INSTANCE_CONTEXT_TAG }, //PoolTag
This
is a fixed-size context definition, because the Size member is a
constant. (If the Size member were FLT_VARIABLE_SIZED_CONTEXTS, it would
be a variable-size context definition.) Note that the
FLTFL_CONTEXT_REGISTRATION_NO_EXACT_SIZE_MATCH flag is not set in the Flags member. In this case, if the value of the Size parameter of FltAllocateContext matches that of the Size member of the context definition, FltAllocateContext allocates the instance context from the appropriate nonpaged lookaside list. If the values do not match, FltAllocateContext fails with a return value of
STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND.
FltAllocateContext initializes the reference
count on the new context to one. When the context is no
longer needed, the minifilter driver must
release this reference. Thus, every call to FltAllocateContext must be matched by a subsequent call to FltReleaseContext.
After
creating a new context, a minifilter driver can
attach it to an object by calling FltSetXxxContext,
where Xxx is the context type.
If
the Operation parameter of the FltSetXxxContext routine is set to FLT_SET_CONTEXT_KEEP_IF_EXISTS, FltSetXxxContext attaches the newly allocated context to the object only if the minifilter driver has not already set a context for the
object. If the minifilter driver has already set a
context, FltSetXxxContext returns STATUS_FLT_CONTEXT_ALREADY_DEFINED, which is an NTSTATUS error code,
and does not replace the existing context. If the OldContext parameter of the FltSetXxxContext routine is non-NULL, it receives a pointer to the existing context. When this
pointer is no longer needed, the minifilter driver must release it by calling FltReleaseContext.
If
the Operation parameter is set to FLT_SET_CONTEXT_REPLACE_IF_EXISTS, FltSetXxxContext always attaches the
new context to the object. If the minifilter driver
has already set a context, FltSetXxxContext deletes the existing context, sets the new context, and increments the
reference count on the new context. If the OldContext parameter is non-NULL, it receives a pointer to the deleted context. When this
pointer is no longer needed, the minifilter driver must release it by calling FltReleaseContext.
In
the following code example, taken from the CTX sample minifilter driver, the CtxInstanceSetup routine creates
and sets an instance context:
status = FltAllocateContext(
FltObjects->Filter, //Filter
FLT_INSTANCE_CONTEXT, //ContextType
CTX_INSTANCE_CONTEXT_SIZE, //ContextSize
NonPagedPool, //PoolType
&instanceContext); //ReturnedContext
...
status = FltSetInstanceContext(
FltObjects->Instance, //Instance
FLT_SET_CONTEXT_KEEP_IF_EXISTS, //Operation
instanceContext, //NewContext
NULL); //OldContext
if (instanceContext != NULL) {
FltReleaseContext(instanceContext);
}
return status;
Note
that after the call to FltSetInstanceContext,
there is a call to FltReleaseContext to
release the reference count that was set by FltAllocateContext (not FltSetInstanceContext).
This is explained in Releasing Contexts.
Once
a minifilter driver has set a context for an object,
it can get the context by calling FltGetXxxContext,
where Xxx is the context type.
In
the following code example, taken from the SwapBuffers sample minifilter driver, the minifilter driver calls FltGetVolumeContext to get a
volume context:
status = FltGetVolumeContext(
FltObjects->Filter, //Filter
FltObjects->Volume, //Volume
&volCtx); //Context
...
if (volCtx != NULL) {
FltReleaseContext(volCtx);
}
If
the call to FltGetVolumeContext is successful,
the Context parameter receives the address of the caller's volume
context. FltGetVolumeContext increments the reference count on the Context pointer. Thus, when
this pointer is no longer needed, the minifilter driver must release it by calling FltReleaseContext.
The
filter manager uses reference counting to manage the lifetime of a minifilter driver context. A reference count is a number
indicating the state of a context. Whenever a context is
created or is referenced by a system component, the reference count of
the context is incremented by one. When a context is no
longer needed, its reference count is decremented. A positive reference
count means that the context is usable. When the reference count becomes zero,
the context is unusable, and the filter manager eventually frees it.
A minifilter driver can add its own reference to a
context by calling FltReferenceContext to
increment the context's reference count. This added reference must eventually be removed by calling FltReleaseContext.
A minifilter driver releases a context by calling FltReleaseContext. Every successful call to one of
the following routines must eventually be matched by a
call to FltReleaseContext:
FltAllocateContext
FltGetXxxContext
FltReferenceContext
Note
that the OldContext pointer returned by FltSetXxxContext and the Context pointer returned by FltDeleteContext must also be released when they are no longer needed.
In
the following code example, taken from the CTX sample minifilter driver, the CtxInstanceSetup routine creates
and sets an instance context and then calls FltReleaseContext:
status = FltAllocateContext(
FltObjects->Filter, //Filter
FLT_INSTANCE_CONTEXT, //ContextType
CTX_INSTANCE_CONTEXT_SIZE, //ContextSize
NonPagedPool, //PoolType
&instanceContext); //ReturnedContext
...
status = FltSetInstanceContext(
FltObjects->Instance, //Instance
FLT_SET_CONTEXT_KEEP_IF_EXISTS, //Operation
instanceContext, //NewContext
NULL); //OldContext
if (instanceContext != NULL) {
FltReleaseContext(instanceContext);
}
return status;
Note
that FltReleaseContext is
called regardless of whether the call to FltSetInstanceContext succeeds. In both cases, the caller must call FltReleaseContext to release the reference set by FltAllocateContext (not FltSetInstanceContext).
If
the context is successfully set for the instance, FltSetInstanceContext adds its own reference to the instance context. Thus, the reference set by FltAllocateContext is no longer
needed, and the call to FltReleaseContext removes it.
If
the call to FltSetInstanceContext fails, the
instance context has only one reference, namely the one set by FltAllocateContext. When FltReleaseContext returns, the instance context has a reference count of zero, and it is freed by the filter manager.
Every
context that is set by a successful call to FltSetXxxContext must eventually be
deleted. However, the filter manager deletes contexts automatically when the
objects that they are attached to are deleted, when a minifilter driver instance is detached from a volume, or
when the minifilter driver is unloaded. Thus, it is
rarely necessary for a minifilter driver to explicitly delete a context.
A minifilter driver can delete a context by calling FltDeleteXxxContext, where Xxx is the context type, or by calling FltDeleteContext.
A
context can be deleted only if it is currently set for
an object. A context cannot be deleted if it has not
yet been set, or if it has already been replaced by a successful call to FltSetXxxContext.
In
the call to FltDeleteXxxContext,
the old context is returned in the OldContext parameter, if it is non-NULL. If the OldContext parameter is NULL, the filter manager decrements the reference
count on the context, which is then freed unless the minifilter driver has an outstanding reference on it.
The
following code example shows how to delete a stream context:
status = FltDeleteStreamContext(
FltObjects->Instance, //Instance
FltObjects->FileObject,
//FileObject
&oldContext); //OldContext
...
if (oldContext != NULL) {
FltReleaseContext(oldContext);
}
In
this example, FltDeleteStreamContext removes
the stream context from the stream, but it does not decrement the context's
reference count, because the OldContext parameter is non-NULL. FltDeleteStreamContext returns the address of the deleted context in the OldContext parameter. After performing any needed processing, the caller must release the
deleted context by calling FltReleaseContext.
A
context is freed after it is deleted and all
outstanding references to it have been released.
There
is one exception to this rule: if a context has been created but has not been set by calling FltSetXxxContext,
it does not need to be deleted. It is freed when its
reference count reaches zero. (See the code example in Releasing Contexts.)
When
a minifilter driver registers its context types, each
context definition can optionally include a context cleanup
callback routine to be called before the context is freed. For more
information, see PFLT_CONTEXT_CLEANUP_CALLBACK.
To
support file contexts (if applicable), stream contexts, and file object (stream
handle) contexts, a file system must use the
FSRTL_ADVANCED_FCB_HEADER structure. All Microsoft Windows file systems use
this structure, and all third-party file system
developers are strongly encouraged to do so as well. For more information, see FsRtlSetupAdvancedHeader and
FSRTL_ADVANCED_FCB_HEADER.
The
NTFS and FAT file systems do not support file, stream, or file object contexts
on paging files, in the pre-create or post-close path, or for
IRP_MJ_NETWORK_QUERY_OPEN operations.
A minifilter driver can determine whether a file system
supports stream contexts and file object contexts for a given file object by
calling FltSupportsStreamContexts and FltSupportsStreamHandleContexts, respectively.
File
contexts are available on Windows Vista and later.
For
file systems (such as FAT) that support only a single data stream per file,
file contexts are equivalent to stream contexts. Such file systems usually
support stream contexts but do not support file contexts. Instead, the filter
manager provides this support, using the file system's existing support for
stream contexts. For minifilter driver instances
attached to these file systems, FltSupportsFileContexts returns FALSE, while FltSupportsFileContextsEx returns TRUE (when a valid non-NULL value is passed for the Instance parameter).
To
support file contexts, a file system must:
·
Embed a FileContextSupportPointer member of type PVOID in its file context structure, usually the file context
block (FCB). The file system must initialize this member to NULL.
·
Use FsRtlSetupAdvancedHeaderEx (instead of FsRtlSetupAdvancedHeader) to
initialize its stream context structure, passing a valid pointer to the FileContextSupportPointer member (embedded in the
corresponding file context structure) for the FileContextSupportPointer parameter. For more information, see FsRtlSetupAdvancedHeaderEx and FSRTL_ADVANCED_FCB_HEADER.
· Call FsRtlTeardownPerFileContexts to free all file context structures that filter and minifilter drivers have associated with a file when the file system deletes its file context structure for the file.