We make and sell a device that our users will sometimes want to connect to their computer in large quantities with multiple USB hubs. It is a USB composite device that has both human interface (HID) and mass storage (MSD) interfaces. Windows automatically mounts the file-system of each device until it runs out of letters at 'Z:'.
I can walk the device tree and get the device instance identifiers for the HID and USBSTOR interfaces using a combination of the PnP Configuration Manager and Device Installation functions. With the USB storage device path I can also get the disk number (i.e. \\.\PhysicalDrive1
).
The next step would be to mount these disks as need by cycling out drive letters as we communicate with the devices, or better yet, mount them in temporary directories on the C: drive. I'm having difficulties attempting to use DefineDosDevice for this task and cannot make headway with SetVolumeMountPoint since a device does not have a Volume GUID until it is mounted. That presents a chicken and egg problem.
If only our customers used unix!!!
Windows does not mount disks; it mounts volumes. However, the volume for a USBSTOR class device is not listed as a child node in the device tree. Therefore, you have to enumerate all volumes and and do a bunch of string manipulation and comparisons to match up STORAGE\VOLUME nodes with USBSTOR nodes.
All volume GUID values are enumerated with the FindFirstVolume set of functions. The leading "\.\" and trailing "\" characters can be stripped and the resulting string then passed to QueryDosDevice. This provides a device name.
Next, one must enumerate all volumes using GUID_DEVINTERFACE_VOLUME with SetupDiGetClassDevs and friends. Compare the device type and number of each volume to the USBSTOR device you are looking for using IOCTL_STORAGE_GET_DEVICE_NUMBER. Once those are matched, you can get the device name from the volume and compare that to the other list of device names to find the volume GUID.
Finally, the volume GUID can be successfully used with SetVolumeMountPoint.
Thanks to Gabe for his very helpful assistance in the comments to my question.
Get device type and number from device path:
STORAGE_DEVICE_NUMBER sdn;
HANDLE handle = CreateFile(devInterfaceDetail->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL);
DWORD len = 0;
DeviceIoControl(h, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof (sdn), &len, NULL);
Find the device name for the corresponding USBSTOR instance by iterating over all volume interfaces and comparing the disk number from the above snippet:
std::string deviceName;
HDEVINFO devInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
SP_DEVICE_INTERFACE_DATA devInterface = { 0 };
devInterface.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
for (int i = 0; SetupDiEnumDeviceInterfaces(devInfoSet, NULL, &GUID_DEVINTERFACE_VOLUME, i, &devInterface); ++i) {
SP_DEVINFO_DATA devInfoData = { 0 };
devInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
DWORD len;
SetupDiGetDeviceInterfaceDetail(devInfoSet, &devInterface, NULL, 0, &len, &devInfoData);
std::vector<char> buf(len);
SP_DEVICE_INTERFACE_DETAIL_DATA *devInterfaceDetail = (SP_DEVICE_INTERFACE_DETAIL_DATA *) &buf[0];
devInterfaceDetail->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(devInfoSet, &devInterface, devInterfaceDetail, len, NULL, &devInfoData)) {
if (DEVICE_NUMBER == this->getDeviceNumber(devInterfaceDetail->DevicePath)) {
std::vector<BYTE> buf(MAX_PATH + 1);
DWORD type, len;
if (SetupDiGetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, &type, &buf[0], buf.size(), &len)) {
deviceName.assign(buf.begin(), buf.begin() + len);
break;
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With