How does one programmatically mount a drive in Windows?

假装没事ソ 提交于 2019-11-30 07:36:17
Judge Maygarden

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.


Code Snippets

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;
            }
        }
    }
}
Oleg

It seems to me that you have to use IOCTL_MOUNTMGR_CREATE_POINT. Unfortunately the most example used IOCTL_MOUNTMGR_XXX are written for kernel mode drivers, but it is not required. Probably my old answer (which use IOCTL_MOUNTMGR_QUERY_POINTS) and another one can help you to do this. See also http://msdn.microsoft.com/en-us/library/ff567603.aspx and http://support.microsoft.com/kb/836662.

It can be that after better understanding how IOCTL_MOUNTMGR_CREATE_POINT should be used you will be able to solve the problem with respect of SetVolumeMountPoint.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!