C++ 如何在 Windows 上获取插入的 USB 设备的供应商 ID 和产品 ID

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2935184/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:33:03  来源:igfitidea点击:

how to get vendor id and product id of a plugged usb device on windows

c++windowsqtwinapiusb

提问by user198725878

I am using Qt on windows platform.

我在 windows 平台上使用 Qt。

i want to get and display vendor id and product id of a plugged usb device from my local system.

我想从本地系统获取并显示插入的 USB 设备的供应商 ID 和产品 ID。

Below is my full source code to get the vendor id and product id from the usb device.

下面是我从 USB 设备获取供应商 ID 和产品 ID 的完整源代码。

when i run the my qt application it does not throw me any errors .

当我运行我的 qt 应用程序时,它不会给我任何错误。

so i plug the usb device into the system.

所以我将USB设备插入系统。

but my print statement displays the result as below

但我的打印语句显示的结果如下

qDebug ()<<pDetData->DevicePath;

qDebug ()<<pDetData->DevicePath;

i get the result as 0x4

我得到的结果为 0x4

Whether i have any implementation mistakes in my source code ?

我的源代码中是否有任何实现错误?

if so please guide me what i am doing wrong..

如果是这样,请指导我我做错了什么..

Have i missed out any other functions ?

我错过了任何其他功能吗?

Is it possible to get the vendor id and product id from the usb device based on my source code .( my implementation of the code ) ?

是否可以根据我的源代码从 USB 设备获取供应商 ID 和产品 ID。(我的代码实现)?

kindly find my source code below

请在下面找到我的源代码

static GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10L, 0x6530, 0x11D2, 
    { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };

HANDLE hInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE,NULL,NULL,
    DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);

if ( hInfo == INVALID_HANDLE_VALUE )    
{    
    qDebug ()<<"invalid";   
}    
else    
{        
    qDebug ()<<"valid handle";    

    SP_DEVINFO_DATA DeviceInfoData;
    DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

    SP_INTERFACE_DEVICE_DATA Interface_Info;    
    Interface_Info.cbSize = sizeof(Interface_Info);

    BYTE Buf[1024];
    DWORD i;
    DWORD InterfaceNumber= 0;

    PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = 
        (PSP_DEVICE_INTERFACE_DETAIL_DATA) Buf;

    for (i=0;SetupDiEnumDeviceInfo(hInfo,i,&DeviceInfoData);i++)
    {
        DWORD DataT;
        LPTSTR buffer = NULL;
        DWORD buffersize = 0;

        while (!SetupDiGetDeviceRegistryProperty( hInfo,
            &DeviceInfoData,
            SPDRP_DEVICEDESC,
            &DataT,
            (PBYTE)buffer,
            buffersize,
            &buffersize))    
         {
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
            {
                // Change the buffer size.
                if (buffer) LocalFree(buffer);
                buffer = (LPTSTR)LocalAlloc(LPTR,buffersize);
            }
            else
            {
                // Insert error handling here.
                break;
            }

            qDebug ()<<(TEXT("Device Number %i is: %s\n"),i, buffer);

            if (buffer) LocalFree(buffer);

            if ( GetLastError() != NO_ERROR 
                     && GetLastError() != ERROR_NO_MORE_ITEMS )    
            {
                // Insert error handling here.
                qDebug ()<<"return false";
            }

            InterfaceNumber = 0; // this just returns the first one, you can iterate on this

            if (SetupDiEnumDeviceInterfaces(hInfo,
                                   NULL, 
                                   &GUID_DEVINTERFACE_USB_DEVICE,
                                   InterfaceNumber,
                                   &Interface_Info))
            {
                printf("Got interface");
                DWORD needed;
                pspdidd->cbSize = sizeof(*pspdidd);    
                SP_DEVICE_INTERFACE_DETAIL_DATA *pDetData = NULL;
                DWORD dwDetDataSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) 
                                      + 256;

                SetupDiGetDeviceInterfaceDetail(hInfo, 
                    &Interface_Info, pDetData,dwDetDataSize, NULL,
                    &DeviceInfoData);

                qDebug ()<<pDetData->DevicePath;
                //qDebug ()<<QString::fromWCharArray(pDetData->DevicePath);
            }
            else
            {    
                printf("\nNo interface");

                //ErrorExit((LPTSTR) "SetupDiEnumDeviceInterfaces");

                if ( GetLastError() == ERROR_NO_MORE_ITEMS) 
                    printf(", since there are no more items found.");
                else 
                    printf(", unknown reason.");

            }
            // Cleanup

            SetupDiDestroyDeviceInfoList(hInfo);
            qDebug ()<<"return true";
        }
    }
}

