能否以编程方式为 Windows 中的设备识别物理 USB 端口?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6416931/
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-09-15 17:07:45  来源:igfitidea点击:

Can the physical USB port be identified programmatically for a device in Windows?

c#windowsusbwmiwmi-query

提问by Judge Maygarden

I have a USB device that enumerates with a different interface, VID, PID and serial number when commanded to do so, and I'd like to keep track of the physical device after this change occurs. My thought was to track it by its hub and port location.

我有一个 USB 设备,它在收到命令时使用不同的接口、VID、PID 和序列号进行枚举,我想在发生此更改后跟踪物理设备。我的想法是通过其枢纽和港口位置对其进行跟踪。

The Win32_PnPSignedDriverclass has a "Location" field that seemed perfect (e.g. Port_#0001.Hub_#0010), but it only contains the location of the device when the driver was first loaded. Plugging the hardware into a different port does not update that field.

Win32_PnPSignedDriver类有一个“位置”栏,似乎是完美的(例如Port_#0001.Hub_#0010),但它仅包含设备的位置是第一次加载驱动程序时。将硬件插入不同的端口不会更新该字段。

However, the information is available somewhere because there is a "Location information" field under the "Details" tab when viewing the device via the Device Manager. Can this information be retrieve through WMI queriesor some other method? Is there a better approach to solving this problem?

但是,该信息在某处可用,因为当通过设备管理器查看设备时,“详细信息”选项卡下有一个“位置信息”字段。是否可以通过WMI 查询或某种其他方法检索此信息?有没有更好的方法来解决这个问题?

EDIT:I know this sounds like a strange scenario. The microcontroller in these devices contains a ROM that enumerates as a CDC device (i.e. serial port) and allows programming. During manufacturing, it would be beneficial to track a device as it changes between the manufacturer's ROM (unique VID/PID/serial number) and my custom firmware interface (different VID/PID/serial number).

编辑:我知道这听起来像是一个奇怪的场景。这些设备中的微控制器包含一个 ROM,可枚举为 CDC 设备(即串行端口)并允许编程。在制造过程中,当设备在制造商的 ROM(唯一 VID/PID/序列号)和我的自定义固件接口(不同 VID/PID/序列号)之间发生变化时,跟踪设备将是有益的。

采纳答案by Judge Maygarden

As best as I can tell, correlating a USB device with a physical port is not possible in Windows. Please feel free to prove me wrong.

据我所知,在 Windows 中不可能将 USB 设备与物理端口相关联。请随时证明我是错的。

回答by bbyam

I know it's been awhile since any activity on this answer, but I am working on a project that requires a similar functionality to this as well, and I can tell you it is indeed possible. As far as I can tell, it does require the DDK and PInvoke, there's no C# or WMI interface for this information. It requires opening the low-level USB root hub devices and directly sending driver IOCTL commands to them.

我知道这个答案的任何活动已经有一段时间了,但我正在从事一个项目,它也需要与此类似的功能,我可以告诉你这确实是可能的。据我所知,它确实需要 DDK,并且PInvoke没有用于此信息的 C# 或 WMI 接口。它需要打开低级 USB 根集线器设备,并直接向它们发送驱动程序 IOCTL 命令。

The good news is, Microsoft provides an example C++ application that completely enumerates all USB devices and shows exactly which ports they are connected to. That application is the USBView sample application.

好消息是,Microsoft 提供了一个示例 C++ 应用程序,它完全枚举了所有 USB 设备并准确显示它们连接到哪些端口。该应用程序是USBView 示例应用程序

I think you will find if you compile and run this application, you'll see that it shows you exactly where your device is plugged in, and if you plug any device into that port, it shows up in the same place. Perhaps it might be easier if you create an unmanaged C++ DLL that provides a few calls your C# application can use to get the information it needs.

我想你会发现如果你编译并运行这个应用程序,你会看到它准确地显示了你的设备插入的位置,如果你将任何设备插入该端口,它会显示在同一个位置。如果您创建一个非托管 C++ DLL 来提供一些调用,您的 C# 应用程序可以用来获取它需要的信息,那么这可能会更容易。

It has this to say about the EnumerateHubPorts()function in its code:

关于EnumerateHubPorts()代码中的函数,它是这样说的:

Given an handle to an open hub and the number of downstream ports on the hub, send the hub an IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX request for each downstream port of the hub to get info about the device (if any) attached to each port.

给定一个开放集线器的句柄和集线器上下游端口的数量,为集线器的每个下游端口发送 IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX 请求以获取有关连接到每个端口的设备(如果有)的信息。

To give an idea about everything this requires (everything must be enumerated starting at the top, even if you're only interested in one port), here are the comments listed at the top of the enum.cfile in the code:

要了解这需要的所有内容(所有内容都必须从顶部开始枚举,即使您只对一个端口感兴趣),以下是enum.c代码中文件顶部列出的注释:

/*

This source file contains the routines which enumerate the USB bus
and populate the TreeView control.

The enumeration process goes like this:

(1) Enumerate Host Controllers and Root Hubs
EnumerateHostControllers()
EnumerateHostController()
Host controllers currently have symbolic link names of the form HCDx,
where x starts at 0.  Use CreateFile() to open each host controller
symbolic link.  Create a node in the TreeView to represent each host
controller.

GetRootHubName()
After a host controller has been opened, send the host controller an
IOCTL_USB_GET_ROOT_HUB_NAME request to get the symbolic link name of
the root hub that is part of the host controller.

(2) Enumerate Hubs (Root Hubs and External Hubs)
EnumerateHub()
Given the name of a hub, use CreateFile() to map the hub.  Send the
hub an IOCTL_USB_GET_NODE_INFORMATION request to get info about the
hub, such as the number of downstream ports.  Create a node in the
TreeView to represent each hub.

(3) Enumerate Downstream Ports
EnumerateHubPorts()
Given an handle to an open hub and the number of downstream ports on
the hub, send the hub an IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX
request for each downstream port of the hub to get info about the
device (if any) attached to each port.  If there is a device attached
to a port, send the hub an IOCTL_USB_GET_NODE_CONNECTION_NAME request
to get the symbolic link name of the hub attached to the downstream
port.  If there is a hub attached to the downstream port, recurse to
step (2).  

GetAllStringDescriptors()
GetConfigDescriptor()
Create a node in the TreeView to represent each hub port
and attached device.
*/

回答by Avinash Agarwal

Did you try SetupDi? You can use the SetupDi class of API function to get the information from DeviceManager.

你试过 SetupDi 吗?您可以使用API​​ 函数的SetupDi 类从DeviceManager 中获取信息。

回答by Ben Voigt

The "Location information" under device manager is the exact same string you've gotten through WMI.

设备管理器下的“位置信息”与您通过 WMI 获得的字符串完全相同。

Have you considered that when the device is plugged into a different port, instead of updating the metadata with the new location, Windows creates a new driver instance and new metadata. Try filtering the Win32_PnPDeviceobject instances for just those that are currently plugged in, and I think you'll find the current location information.

您是否考虑过当设备插入不同的端口时,Windows 将创建一个新的驱动程序实例和新的元数据,而不是使用新位置更新元数据。尝试过滤Win32_PnPDevice当前插入的对象实例,我想你会找到当前的位置信息。

For example, if I move my USB mouse to a different port, there's a copy of the mouse associated with the old port still listed under Device Manager, it's just hidden by default. See http://oreilly.com/pub/h/3105for instructions to view these disconnected devices. Or run the following from an elevated administrator command prompt:

例如,如果我将 USB 鼠标移动到不同的端口,则设备管理器下仍会列出与旧端口关联的鼠标副本,默认情况下它只是隐藏的。有关查看这些断开连接的设备的说明,请参阅http://oreilly.com/pub/h/3105。或者从提升的管理员命令提示符运行以下命令:

C:\Windows\system32>set devmgr_show_nonpresent_devices=1
C:\Windows\system32>devmgmt

回答by Alphaneo

A better Idea will be to use the Unique serial number of the USB device.

更好的想法是使用 USB 设备的唯一序列号。