如何以编程方式在Windows中安装驱动器?

时间:2010-09-24 14:30:29

标签: winapi usb filesystems disk mount

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

我可以使用PnP Configuration ManagerDevice Installation函数的组合来遍历设备树并获取HID和USBSTOR接口的设备实例标识符。使用USB存储设备路径,我也可以获得磁盘编号(即\\.\PhysicalDrive1)。

下一步是根据需要通过在与设备通信时循环输出驱动器号来安装这些磁盘,或者更好的是,将它们安装在C:驱动器上的临时目录中。我在尝试使用DefineDosDevice执行此任务时遇到了困难,并且由于设备在安装之前没有SetVolumeMountPoint,因此无法与Volume GUID取得进展。这会产生鸡和蛋的问题。

如果只有我们的客户使用unix !!!

2 个答案:

答案 0 :(得分:8)

Windows无法装入磁盘;它装载量。但是,USBSTOR类设备的卷未在设备树中列为子节点。因此,您必须枚举所有卷并进行一系列字符串操作和比较,以使STORAGE \ VOLUME节点与USBSTOR节点相匹配。

使用FindFirstVolume函数集枚举所有卷GUID值。可以删除前导“\。\”和尾随“\”字符,然后将生成的字符串传递给QueryDosDevice。这提供了设备名称。

接下来,必须使用带有SetupDiGetClassDevs和朋友的GUID_DEVINTERFACE_VOLUME枚举所有卷。使用IOCTL_STORAGE_GET_DEVICE_NUMBER将设备类型和每个卷的编号与您要查找的USBSTOR设备进行比较。匹配后,您可以从卷中获取设备名称,并将其与其他设备名称列表进行比较,以查找卷GUID。

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

感谢Gabe在我的问题评论中提供的非常有用的帮助。


Code Snippets

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

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

通过迭代所有卷接口并比较上述代码段中的磁盘编号来查找相应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;
            }
        }
    }
}

答案 1 :(得分:0)

在我看来,你必须使用IOCTL_MOUNTMGR_CREATE_POINT。不幸的是,使用IOCTL_MOUNTMGR_XXX的大多数示例都是为内核模式驱动程序编写的,但并不是必需的。可能我的old answer(使用IOCTL_MOUNTMGR_QUERY_POINTS)和another one可以帮助您完成此操作。另请参阅http://msdn.microsoft.com/en-us/library/ff567603.aspxhttp://support.microsoft.com/kb/836662

可能是在更好地理解了IOCTL_MOUNTMGR_CREATE_POINT应该如何使用后,您将能够解决SetVolumeMountPoint方面的问题。