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

5

11

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.

The Win32_PnPSignedDriver class 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.

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 queries or some other method? Is there a better approach to solving this problem?

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).

Wolfenbarger answered 20/6, 2011 at 20:15 Comment(3)
It looks like I can get the location from the registry via HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB. I'll write up an answer once I verify it.Wolfenbarger
One would expect that, since the non-WMI API is named SetupDiGetDeviceRegistryProperty Pattypatulous
Looks like the LocationInformation in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB is not updated when the device is plugged into a different port eitherDeangelis
C
10

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.

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.

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.

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

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.

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.c file in the code:

/*

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.
*/
Cycloid answered 9/2, 2013 at 7:10 Comment(1)
I worked around the problem I had, but I'll definitely take a look at this. Thanks!Wolfenbarger
C
2

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

Coprology answered 1/7, 2011 at 16:39 Comment(4)
I am familiar with SetupDi, but was hoping for a WMI solution to avoid dealing with the DDK and PInvoke.Wolfenbarger
Is there a particular SetupDi interface that exposes this information of which you are aware?Wolfenbarger
I think you will need to call a few SetupDi API's to get this information. a. Enumerate the available devices for a particular Device class ( USB device class in your case). Enumerate using SetupDiGetClassDevs method. Then iterate through this collection using the SetupDiEnumDeviceInfo API and then for each of this device get the relevant device property by using SetupDiGetDeviceRegistryProperty API. The registry properties enum is available at pinvoke.net/default.aspx/Enums/SPDRP%20.htmlCoprology
The SPDRP value for location information is 0x0000000D and Device class GUID for USB Device class is 36FC9E60-C465-11CF-8056-444553540000Coprology
P
2

The "Location information" under device manager is the exact same string you've gotten through 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_PnPDevice object instances for just those that are currently plugged in, and I think you'll find the current location information.

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/3105 for instructions to view these disconnected devices. Or run the following from an elevated administrator command prompt:

C:\Windows\system32>set devmgr_show_nonpresent_devices=1
C:\Windows\system32>devmgmt
Pattypatulous answered 1/7, 2011 at 16:48 Comment(3)
New instances of Win32_PnPSignedDriver are not created when I use a different USB port. It loads the same driver and does not update the location.Wolfenbarger
Interesting topic. @Judge: Could your comment above be caused by the USB ports residing on the same USB hub? I am very out of my element here, but I find the topic very interesting.Scaphoid
@Judge: Win32_PnPSignedDriver won't help you anyway, since there can be many device instances using the same driver.Pattypatulous
A
0

REF: "The Win32_PnPSignedDriver class 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."

It does for me. However, just be sure to refresh (F5) the regedit app between port swaps or you won't see the change.

Here are some examples:

Port2 Hub2
Port2 Hub4
Port3 Hub4

Arvind answered 31/8, 2020 at 10:30 Comment(1)
Display images instead of hyperlinks.Smutchy
D
-2

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

Dafna answered 27/6, 2011 at 6:10 Comment(4)
First, how do I get the "Unique serial number?" Second, I don't think that will work in this case. The device won't necessarily retain the same serial number.Wolfenbarger
I apologize if the comment came across as rude. I was typing it in a hurry as I'm sure you must have done as well. The device has a serial number, but the VID, PID and serial number will change and I need to track the physical device when this happens.Wolfenbarger
In retrospect, I don't think my comment was rude at all. I still don't know how to retrieve the USB serial number from a device. It is a valid question. Yes, all USB devices have them, but I don't know of a trivial way to retrieve it in Windows.Wolfenbarger
@Judge: If you do decide to use a serial number, try this. But if your re-enumeration (firmware update?) changes the serial number along with the VID/PID then that won't help.Pattypatulous

© 2022 - 2024 — McMap. All rights reserved.