--------------- Edited to add: -----------------

--------------- 编辑添加:-----------------

Hi... the application comes and prints this

嗨...应用程序来打印这个

\?\usb#vid_04f2&pid_0111#5&1ba5a77f&0&2#{a5dcbf1 0-6530-11d2-901f-00c04fb951ed}

\?\usb#vid_04f2&pid_0111#5&1ba5a77f&0&2#{a5dcbf1 0-6530-11d2-901f-00c04fb951ed}

again it goes to while loop .... here it gets breaked in the else statement...

它再次进入 while 循环......在这里它在 else 语句中被打破......

Qt Code:

Qt代码:

if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 
    // Change the buffer size. 
    if (buffer) LocalFree(buffer); 
    buffer = (LPTSTR)LocalAlloc(LPTR,buffersize); 
} else { 
    qDebug ()<<"Here it quits the application"; 
    // Insert error handling here. break; 
} 

Any ideas in this....

这方面的任何想法......

回答by egrunin

After this line:

在这一行之后:

SP_DEVICE_INTERFACE_DETAIL_DATA *pDetData = NULL;

Add this:

添加这个:

DWORD dwDetDataSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA) + 256;
pDetData = (_SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc (dwDetDataSize);
pDetData->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);

After this line:

在这一行之后:

qDebug ()<<pDetData->DevicePath;

Add this:

添加这个:

free(pDetData);

But eventually you're going to have to read the docs for SetupDiGetDeviceInterfaceDetail(). Do it, there are lots of functions that work like this, with pointers to variable-size structs.

但最终你将不得不阅读SetupDiGetDeviceInterfaceDetail(). 这样做,有很多函数都是这样工作的,带有指向可变大小结构的指针。

-------- Edited to add: --------

-------- 编辑添加: --------

You're really going about this the wrong way. I see you're following the advice you got here, and it's taken you down the wrong path. idVendorand idProductcan only be found in the USB_DEVICE_DESCRIPTOR(MSDN).

你真的走错了路。我看到你遵循了你在这里得到的建议,它把你带上了错误的道路。idVendor并且idProduct只能在USB_DEVICE_DESCRIPTOR( MSDN) 中找到。

It looks like you already know how to get the device handle (using CreateFile()). After that, you call WinUsb_Initialize()(MSDN). That gets you a WINUSB_INTERFACE_HANDLE.

看起来您已经知道如何获取设备句柄(使用CreateFile())。之后,你打电话WinUsb_Initialize()MSDN)。这会让你得到一个WINUSB_INTERFACE_HANDLE.

Once you have that handle, you want to call WinUsb_GetDescriptor()(MSDN), with the DescriptorTypeset to URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE. I can't test code now, but it will look something like this:

获得该句柄后,您想调用WinUsb_GetDescriptor()( MSDN),并将DescriptorType设置为URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE. 我现在无法测试代码,但它看起来像这样:

USB_DEVICE_DESCRIPTOR udd;
memset(&udd, 0, sizeof(udd));
ULONG LengthTransferred = 0;

WinUsb_GetDescriptor(
    winusb_interface_handle, // returned by WinUsbInitialize
    URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
    0,     // not sure if we need this
    0x409, // not sure if we need this
    &udd,
    sizeof(udd),
    &LengthTransferred);

After that, udd->idVendorand udd->idProductshould have what you want.

