IMO the documentation for the instance is badly phrased - it tries to tell
you what you should do, not what the calls do. This confused the heck out
of me when I started looking at it and appears to have done the same of many
others.
Me, I like to think about this in terms of a reference count and who “owns”
each count (actually when I write my own referenced objects I express that
in code and have multiple reference counts so when I lose a count I know
which path didn’t clear up behind itself).
When you call FltAllocateContext you get back a context with a reference of
- You (the caller) own that count.
When you call FltReferenceContext you add another reference (which you own).
When you call FltSetXxxContext one of two things will happen. If the
“attach” works, then the reference count is incremented, but that reference
count is “owned” by the data structure you are attached to (FsContext for
StreamContexts, FsContext2 for StreamHandleContext, and so forth). If the
“attach” failed then no reference count is added, but you still own any
reference counts you had when the function was called.
Time will pass and eventuall the data structure which owns that extra
reference count we added via FltSetXxxContext will go away. As it goes away
it will drop its reference count.
So after calling FltSetXxxContext you only need to down the count once (for
the count you added when you created the context). If the attach worked
then the context is still referenced, if not it will just go away.
Where the confusion starts is when you try to set a context, but one exists
and you asked to get that back. In this case the context you passed in will
not have the ref added for the backing structure (but you still need to
dereference it), but also you will get back the context that really backs
that data structure. FltSetXxxContext will give you that one back, but it
will reference it for you first. Similar logic holds if you are asking to
replace a context.
The most confusing calls for some people are the FltDeleteXXX and
FltReleaseXXX calls. The former detaches the data structure from the
context and deferences it (it may well drop your reference as well - the
documentation infers that it does but I’ve not checked). The latter just
drops your reference on the structure. You will very very rarely need to
call the former.
There *should* be a useful windbg extension to help you with all this, but
it requires symbols which are not exported (I’m not sure which is the most
frustrating, not having a tool, or knowing that there is a tool but you
have been denied access to it). For the purposes of experiementation, it
appears that the reference count is the first ULONG in front of the context.