You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

已知DEVINST,如何获取复合WinUSB子设备的设备路径?

获取WinUSB设备路径的步骤(基于DEVINST)

刚好做过类似的需求!既然你已经通过cfgmgr32定位到了目标子设备的DEVINST,那获取WinUSB需要的设备路径其实可以通过Windows原生API一步步搞定,不用绕弯路,我给你拆解下具体步骤:

核心思路

WinUSB的设备路径本质是设备接口的符号链接,我们可以先通过DEVINST拿到设备的硬件ID,再基于WinUSB的接口GUID匹配出对应的符号链接路径;或者更直接地,用DEVINST筛选设备接口列表。

方法一:从DEVINST到硬件ID,再到设备路径

这是最通用的流程,适合大多数场景:

  • 第一步:获取设备的硬件ID
    调用CM_Get_Device_ID API,传入你的DEVINST编号,它会直接返回设备的硬件ID字符串(就是你示例路径里usb#vid_xxxx&pid_xxxx#...的那部分)。记得要分配足够大的缓冲区,系统定义了MAX_DEVICE_ID_LEN常量可以直接用。

  • 第二步:匹配WinUSB设备接口并获取路径

    1. 调用SetupDiGetClassDevs,指定参数为WinUSB的接口GUID(GUID_DEVINTERFACE_WINUSB,定义在winusb.h中),同时传入第一步拿到的硬件ID,这样可以直接过滤出目标设备的设备信息集合。
    2. SetupDiEnumDeviceInterfaces枚举这个集合里的设备接口,找到符合条件的那个(如果设备只有一个WinUSB接口,索引传0即可)。
    3. 最后调用SetupDiGetDeviceInterfaceDetail获取完整的设备路径——这就是你需要传给CreateFile的字符串。

方法二:直接通过DEVINST获取设备接口路径(更高效)

如果你不想先拿硬件ID,可以直接用CM_Get_Device_Interface_List API,传入WinUSB的GUID和你的DEVINST,它会直接返回该设备下所有WinUSB接口的路径列表,省去枚举步骤,效率更高。

代码示例(C++)

给你一段可参考的代码片段,实现方法一的逻辑:

#include <cfgmgr32.h>
#include <setupapi.h>
#include <winusb.h>
#include <wchar.h>

#pragma comment(lib, "cfgmgr32.lib")
#pragma comment(lib, "setupapi.lib")

BOOL GetWinUSBDevicePath(DEVINST devInst, WCHAR* devicePath, DWORD devicePathSize) {
    WCHAR hardwareId[MAX_DEVICE_ID_LEN] = {0};
    // 1. 获取设备硬件ID
    CONFIGRET cr = CM_Get_Device_ID(devInst, hardwareId, MAX_DEVICE_ID_LEN, 0);
    if (cr != CR_SUCCESS) {
        return FALSE;
    }

    // 2. 获取WinUSB设备接口信息集合
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_WINUSB, 
                                            hardwareId, 
                                            NULL, 
                                            DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
    if (hDevInfo == INVALID_HANDLE_VALUE) {
        return FALSE;
    }

    SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0};
    deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    // 3. 枚举设备接口
    BOOL found = SetupDiEnumDeviceInterfaces(hDevInfo, 
                                             NULL, 
                                             &GUID_DEVINTERFACE_WINUSB, 
                                             0, 
                                             &deviceInterfaceData);
    if (!found) {
        SetupDiDestroyDeviceInfoList(hDevInfo);
        return FALSE;
    }

    // 4. 获取设备接口详情所需的缓冲区大小
    DWORD requiredSize = 0;
    SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, NULL, 0, &requiredSize, NULL);
    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
        SetupDiDestroyDeviceInfoList(hDevInfo);
        return FALSE;
    }

    // 5. 分配缓冲区并获取设备路径
    PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, requiredSize);
    if (!pDetailData) {
        SetupDiDestroyDeviceInfoList(hDevInfo);
        return FALSE;
    }
    pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

    SP_DEVINFO_DATA devInfoData = {0};
    devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    found = SetupDiGetDeviceInterfaceDetail(hDevInfo, 
                                            &deviceInterfaceData, 
                                            pDetailData, 
                                            requiredSize, 
                                            NULL, 
                                            &devInfoData);
    if (found) {
        wcsncpy_s(devicePath, devicePathSize, pDetailData->DevicePath, _TRUNCATE);
    }

    // 清理资源
    LocalFree(pDetailData);
    SetupDiDestroyDeviceInfoList(hDevInfo);
    return found;
}

注意事项

  • 权限问题:确保你的程序以管理员身份运行,否则可能无法获取设备路径或打开设备。
  • 多接口处理:如果目标设备有多个WinUSB接口,你需要循环调用SetupDiEnumDeviceInterfaces(递增索引参数),找到你需要的那个接口对应的路径。
  • 自定义GUID:如果你的设备INF文件里指定了自定义的接口GUID,记得把代码中的GUID_DEVINTERFACE_WINUSB替换成这个自定义GUID。

内容的提问来源于stack exchange,提问作者shogged

火山引擎 最新活动