使用VID和PID识别连接到x64的USB设备的COM端口

如下我能够通过给定的pid和vid获得连接到32位win7OS机器的usb com端口名称,但是当在x64中运行时,它会卡在以下行中:

comports.Add((string)rk6.GetValue("PortName")); 

这是我的代码

 static List ComPortNames(String VID, String PID) { String pattern = String.Format("^VID_{0}.PID_{1}", VID, PID); Regex _rx = new Regex(pattern, RegexOptions.IgnoreCase); List comports = new List(); RegistryKey rk1 = Registry.LocalMachine; RegistryKey rk2 = rk1.OpenSubKey("SYSTEM\\CurrentControlSet\\Enum"); foreach (String s3 in rk2.GetSubKeyNames()) { RegistryKey rk3 = rk2.OpenSubKey(s3); foreach (String s in rk3.GetSubKeyNames()) { if (_rx.Match(s).Success) { RegistryKey rk4 = rk3.OpenSubKey(s); foreach (String s2 in rk4.GetSubKeyNames()) { RegistryKey rk5 = rk4.OpenSubKey(s2); RegistryKey rk6 = rk5.OpenSubKey("Device Parameters"); comports.Add((string)rk6.GetValue("PortName")); } } } } return comports; } 

实际代码到了这里 ,那么如何在x64中获取com端口名称,有什么建议吗?

