如何以编程方式在 Windows 中安装驱动器?
Posted
技术标签:
【中文标题】如何以编程方式在 Windows 中安装驱动器?【英文标题】:How does one programmatically mount a drive in Windows? 【发布时间】:2011-04-16 19:51:39 【问题描述】:我们制造和销售一种设备,我们的用户有时希望通过多个 USB 集线器大量连接到他们的计算机。它是一种同时具有人机接口 (HID) 和大容量存储 (MSD) 接口的 USB 复合设备。 Windows 会自动挂载每个设备的文件系统,直到 'Z:' 处的字母用完为止。
我可以使用PnP Configuration Manager 和Device Installation 函数的组合遍历设备树并获取HID 和USBSTOR 接口的设备实例标识符。通过 USB 存储设备路径,我还可以获得磁盘号(即\\.\PhysicalDrive1
)。
下一步是根据需要通过在与设备通信时循环输出驱动器号来安装这些磁盘,或者更好的是,将它们安装在 C: 驱动器上的临时目录中。我在尝试使用DefineDosDevice 执行此任务时遇到困难,并且无法使用SetVolumeMountPoint 取得进展,因为设备在安装之前没有Volume GUID。这就提出了先有鸡还是先有蛋的问题。
如果我们的客户使用 unix 就好了!!!
【问题讨论】:
当您说“设备在挂载之前没有卷 GUID”时,您的意思是它没有,还是您不知道它是什么?FindFirstVolume
(msdn.microsoft.com/en-us/library/aa364425(VS.85).aspx) 应该让您枚举甚至未挂载的卷。
好的,我现在就试试看。
@Gabe 那么,如何将卷 GUID 与磁盘号和/或设备 ID 匹配?
你看过 QueryDosDevice (msdn.microsoft.com/en-us/library/aa365461(VS.85).aspx) 吗?我想也许一个完整的样本会有所帮助:msdn.microsoft.com/en-us/library/cc542456(VS.85).aspx
另见:***.com/questions/3003810/how-to-get-the-volume-guid
【参考方案1】:
Windows 不挂载磁盘;它安装卷。但是,USBSTOR 类设备的卷并未列为设备树中的子节点。因此,您必须枚举所有卷,并进行一系列字符串操作和比较,以将 STORAGE\VOLUME 节点与 USBSTOR 节点匹配。
使用FindFirstVolume 函数集枚举所有卷 GUID 值。可以去除前导“\.\”和尾随“\”字符,然后将生成的字符串传递给QueryDosDevice。这提供了一个设备名称。
接下来,必须使用 GUID_DEVINTERFACE_VOLUME 和SetupDiGetClassDevs 和朋友枚举所有卷。使用IOCTL_STORAGE_GET_DEVICE_NUMBER 将每个卷的设备类型和数量与您要查找的 USBSTOR 设备进行比较。匹配后,您可以从卷中获取设备名称并将其与其他设备名称列表进行比较以查找卷 GUID。
最后,卷 GUID 可以与SetVolumeMountPoint 一起成功使用。
感谢 Gabe 在 cmets 对我的问题提供的非常有帮助的帮助。
代码片段
从设备路径获取设备类型和编号:
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);
通过遍历所有卷接口并比较上述sn-p中的磁盘号,找到相应USBSTOR实例的设备名称:
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;
【讨论】:
【参考方案2】:在我看来你必须使用IOCTL_MOUNTMGR_CREATE_POINT
。不幸的是,大多数使用IOCTL_MOUNTMGR_XXX
的示例是为内核模式驱动程序编写的,但这不是必需的。可能我的old answer(使用IOCTL_MOUNTMGR_QUERY_POINTS
)和another one 可以帮助你做到这一点。另见http://msdn.microsoft.com/en-us/library/ff567603.aspx 和http://support.microsoft.com/kb/836662。
在更好地理解IOCTL_MOUNTMGR_CREATE_POINT
应该如何使用之后,您将能够解决SetVolumeMountPoint的问题。
【讨论】:
@Oleg 我发布了我自己的问题的答案,感谢@Gabe 在 cmets 的帮助。我从来没有见过挂载管理器的方法,我会看看它是否比几个设备枚举和字符串匹配更直接。 @Oleg 如果这浪费了您的时间,我很抱歉。在 2 天过去之前,Stack Overflow 不允许我回答我自己的答案。 @Judge Maygarden:有趣!我以前不知道这一点。 ***上确实有一些奇怪的东西。 :-) 顺便说一句,如果您有时间可以发布您使用的代码示例。我觉得你的问题很有趣。您是在最后将 USB 存储安装到文件夹还是驱动器上? @Oleg 会的。另外,我不接受我的回答,因为它不适用于 Windows XP。因此,我仍在尝试找到一种将 USBSTOR 设备节点与 STORAGE/VOLUME 设备节点相关联的方法,以便获取卷 GUID。 @Oleg 在 Windows 7 上,我使用我们的 VID/PID 找到每个 USB 设备的根节点,并遍历树以匹配 HID 和 USBSTOR 节点。然后我枚举卷并尝试将它们与 USBSTOR 匹配。接下来,每个匹配的卷都被挂载到一个目录,这样我们就不会遇到驱动器号不足的问题。以上是关于如何以编程方式在 Windows 中安装驱动器?的主要内容,如果未能解决你的问题,请参考以下文章
电脑成功安装好Android4.0模拟器后,如何在模拟器中安装软件?
以编程方式在 Android 设备中安装“Google Play 服务”