如何在Windows中以编程方式安装驱动器? [英] How does one programmatically mount a drive in Windows?

查看:216
本文介绍了如何在Windows中以编程方式安装驱动器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们制造和销售一个设备,我们的用户有时会希望通过多个USB集线器大量连接到他们的电脑。这是一个兼容人机界面(HID)和海量存储(MSD)接口的USB复合设备。 Windows会自动挂载每个设备的文件系统,直到在Z:处用完字母。

我可以走设备树并获取设备实例标识符HID和USBSTOR接口使用 PnP配置管理器设备安装功能。使用USB存储设备路径,我也可以获得磁盘编号(例如 \\\\PhysicalDrive1 )。

下一步就是在我们与设备进行通信时,通过驱动器盘符来装载这些磁盘,或者更好的方式是将它们挂载到C:驱动器上的临时目录中。尝试使用 DefineDosDevice 时遇到困难对于此任务,无法使用 SetVolumeMountPoint 由于设备没有卷GUID 直到它被安装。如果只有我们的客户使用unix !!!

解决方案

Windows不安装磁盘;它装入卷。但是,USBSTOR类设备的音量在设备树中没有列为子节点。因此,您必须枚举所有的卷,然后执行一些字符串操作和比较,以便将STORAGE \VOLUME节点与USBSTOR节点进行匹配。

所有卷GUID值均为枚举与 FindFirstVolume 功能集。前导的\\\\和尾随的\字符可以被剥离,然后将结果字符串传递给 QueryDosDevice 。这提供了一个设备名称。



接下来,我们必须使用GUID_DEVINTERFACE_VOLUME和 SetupDiGetClassDevs 和朋友。使用 IOCTL_STORAGE_GET_DEVICE_NUMBER 。一旦匹配,您可以从卷中获取设备名称,并将其与设备名称的其他列表进行比较,以查找卷GUID。

最后,卷GUID可成功与 SetVolumeMountPoint 一起使用。



感谢 Gabe 对我的评论非常有帮助问题。






代码片段



获取设备类型和编号从设备路径:

  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);

通过迭代所有卷接口并将磁盘编号与上面的代码片段:

  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); (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); (DeviceDiGetDeviceInterfaceDetail(devInfoSet,& devInterface,devInterfaceDetail,len,NULL,& devInfoData)){
if(DEVICE_NUMBER == this-> getDeviceNumber(devInterfaceDetail-> DevicePath)){
std :: vector< BYTE> buf(MAX_PATH + 1);
DWORD类型,len; (SetupDiGetDeviceRegistryProperty(devInfoSet,& devInfoData,SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,& type,& buf [0],buf.size(),& len)){
deviceName.assign(buf.begin (),buf.begin()+ len);
break;
}
}
}
}


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.


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

这篇关于如何在Windows中以编程方式安装驱动器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