Hello,
In the DDK documentation for FltAttachVolume and FltDetachVolume, the parameter InstanceName is described as a pointer to a UNICODE_STRING containing an instance name. In the case of FltAttachVolume, the documentation impliess that it is the name of the instance to use for retrieving the characteristics of the attachment (altitude, flags, …). In the case of FltDetachVolume, the documentation says that it contains the name of the instance to remove. In both cases, it is optional and can be NULL. For FltAttachVolume, a NULL value causes the routine to look in the instance associated with the DefaultInstance value in the filter’s service entry in the registry. For FltDetachVolume, a NULL value should remove the highest level (altitude?) instance.
The behavior I have observed in Windows XP SP3 is as follows:
When InstanceName is NULL for FltAttachVolume, the call succeeds. If it is a pointer to UNICODE_STRING containing the filter’s default instance name, the call returns the error 0xC0000034 (STATUS_OBJECT_NAME_NOT_FOUND in ntstatus.h).
When InstanceName is NULL for FltDetachVolume, the call results in an access violation and the stack trace contains:
STACK_TEXT:
f643aaa0 f84d190a 820fccb8 820faa14 00000000 fltMgr!FltGetVolumeInstanceFromName+0x34
f643aabc f84d1993 820fccb8 820fa9c8 00000000 fltMgr!FltpCommonDetachVolume+0x18
f643aad8 f8a9c072 820fccb8 820fa9c8 00000000 fltMgr!FltDetachVolume+0x17
f643aaf4 f8a9be9c 00c9fee8 0eea1a07 81f03448 bkupfilter!VolumeDetachMessage+0x22 <- my code calls FltDetachVolume here
f643ab44 f8a9bccc f8a9fb60 00c9fee8 00000018 bkupfilter!ProcessMessage+0x1bc
f643ab68 f84cb03d 00000000 00c9fee8 00000018 bkupfilter!ClosedPortMessage+0x3c f643ab94 f84d59ac 823669c8 00c9fee8 00000018 fltMgr!FltpFilterMessage+0x45
…
Has anyone successfully used these APIs in XP or in any other Windows flavor?
Thanks in advance,
David
Actually there is a sample in the WDK, the MetadataManager (\src\filesys\miniFilter\MetadataManager) that calls FltDetachVolume with a NULL instance name. I have to say I haven’t actually tried your scenario, but perhaps you could give it a go in your environment and post your findings ?
Thanks,
Alex.
I’d do what Alex suggests. Looking at the XPSP3 Filter Manager code, I don’t see any reason for FltGetVolumeInstanceFromName to crash if InstanceName is NULL.
–
Christian [MSFT]
This posting is provided “AS IS” with no warranties, and confers no rights.
I didn’t find the call in MetadataManager because my grep search was for FltAttachVolume which that sample doesn’t use. I wonder how the volume got attached in the first place.
In any event, here is my code. First the ‘volume attach’ logic:
NTSTATUS VolumeAttachMessage (
__in bkupcmd_t *cmdBlk)
{
NTSTATUS status;
UNICODE_STRING volName;
PFLT_VOLUME volObject;
PFLT_INSTANCE volInstance;
/* Use the name to get a pointer to the volume object */
RtlInitUnicodeString (&volName,cmdBlk->volName);
status = FltGetVolumeFromName (gFilter,&volName,&volObject);
if (ERR_STATUS) {
DBPRINT (DBERRS,“GetVolFromName returns %08X”,status);
return (status);
}
/* Attach to the volume object. If successful, pass the volume instance
pointer back to the caller as an integer (I know this is 32-bit only, in the
real code it is done slightly differently. */
status = FltAttachVolume (gFilter,volObject,NULL,&volInstance);
FltObjectDereference (volObject);
if (OK_STATUS) {
DBPRINT (DBINFO,“Attach instance: %08X”,volInstance);
cmdBlk->volumeID = (int)volInstance;
FltObjectDereference (volInstance);
}
else {
DBPRINT (DBERRS,“FltAttachVolume returns %08X”,status);
cmdBlk->volumeID = 0;
}
return (status);
}
This code always works when the InstanceName parameter is NULL and never works when it isn’t (returns 0xC0000034). The value I tried was the name of the default instance subkey of the Instances key in the registry.
Now the ‘volume detach’ logic:
NTSTATUS VolumeDetachMessage (
__in bkupcmd_t *cmdBlk)
{
NTSTATUS status;
union {
int volumeID;
PFLT_VOLUME volumePtr;
} vol;
vol.volumeID = cmdBlk->volumeID;
status = FltDetachVolume (gFilter,vol.volumePtr,NULL);
if (OK_STATUS) {
DBPRINT (DBINFO,“Volume detached”);
}
else {
DBPRINT (DBINFO,“FltDetachVolume returns: %08X”,status);
}
return (status);
}
This call to FltDetachVolume always generates the access violation that I described in my initial post. As far as I can see, this logic is identical to the examples in the MetadataManger sample. I have verified with WinDbg that the vol.volumePtr argument contains the correct value - i.e. the PFLT_VOLUME returned by FltAttachVolume.
Quick update.
I have determined that the reason that the FltAttachVolume failed when I supplied an InstanceName rather than NULL was because I had erroneously included the terminating null character in the value that I read from the registry. After correcting this problem, the attach works as described with a non-NULL instance name.
Alas, the FltDetachVolume still consistently fails whether I use NULL or the now-corrected InstanceName.
If I’m reading this right, you call FltAttachVolume (gFilter,volObject,NULL,&volInstance); which returns the instance pointer (PFLT_INSTANCE) in volInstance. You then save the instance by cmdBlk->volumeID = (int)volInstance and after that you dereference the instance. This is a bad idea in general (never store a referenced pointer without taking a reference). In this case if the instance is detached then cmdBlk->volumeID could be freed and you’ll still have a pointer to it.
Anyway, you have cmdBlk->volumeID set to the PFLT_INSTANCE.
In the detach function you read the PFLT_INSTANCE you got before (i guess, though it’s possible that you converted the cmdBlk->volumeID to something else in some other piece of code you didn’t paste) by issuing vol.volumeID = cmdBlk->volumeID; and then you call FltDetachVolume(gFilter,vol.volumePtr,NULL); with it which is to say that you call FltDetachVolume passing in an PFLT_INSTANCE pointer instead of the expected PFLT_VOLUME pointer.
Thanks,
Alex.
I apologize to all. I misread the documentation and confused the PFLT_INSTANCE returned by FltAttachVolume with the PFLT_VOLUME required by FltDetachVolume. I see now that for the detach API I need to start with a volume name, map it to a PFLT_VOLUME object, use that for the detach and then finally de-reference it.
Once again, never mind.
No worries, it happens.
However, may i ask why do you convert the pointer to an int and then back ? If it wasn’t for that the compiler would have detected this.
Thanks,
Alex.
When I was laboring under the delusion that the PFLT_INSTANCE returned by FltAttachVolume was the value that I needed in FltDetachVolume, I wanted to pass it back to the caller at user-level so it could be saved and used it later for the detach. I didn’t want to force the caller to include kernel level header files so I passed it back as an int (an int64 on 64-bit platforms).
I’ll try to pay a little more attention to the documentation in the future but you have to admit that working with MSDN is not a joy. You spend so much time flitting back and forth between the pages that oversights like this one are easy to make - especially when you are working in an area (filter drivers) that you are not that familiar with.
Once again, thanks for the patience.
David