0

I'm currently working with an application that has branching logic depending on whether a specific USB drive is inserted into the system. It does this by polling all drive letters looking for a path on the root of each drive.

This works for the majority of machines, but often, this application runs on startup with the USB drive inserted. In addition, some machines are especially slow and take a good minute to load the USB drive once Windows boots. In these machines, the code reaches the check of whether this drive exists, it can't find the drive, and the wrong branch is executed.

It could be possible to wait a minute before checking for drives. I'd prefer to have the application wait for all USB devices (or simply only mass storage devices) to load before checking for the drives, or something even more intelligent.

Unfortunately, I am unfamiliar with the methods needed to wait for all USB devices to finish loading, and with the DDK in general. I can see that it's possible to register a window for device notifications with GUID_DEVINTERFACE_USB_DEVICE, possibly receiving messages like DBT_DEVICEARRIVAL, DBT_DEVNODES_CHANGED, and WM_DEVICECHANGE, the distinctions of which I do not know.

However, the USB drive will likely be already inserted and detected (but not having a drive letter) into the system before the program executes. So, registering for all device change notifications would not make sense. If it's possible to identify devices which are inserted but not loaded (possibly with SetupDiEnumDeviceInterfaces) and then register for "loaded" notifications on all of those devices, it might work. I don't have familiarity with any this, so pointers (or sample code) would be extremely helpful.

Community
  • 1
  • 1
Alyssa Haroldsen
  • 3,652
  • 1
  • 20
  • 35
  • *"I'd prefer to have the application wait for all USB devices"* - That'd require that you provide a concise specification for what *"all USB devices"* encompasses. Since USB devices can support hot-plugging, this is pretty hard to specify. Also, your 1:1 mapping between USB drives and drive letters is flawed. A USB device can have zero or more drive letters assigned. And drive letters are assigned per user. So dealing with drive letters in a service is fairly meaningless. (Assuming that you are writing a service, since you talk about boot-time initialization.) – IInspectable Jul 20 '16 at 10:37
  • @IInspectable: Actually, drive letters are a union of systemwide assignments (local disks) and per-session assignments (remote shares, using user credentials). The USB disk is local. But there's some minor magic IIRC to avoid picking a letter that's already in use for a remote share. – MSalters Jul 20 '16 at 11:24
  • @IInspectable Assume only "removable" volumes are enumerated, regardless of whether it has a drive letter. They still can't be accessed by Volume GUID. The drives also contain exactly one full-disk NTFS partition. – Alyssa Haroldsen Jul 20 '16 at 11:39
  • As I said, you need a **concise** specification. Repeating *"all"* doesn't explain much, as hot-plugging makes availability a function over time. – IInspectable Jul 20 '16 at 11:44
  • I'm asking for the API equivalent of detecting if the "Drive Software Installation" in the notification area is currently showing any currently loading devices, and to receive a notification when the devices currently listed there are available to use (which is when the drive letter appears), or if the devices are disconnected. I'm not sure of a precise (and concise) definition that would explain what I need. I want to know if there are USB mass storage devices attached but not finished loading, and to be notified when a volume might be available (or the drive is disconnected). – Alyssa Haroldsen Jul 20 '16 at 11:53
  • @Kupiakos: "contain exactly one full-disk NTFS partition" is not something that Windows will know up front. It will discover these things only in steps. In fact, I bet your drive won't contain a partition at all - USB drives usually aren't partitioned. It most likely just contains a single NTFS filesystem. Minor details, sure, but Windows has to deal with all such things. The NTFS driver needs to know whether to start at absolute 0, or at the first data block inside the first partition. And without a partition table, how does Windows even know it's an NTFS system? Trial and error, IIRC. – MSalters Jul 20 '16 at 11:57
  • @MSalters I'm saying I know for a fact that the drives that will be connected are guaranteed to have an MBR partition table with one full-disk NTFS-formatted partition. I'm not asking when Windows finds this out (although to be honest, I've never once seen a non-partitioned USB disk). I want to know when the drive will be fully available for its intended use and any associated volumes ready to be accessed. This is a controlled, specialized scenario. – Alyssa Haroldsen Jul 20 '16 at 12:05

2 Answers2

0

I don't think you can.

The problem is that you're tyring to distinguish two cases which are not actually distinct, that of plugging in a USB device during boot and plugging it in later.

You have to know that USB is a protocol which requires a non-trivial amount of intelligence in the USB slave devices. They exchange multiple messages with the USB host (i.e. your OS). This exchange isn't instant. For instance, your USB harddrive will need to ask for permission to draw more than 100mA power. To answer that, the power drivers of Windows must be up and running. The phsyical disk can only spin up when the answer arrives.

So, there's a whole message sequence going on, and the drive letter shows up only fairly late. Windows must know how many partitions exist. So during this exchange, new devices are being created all the time.

When you enumerate devices while devices are actively being added, you're really asking for troubles. The SetupDiEnumDeviceInterfaces API doesn't operate on a snapshot (which we know because there's no Close method); you're asking for the N'th device until you get an "no more devices" error an you know N was to big. But when devices are still actively being added, N changes. And I don't see a guarantee that the list order is by age; devices might be added in the middle as well.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • I suppose I'm asking for the API equivalent of detecting if the "Drive Software Installation" in the notification area is currently showing any currently loading devices, and to receive a notification when the devices currently listed there are available to use (which is when the drive letter appears). – Alyssa Haroldsen Jul 20 '16 at 11:55
0

I don't think that getting notifications about drivers being installed for newly plugged-in devices would help you much. When you plug in the same device repeatedly, the drivers are usually installed only the first time.

Also, an USB flash drive, although physically looks like one compact device, is represented by at least three PnP devices by Windows: an USB mass storage device (represents the USB endpoint), a disk device (represents the physical disk inside the flash drive) and one or multiple Volume devices (each represents one volume = partition in your case). Drive letters may be assigned to the Volume devices.

What you can possibly do is monitoring the arrival and removal of Volume devices (RegisterDeviceNotification for GUID_DEVINTERFACE_VOLUME) and examining each volume device that arrives (I believe that Setup API allows you to track its "parents" to the USB stack).

Martin Drab
  • 667
  • 4
  • 6