You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows系统下如何通过厂商ID和产品ID获取USB设备路径

仅通过Vendor ID和Product ID查找USB设备路径(SetupDi系列函数实现)

不需要额外的设备实例ID,仅用VID和PID就能通过SetupDi系列函数筛选目标USB设备,核心是通过读取设备的**硬件ID(Hardware ID)**进行匹配,以下是具体实现步骤和代码:

实现步骤

  1. 获取USB设备信息集:调用SetupDiGetClassDevs获取当前系统中所有已连接的USB设备接口集合,指定DIGCF_PRESENT(仅枚举已连接设备)和DIGCF_DEVICEINTERFACE(枚举设备接口而非设备实例)。
  2. 遍历设备接口:用SetupDiEnumDeviceInterfaces逐个枚举设备信息集中的设备接口。
  3. 匹配VID/PID:对每个设备接口,调用SetupDiGetDeviceRegistryProperty读取其硬件ID,解析硬件ID字符串(格式通常为USB\VID_XXXX&PID_YYYY&...),匹配目标VID和PID。
  4. 获取设备路径:匹配成功后,调用SetupDiGetDeviceInterfaceDetail获取可用于创建设备句柄的设备路径。

代码示例(C++)

#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include <usbiodef.h>
#include <iostream>
#include <vector>
#include <string>

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

bool FindUsbDevicePath(WORD targetVid, WORD targetPid, std::wstring& outDevicePath) {
    HDEVINFO deviceInfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (deviceInfoSet == INVALID_HANDLE_VALUE) {
        std::cerr << "SetupDiGetClassDevs failed, error: " << GetLastError() << std::endl;
        return false;
    }

    SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0};
    deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    for (DWORD i = 0; SetupDiEnumDeviceInterfaces(deviceInfoSet, nullptr, &GUID_DEVINTERFACE_USB_DEVICE, i, &deviceInterfaceData); i++) {
        // 先获取所需缓冲区大小
        DWORD requiredSize = 0;
        SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, nullptr, 0, &requiredSize, nullptr);
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
            std::cerr << "SetupDiGetDeviceInterfaceDetail (size check) failed, error: " << GetLastError() << std::endl;
            continue;
        }

        // 分配缓冲区
        std::vector<BYTE> detailBuffer(requiredSize);
        PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(detailBuffer.data());
        pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

        SP_DEVINFO_DATA devInfoData = {0};
        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

        if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, pDetailData, requiredSize, nullptr, &devInfoData)) {
            std::cerr << "SetupDiGetDeviceInterfaceDetail failed, error: " << GetLastError() << std::endl;
            continue;
        }

        // 读取硬件ID
        WCHAR hardwareIdBuffer[1024] = {0};
        if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, &devInfoData, SPDRP_HARDWAREID, nullptr, reinterpret_cast<PBYTE>(hardwareIdBuffer), sizeof(hardwareIdBuffer), nullptr)) {
            std::cerr << "SetupDiGetDeviceRegistryProperty failed, error: " << GetLastError() << std::endl;
            continue;
        }

        // 解析硬件ID,匹配VID/PID
        WCHAR* currentId = hardwareIdBuffer;
        while (*currentId != L'\0') {
            std::wstring idStr(currentId);
            // 查找VID和PID的位置
            size_t vidPos = idStr.find(L"VID_");
            size_t pidPos = idStr.find(L"PID_");
            if (vidPos != std::wstring::npos && pidPos != std::wstring::npos) {
                WORD vid = static_cast<WORD>(wcstoul(idStr.substr(vidPos + 4, 4).c_str(), nullptr, 16));
                WORD pid = static_cast<WORD>(wcstoul(idStr.substr(pidPos + 4, 4).c_str(), nullptr, 16));
                if (vid == targetVid && pid == targetPid) {
                    outDevicePath = pDetailData->DevicePath;
                    SetupDiDestroyDeviceInfoList(deviceInfoSet);
                    return true;
                }
            }
            currentId += wcslen(currentId) + 1;
        }
    }

    SetupDiDestroyDeviceInfoList(deviceInfoSet);
    return false;
}

int main() {
    WORD targetVid = 0x1234; // 替换为你的目标厂商ID
    WORD targetPid = 0x5678; // 替换为你的目标产品ID
    std::wstring devicePath;

    if (FindUsbDevicePath(targetVid, targetPid, devicePath)) {
        std::wcout << L"找到目标设备路径: " << devicePath << std::endl;
        // 后续可使用CreateFile打开设备句柄,发送控制码
        HANDLE hDevice = CreateFile(devicePath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
        if (hDevice != INVALID_HANDLE_VALUE) {
            // 这里可以发送IOCTL控制码
            CloseHandle(hDevice);
        }
    } else {
        std::cerr << "未找到目标设备" << std::endl;
    }

    return 0;
}

关键说明

  • GUID_DEVINTERFACE_USB_DEVICE:这是USB设备接口的类GUID,用于筛选所有USB设备接口,确保我们获取的是可直接打开的设备路径。
  • 硬件ID解析:每个设备的硬件ID是多个以NULL分隔的字符串,最后以双NULL结尾,需要逐个遍历检查是否包含匹配的VID和PID。
  • 错误处理:所有SetupDi系列函数调用后都要检查返回值,通过GetLastError()排查问题。
  • 设备路径使用:获取到的设备路径可直接传入CreateFile创建设备句柄,之后即可调用DeviceIoControl发送控制码。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:35:23