【问题标题】:How to detect USB speed on Windows如何在 Windows 上检测 USB 速度
【发布时间】:2016-04-15 20:44:04
【问题描述】:

我使用 setup API 函数查找 USB 设备,然后使用 createfile 与其通信。即使用 SetupDiGetClassDevs、SetupDiEnumDeviceInterfaces、SetupDiGetDeviceInterfaceDetail 等。

我希望能够确定设备是以 USB2 速度还是 USB3 速度连接的,即。超速与否

如何通过 Windows API 做到这一点?

【问题讨论】:

    标签: c++ usb setupapi


    【解决方案1】:

    我想您将不得不尝试WinUSB 在链接中有一个检测 USB 速度的示例代码。如果你想要WinUSB的描述,你可以找到here

    【讨论】:

    • 与我通话的设备不是 WinUSB.sys 设备。难道没有更通用的方法来确定这一点吗?
    【解决方案2】:

    这就是我最终的结果。很复杂。不敢相信没有更简单的方法:

    #include "stdafx.h"
    
    #include <Windows.h>
    #include <Setupapi.h>
    #include <winusb.h>
    
    #undef LowSpeed
    #include <Usbioctl.h>
    
    #include <iostream>
    #include <string>
    #include <memory>
    #include <vector>
    
    class Usb_Device
    {
    private:
        std::wstring _driverKey;
        char _speed;
    
    public:
        Usb_Device(int adapterNumber, std::wstring devicePath, char speed);
    
        virtual char GetSpeed(std::wstring driverKey);
    };
    
    class Usb_Hub : public Usb_Device
    {
    private:
        bool _isRootHub;
        std::wstring _deviceDescription;
        std::wstring _devicePath;
    
        std::vector<std::unique_ptr<Usb_Device>> _devices;
    
    public:
        Usb_Hub(std::wstring devicePath, char speed);
    
        virtual char GetSpeed(std::wstring driverKey) override;
    };
    
    class Usb_Controller
    {
    private:
    
        GUID _interfaceClassGuid;
        std::wstring _devicePath;
        std::wstring _deviceDescription;
        std::wstring _driverKey;
    
        std::vector<std::unique_ptr<Usb_Device>> _devices;
    
    public:
        Usb_Controller();
    
        char GetSpeed(std::wstring driverKey);
    };
    
    static std::unique_ptr<Usb_Device> BuildDevice(int portCount, std::wstring devicePath)
    {
        std::unique_ptr<Usb_Device> ret;
    
        HANDLE handle = INVALID_HANDLE_VALUE;
    
        DWORD bytes = -1;
        DWORD bytesReturned = -1;
        BOOL isConnected = FALSE;
        char speed;
    
        // Open a handle to the Hub device
        handle = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
        if (handle != INVALID_HANDLE_VALUE)
        {
            bytes = sizeof(USB_NODE_CONNECTION_INFORMATION_EX);
            PUSB_NODE_CONNECTION_INFORMATION_EX nodeConnection = (PUSB_NODE_CONNECTION_INFORMATION_EX)(new char[bytes]);
    
            nodeConnection->ConnectionIndex = portCount;
    
            if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, nodeConnection, bytes, nodeConnection, bytes, &bytesReturned, 0))
            {
                isConnected = nodeConnection->ConnectionStatus == USB_CONNECTION_STATUS::DeviceConnected;
                speed = nodeConnection->Speed;
            }
    
            if (isConnected)
            {
                if (nodeConnection->DeviceDescriptor.bDeviceClass == 0x09 /*HubDevice*/)
                {
                    bytes = sizeof(USB_NODE_CONNECTION_NAME);
                    PUSB_NODE_CONNECTION_NAME nodeConnectionName = (PUSB_NODE_CONNECTION_NAME)(new char[bytes]);
                    nodeConnectionName->ConnectionIndex = portCount;
    
                    if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_NAME, nodeConnectionName, bytes, nodeConnectionName, bytes, &bytesReturned, 0))
                    {
                        bytes = nodeConnectionName->ActualLength;
                        delete[] nodeConnectionName;
    
                        nodeConnectionName = (PUSB_NODE_CONNECTION_NAME)(new char[bytes]);
                        nodeConnectionName->ConnectionIndex = portCount;
    
                        if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_NAME, nodeConnectionName, bytes, nodeConnectionName, bytes, &bytesReturned, 0))
                        {
                            std::wstring name = std::wstring(L"\\\\?\\") + std::wstring(nodeConnectionName->NodeName);
                            ret = std::unique_ptr<Usb_Device>(new Usb_Hub(name, speed));
                        }
                    }
    
                    delete[] nodeConnectionName;
                }
                else
                {
                    ret = std::unique_ptr<Usb_Device>(new Usb_Device(portCount, devicePath, speed));
                }
            }
            else
            {
                // Chuck this device
            }
    
            delete[] nodeConnection;
            CloseHandle(handle);
        }
    
        return ret;
    }
    
    Usb_Controller::Usb_Controller()
    {
        BOOL success = TRUE;
        for (int index = 0; success; index++)
        {
            GUID guid;
            HRESULT hr = CLSIDFromString(L"{3abf6f2d-71c4-462a-8a92-1e6861e6af27}", (LPCLSID)&guid);
    
            unsigned char* ptr = new unsigned char[2048]; // Should really do two calls, but that's more effort
    
            HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    
            // Create a device interface data structure
            SP_DEVICE_INTERFACE_DATA deviceInterfaceData = { 0 };
            deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    
            // Start the enumeration.
            success = SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, index, &deviceInterfaceData);
            if (success)
            {
                _interfaceClassGuid = deviceInterfaceData.InterfaceClassGuid;
    
                // Build a DevInfo data structure.
                SP_DEVINFO_DATA deviceInfoData = { 0 };
                deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    
                // Now we can get some more detailed informations.
                DWORD nRequiredSize = 0;
    
                SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterfaceData, 0, 0, &nRequiredSize, 0);
                if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
                {
                    PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[nRequiredSize]);
                    memset(deviceInterfaceDetailData, 0, nRequiredSize);
                    deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
    
                    if (SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterfaceData, deviceInterfaceDetailData, nRequiredSize, &nRequiredSize, &deviceInfoData))
                    {
                        _devicePath = deviceInterfaceDetailData->DevicePath;
    
                        // Get the device description and driver key name.
                        DWORD requiredSize = 0;
                        DWORD regType = REG_SZ;
    
                        if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInfoData, SPDRP_DEVICEDESC, &regType, ptr, 2048, &requiredSize))
                        {
                            _deviceDescription = reinterpret_cast<wchar_t*>(ptr);
                        }
    
                        if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInfoData, SPDRP_DRIVER, &regType, ptr, 2048, &requiredSize))
                        {
                            _driverKey = reinterpret_cast<wchar_t*>(ptr);
                        }
                    }
    
                    delete[] deviceInterfaceDetailData;
                }
    
                SetupDiDestroyDeviceInfoList(deviceInfoHandle);
    
                std::unique_ptr<Usb_Device> hub(new Usb_Hub(_devicePath, -1));
                _devices.push_back(std::move(hub));
            }
            else
            {
                success = false;
            }
    
            delete[] ptr;
        }
    }
    
    char Usb_Controller::GetSpeed(std::wstring driverKey)
    {
        char speed = -1;
    
        for (auto it = _devices.begin(); it != _devices.end() && speed == -1; ++it)
        {
            if (*it != nullptr)
            {
                speed = (*it)->GetSpeed(driverKey);
            }
        }
    
        return speed;
    }
    
    Usb_Hub::Usb_Hub(std::wstring devicePath, char speed) :
        Usb_Device(-1, devicePath, speed)
    {
        HANDLE handle1 = INVALID_HANDLE_VALUE;
        HANDLE handle2 = INVALID_HANDLE_VALUE;
        _deviceDescription = L"Standard-USB-Hub";
        _devicePath = devicePath;
    
        DWORD bytesReturned = -1;
        DWORD bytes = -1;
    
        BOOL success = TRUE;
    
        // Open a handle to the host controller.
        handle1 = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
        if (handle1 != INVALID_HANDLE_VALUE)
        {
            USB_ROOT_HUB_NAME rootHubName;
            memset(&rootHubName, 0, sizeof(USB_ROOT_HUB_NAME));
    
            // Get the root hub name.
            if (DeviceIoControl(handle1, IOCTL_USB_GET_ROOT_HUB_NAME, nullptr, 0, &rootHubName, sizeof(USB_ROOT_HUB_NAME), &bytesReturned, 0))
            {
                if (rootHubName.ActualLength > 0)
                {
                    PUSB_ROOT_HUB_NAME actualRootHubName = (PUSB_ROOT_HUB_NAME)(new char[rootHubName.ActualLength]);
    
                    if (DeviceIoControl(handle1, IOCTL_USB_GET_ROOT_HUB_NAME, nullptr, 0, actualRootHubName, rootHubName.ActualLength, &bytesReturned, 0))
                    {
                        _isRootHub = true;
                        _deviceDescription = L"RootHub";
                        _devicePath = std::wstring(L"\\\\?\\") + std::wstring(actualRootHubName->RootHubName);
                    }
    
                    delete[] actualRootHubName;
                }
            }
    
            // Now let's open the hub (based upon the hub name we got above).
            int PortCount = 0;
            handle2 = CreateFile(_devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
            if (handle2 != INVALID_HANDLE_VALUE)
            {
                bytes = sizeof(USB_NODE_INFORMATION);
                PUSB_NODE_INFORMATION nodeInfo = (PUSB_NODE_INFORMATION)(new char[bytes]);
                memset(nodeInfo, 0, sizeof(USB_NODE_INFORMATION));
    
                nodeInfo->NodeType = USB_HUB_NODE::UsbHub;
    
                // Get the hub information.
                if (DeviceIoControl(handle2, IOCTL_USB_GET_NODE_INFORMATION, nodeInfo, bytes, nodeInfo, bytes, &bytesReturned, 0))
                {
                    DWORD d = GetLastError();
    
                    PortCount = nodeInfo->u.HubInformation.HubDescriptor.bNumberOfPorts;
                }
    
                delete[] nodeInfo;
    
                CloseHandle(handle2);
            }
    
            CloseHandle(handle1);
    
            for (int index = 1; index <= PortCount; index++)
            {
                std::unique_ptr<Usb_Device> device = BuildDevice(index, _devicePath);
                _devices.push_back(std::move(device));
            }
        }
        else
        {
            success = FALSE;
        }
    }
    
    char Usb_Hub::GetSpeed(std::wstring driverKey)
    {
        char speed = Usb_Device::GetSpeed(driverKey);
    
        if (speed == -1)
        {
            for (auto it = _devices.begin(); it != _devices.end() && speed == -1; ++it)
            {
                if (*it != nullptr)
                {
                    speed = (*it)->GetSpeed(driverKey);
                }
            }
        }
    
        return speed;
    }
    
    Usb_Device::Usb_Device(int adapterNumber, std::wstring devicePath, char speed)
    {
        _speed = speed;
    
        HANDLE handle = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
        if (handle != INVALID_HANDLE_VALUE)
        {
            // Get the Driver Key Name (usefull in locating a device)
            DWORD bytesReturned = -1;
            DWORD bytes = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
            PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)(new char[bytes]);
    
            driverKey->ConnectionIndex = adapterNumber;
    
            // Use an IOCTL call to request the Driver Key Name
            if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, driverKey, bytes, driverKey, bytes, &bytesReturned, 0))
            {
                bytes = driverKey->ActualLength;
                delete[] driverKey;
    
                driverKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)(new char[bytes]);
                driverKey->ConnectionIndex = adapterNumber;
    
                if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, driverKey, bytes, driverKey, bytes, &bytesReturned, 0))
                {
                    _driverKey = driverKey->DriverKeyName;
                }
            }
    
            delete[] driverKey;
    
            CloseHandle(handle);
        }
    }
    
    char Usb_Device::GetSpeed(std::wstring driverKey)
    {
        return _speed;
    }
    
    int main()
    {
        Usb_Controller controller;
    
        GUID guid;
        HRESULT hr = CLSIDFromString(L"{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}", (LPCLSID)&guid);
    
        HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    
        if (deviceInfoHandle != INVALID_HANDLE_VALUE)
        {
            int deviceIndex = 0;
            while (true)
            {
                SP_DEVICE_INTERFACE_DATA deviceInterface = { 0 };
                deviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    
                if (SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, deviceIndex, &deviceInterface))
                {
                    DWORD cbRequired = 0;
    
                    SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, 0, 0, &cbRequired, 0);
                    if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
                    {
                        PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[cbRequired]);
                        memset(deviceInterfaceDetail, 0, cbRequired);
                        deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
    
                        if (!SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, deviceInterfaceDetail, cbRequired, &cbRequired, 0))
                        {
                            deviceIndex++;
                            continue;
                        }
    
                        // Initialize the structure before using it.
                        memset(deviceInterfaceDetail, 0, cbRequired);
                        deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
    
                        // Call the API a second time to retrieve the actual
                        // device path string.
                        BOOL status = SetupDiGetDeviceInterfaceDetail(
                            deviceInfoHandle,  // Handle to device information set
                            &deviceInterface,     // Pointer to current node in devinfo set
                            deviceInterfaceDetail,   // Pointer to buffer to receive device path
                            cbRequired,   // Length of user-allocated buffer
                            &cbRequired,  // Pointer to arg to receive required buffer length
                            NULL);        // Not interested in additional data
    
                        BOOL success = TRUE;
                        for (int i = 0; success; i++)
                        {
                            SP_DEVINFO_DATA deviceInterfaceData = { 0 };
                            deviceInterfaceData.cbSize = sizeof(SP_DEVINFO_DATA);
    
                            // Start the enumeration.
                            success = SetupDiEnumDeviceInfo(deviceInfoHandle, i, &deviceInterfaceData);
    
                            DWORD RequiredSize = 0;
                            DWORD regType = REG_SZ;
                            unsigned char* ptr = new unsigned char[2048];
                            if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInterfaceData, SPDRP_DRIVER, &regType, ptr, 2048, &RequiredSize))
                            {
                                char speed = controller.GetSpeed(reinterpret_cast<wchar_t*>(ptr));
                                std::wcout << std::wstring(reinterpret_cast<wchar_t*>(ptr)) << std::endl;
                                std::wcout << L"Speed: " << (int)speed << std::endl;
                            }
    
                            delete[] ptr;
                        }
    
                        auto hDeviceHandle = CreateFile(
                            deviceInterfaceDetail->DevicePath,
                            GENERIC_READ | GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_WRITE,
                            NULL,
                            OPEN_EXISTING,
                            FILE_FLAG_OVERLAPPED,
                            NULL);
    
                        CloseHandle(hDeviceHandle);
    
                        delete[] deviceInterfaceDetail;
                    }
                }
                else
                {
                    break;
                }
    
                ++deviceIndex;
            }
    
            SetupDiDestroyDeviceInfoList(deviceInfoHandle);
        }
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-20
      • 2012-02-28
      • 2015-11-30
      • 2014-10-15
      • 2013-09-06
      相关资源
      最近更新 更多