通过阅读您的代码,我发现您在注册表中查看的当前路径不包含任何有关端口的信息。 但是我找到了一种通过做这个小改变来阅读它的方法:

  static List ComPortNames(String VID, String PID) { String pattern = String.Format("^VID_{0}.PID_{1}", VID, PID); Regex _rx = new Regex(pattern, RegexOptions.IgnoreCase); List comports = new List(); RegistryKey rk1 = Registry.LocalMachine; RegistryKey rk2 = rk1.OpenSubKey("SYSTEM\\CurrentControlSet\\Enum"); foreach (String s3 in rk2.GetSubKeyNames()) { RegistryKey rk3 = rk2.OpenSubKey(s3); foreach (String s in rk3.GetSubKeyNames()) { if (_rx.Match(s).Success) { RegistryKey rk4 = rk3.OpenSubKey(s); foreach (String s2 in rk4.GetSubKeyNames()) { RegistryKey rk5 = rk4.OpenSubKey(s2); string location = (string)rk5.GetValue("LocationInformation"); if (!String.IsNullOrEmpty(location)) { string port = location.Substring(location.IndexOf('#') + 1, 4).TrimStart('0'); if (!String.IsNullOrEmpty(port)) comports.Add(String.Format("COM{0:####}", port)); } //RegistryKey rk6 = rk5.OpenSubKey("Device Parameters"); //comports.Add((string)rk6.GetValue("PortName")); } } } } return comports; } 

它做得很好。 谢谢你的代码,顺便说一句……它给了我很多帮助!

当我在Windows 10 x64下测试Youkko的答案时,我得到了一些奇怪的结果,看着我机器上的注册表, LocationInformation键包含Port_#0002.Hub_#0003这样的字符串,所以它们与USB集线器/端口有关设备未连接到Windows分配的COM端口。

所以在我的情况下,我得到COM2包括我的主板上的硬件端口,它跳过我期待的COM5端口,但它位于PortName注册表项下。 我不确定自从你使用的Windows版本以来是否有某些变化,但我认为你的主要问题可能是没有检查密钥上的空值。

下面稍微修改过的版本似乎可以在各种或Windows 7/10和x32 ​​/ 64系统上正常工作,我还添加了一个检查SerialPort.GetPortNames()以确保设备可用并插入系统之前归还它:

 static List ComPortNames(String VID, String PID) { String pattern = String.Format("^VID_{0}.PID_{1}", VID, PID); Regex _rx = new Regex(pattern, RegexOptions.IgnoreCase); List comports = new List(); RegistryKey rk1 = Registry.LocalMachine; RegistryKey rk2 = rk1.OpenSubKey("SYSTEM\\CurrentControlSet\\Enum"); foreach (String s3 in rk2.GetSubKeyNames()) { RegistryKey rk3 = rk2.OpenSubKey(s3); foreach (String s in rk3.GetSubKeyNames()) { if (_rx.Match(s).Success) { RegistryKey rk4 = rk3.OpenSubKey(s); foreach (String s2 in rk4.GetSubKeyNames()) { RegistryKey rk5 = rk4.OpenSubKey(s2); string location = (string)rk5.GetValue("LocationInformation"); RegistryKey rk6 = rk5.OpenSubKey("Device Parameters"); string portName = (string)rk6.GetValue("PortName"); if (!String.IsNullOrEmpty(portName) && SerialPort.GetPortNames().Contains(portName)) comports.Add((string)rk6.GetValue("PortName")); } } } } return comports; } 

我认为ManagementObjectSearcher可能比直接阅读注册表更好。

这是虚拟COM端口的示例 。

这是我对此的看法(即使它不是Q的直接A)

  • HKLM\SYSTEM\CurrentControlSet\Enum\USB下总是(并且一直)枚举HKLM\SYSTEM\CurrentControlSet\Enum\USB (注意USB末尾)
    • 设备节点的格式为VID_xxxx&PID_xxxx* ,其中xxxx为hex,最后可能有一些额外的function数据
    • 每个设备节点具有基于序列号或设备和function的其他数据的子标识符节点
    • 标识符节点可以具有值"FriendlyName" ,其中某些时候在诸如“虚拟串行端口(COM6)”之类的parantheses中具有COM
    • 生成的路径: HKLM\SYSTEM\CurrentControlSet\Enum\USB\VID_xxxx&PID_xxxx*\*\Device Parameters\具有名为"PortName"
  • System.IO.Ports.SerialPort.GetPortNames()列出当前可用的COM端口
  • OpenSubKey实现了IDisposable并且应该对它们using.Dispose()

     using System.IO.Ports; using System.Linq; using Microsoft.Win32; public class UsbSerialPort { public readonly string PortName; public readonly string DeviceId; public readonly string FriendlyName; private UsbSerialPort(string name, string id, string friendly) { PortName = name; DeviceId = id; FriendlyName = friendly; } private static IEnumerable GetSubKeys(RegistryKey key) { foreach (string keyName in key.GetSubKeyNames()) using (var subKey = key.OpenSubKey(keyName)) yield return subKey; } private static string GetName(RegistryKey key) { string name = key.Name; int idx; return (idx = name.LastIndexOf('\\')) == -1 ? name : name.Substring(idx + 1); } public static IEnumerable GetPorts() { var existingPorts = SerialPort.GetPortNames(); using (var enumUsbKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum\USB")) { if (enumUsbKey == null) throw new ArgumentNullException("USB", "No enumerable USB devices found in registry"); foreach (var devBaseKey in GetSubKeys(enumUsbKey)) { foreach (var devFnKey in GetSubKeys(devBaseKey)) { string friendlyName = (string) devFnKey.GetValue("FriendlyName") ?? (string) devFnKey.GetValue("DeviceDesc"); using (var devParamsKey = devFnKey.OpenSubKey("Device Parameters")) { string portName = (string) devParamsKey?.GetValue("PortName"); if (!string.IsNullOrEmpty(portName) && existingPorts.Contains(portName)) yield return new UsbSerialPort(portName, GetName(devBaseKey) + @"\" + GetName(devFnKey), friendlyName); } } } } } public override string ToString() { return string.Format("{0} Friendly: {1} DeviceId: {2}", PortName, FriendlyName, DeviceId); } } 

好的,使用ManagementObjectSearcher(它提供COM端口索引和VID和PID,如果它们存在):

  List < List > USBCOMlist = new List>(); try { ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PnPEntity"); foreach (ManagementObject queryObj in searcher.Get()) { if (queryObj["Caption"].ToString().Contains("(COM")) { List DevInfo = new List(); string Caption = queryObj["Caption"].ToString(); int CaptionIndex = Caption.IndexOf("(COM"); string CaptionInfo = Caption.Substring(CaptionIndex + 1).TrimEnd(')'); // make the trimming more correct DevInfo.Add(CaptionInfo); string deviceId = queryObj["deviceid"].ToString(); //"DeviceID" int vidIndex = deviceId.IndexOf("VID_"); int pidIndex = deviceId.IndexOf("PID_"); string vid = "", pid = ""; if (vidIndex != -1 && pidIndex != -1) { string startingAtVid = deviceId.Substring(vidIndex + 4); // + 4 to remove "VID_" vid = startingAtVid.Substring(0, 4); // vid is four characters long //Console.WriteLine("VID: " + vid); string startingAtPid = deviceId.Substring(pidIndex + 4); // + 4 to remove "PID_" pid = startingAtPid.Substring(0, 4); // pid is four characters long } DevInfo.Add(vid); DevInfo.Add(pid); USBCOMlist.Add(DevInfo); } } } catch (ManagementException e) { MessageBox.Show(e.Message); }