在此之后,udd->idVendorudd->idProduct应该有你想要的东西。

Microsoft used to supply sample code for all this in the DDK, and probably still does, but I don't have access to one.

Microsoft 过去曾在 DDK 中为所有这些提供示例代码,现在可能仍然这样做,但我没有访问权限。

---------- Edited to add: ----------

---------- 编辑添加: ----------

Daniel K writes that the code should really be:

Daniel K 写道,代码应该是:

USB_DEVICE_DESCRIPTOR udd;
memset(&udd, 0, sizeof(udd));
ULONG LengthTransferred = 0;

WinUsb_GetDescriptor(
    winusb_interface_handle,    // returned by WinUsbInitialize
    USB_DEVICE_DESCRIPTOR_TYPE, // Daniel K's suggestion
    0,
    0x409,     // asks for English
    &udd,
    sizeof(udd),
    &LengthTransferred);

See the comments for further details.

有关更多详细信息,请参阅评论。

回答by Daniel

An alternative is to obtain the hardwareID which includes the VID and PID.

另一种方法是获取包含 VID 和 PID 的硬件 ID。

Call SetupDiGetDeviceRegistryProperty with SPDRP_HARDWAREID like so:

使用 SPDRP_HARDWAREID 调用 SetupDiGetDeviceRegistryProperty,如下所示:

wchar_t *hardwareID;

// First get requiredLength
SetupDiGetDeviceRegistryProperty(deviceInfoList, &deviceInfoData, SPDRP_HARDWAREID, NULL, NULL, 0, &requiredLength);

hardwareID = (wchar_t*)(new char[requiredLength]());

// Second call to populate hardwareID
SetupDiGetDeviceRegistryProperty(deviceInfoList, &deviceInfoData, SPDRP_HARDWAREID, NULL, (PBYTE)hardwareID, requiredLength, NULL);

// Display the string
qDebug() << "hardwareID =" << QString::fromWCharArray(hardwareID);

This will give you a string like USB\ROOT_HUB20&VID1002&PID4396&REV0000which you can parse.

这将为您提供一个USB\ROOT_HUB20&VID1002&PID4396&REV0000可以解析的字符串。

*Note: not all devices will have a VID and PID, such as non-USB devices.

*注意:并非所有设备都有 VID 和 PID,例如非 USB 设备。

回答by Alienfluid

You are enumerating the device "interface". Interfaces do not have a VID or PID - device instances do. I am not sure whether you are enumerating the interfaces to narrow down the devices you are interested in, for because it's an error.

您正在枚举设备“接口”。接口没有 VID 或 PID - 设备实例有。我不确定您是否正在枚举接口以缩小您感兴趣的设备的范围,因为这是一个错误。

If you just enumerate the device instances, then you can call SetupDiGetDeviceProperty with DEVPKEY_Device_HardwareIds and then grep the resulting hardware id for the VID and PID.

如果您只是枚举设备实例,那么您可以使用 DEVPKEY_Device_HardwareIds 调用 SetupDiGetDeviceProperty,然后 grep 生成的 VID 和 PID 的硬件 ID。

If you are using the device interfaces on purpose, then you need to call SetupDiGetDeviceInterfaceDetail once with a NULL PSP_DEVICE_INTERFACE_DETAIL parameter and a valid requiredSize pointer to get the required size of memory to allocate, allocate that memory and then call the function again. In that call, the last parameter is a SP_DEVINFO_DATA structure, which once retrieved, you can use in the call to SetupDiGetDeviceProperty as I mentioned above.

如果您有意使用设备接口,那么您需要使用 NULL PSP_DEVICE_INTERFACE_DETAIL 参数和有效的 requiredSize 指针调用一次 SetupDiGetDeviceInterfaceDetail 以获得所需的内存大小来分配,分配该内存,然后再次调用该函数。在该调用中,最后一个参数是 SP_DEVINFO_DATA 结构,一旦检索到该结构,您就可以在调用 SetupDiGetDeviceProperty 时使用,如上所述。