The Problem
Our company make specialized devices running Windows XP (Windows XPe, to be precise). One of the unbending legal requirements we face is that we must quickly detect when a fixed IDE drive is removed. Quickly as in within a few seconds.
The drives in question are IDE drives. They are also software-protected from writes with an EWF (Enhanced Write Filter) layer. The EWF layer sits under the file system, protecting the disk from writes. If you change or write something on an EWF-protected volume, the actual changes happen only in a memory layer (but the file system isn't aware of that).
The problem is that Windows itself doesn't seem to notice fixed drive removal. You can pull the drive out of the machine, and Windows Explorer will be happy to let you browse directories and even open files if they happen to still be cached in memory. And thanks to the EWF layer, I can even seem to write files to the missing drive.
I need a clean software-only solution. Ideally in C#/.Net 1.1, but I have no problem with using pinvoke or C++.
Things I can't do
- No, I can't retrofit thousands of devices with new hardware.
- No, we can't just super-glue drives in to meet legal requirements.
- No, a normal file write/read won't detect the situation, thanks to the EWF layer.
- No, we can't turn off the EWF layer.
- No, I can't ignore legal requirements, even if they are silly.
- No, I can't detect fixed drive removal the way I would for a USB or other removable drive. These are fixed drives.
- No, I can't use WMI (Windows Management Instrumentation). It isn't installed on our machines.
- No I can't use versions of .Net past 1.1. It won't fit on our small drives. (But if an easy solution exists in a higher version of .Net, I might be able to port it back to 1.1.)
Current awkward solution
I'm not happy with our current solution. I'm looking for something more elegant and efficient.
What I'm currently doing involves two threads.
Thread A polls the drive. It first creates a special file on the drive using Kernel32.dll:
Kernel32.CreateFile(
filename,
File_Access.GenericRead | File_Access.GenericWrite,
File_Share.Read | File_Share.Write,
IntPtr.Zero,
CreationDisposition.CreateAlways,
CreateFileFlagsAndAttributes.File_Attribute_Hidden | CreateFileFlagsAndAttributes.File_Attribute_System,
IntPtr.Zero);
Then it polls the drive by calling
Kernel32.FlushFileBuffers(fileHandle);
If the drive has been removed, then thread A will hang for a long time before returning an error code.
Thread B polls thread A.
If thread B sees that thread A has locked up (hasn't updated a special variable in a while), then thread B raises an event that the drive has been removed.
My current solution works, but I don't like it. If anyone knows a cleaner software-only solution, I would appreciate it.