如下所示,我可以通过给定的pid和vid获得连接到32位win7OS机器的usb com端口名称,但是当在x64中运行时它会卡在以下行中:
comports.Add((string)rk6.GetValue("PortName"));
这是我的代码
static List<string> ComPortNames(String VID, String PID)
{
String pattern = String.Format("^VID_{0}.PID_{1}", VID, PID);
Regex _rx = new Regex(pattern, RegexOptions.IgnoreCase);
List<string> comports = new List<string>();
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;
}
实际代码获取here,那么如何在x64中获取com端口名称,是否有任何建议?
答案 0 :(得分:6)
通过阅读您的代码,我发现您在注册表中查看的当前路径不包含任何有关端口的信息。 但我找到了一种通过做这个小改变来阅读它的方法:
static List<string> ComPortNames(String VID, String PID)
{
String pattern = String.Format("^VID_{0}.PID_{1}", VID, PID);
Regex _rx = new Regex(pattern, RegexOptions.IgnoreCase);
List<string> comports = new List<string>();
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;
}
它确实完美无缺。 顺便说一下,谢谢你的代码......它给了我很多帮助!
答案 1 :(得分:5)
当我在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<string> ComPortNames(String VID, String PID)
{
String pattern = String.Format("^VID_{0}.PID_{1}", VID, PID);
Regex _rx = new Regex(pattern, RegexOptions.IgnoreCase);
List<string> comports = new List<string>();
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;
}
答案 2 :(得分:2)
我认为ManagementObjectSearcher可能比直接阅读注册表更好。
这是虚拟COM端口的an example。
答案 3 :(得分:1)
这是我对此的看法(即使它不是Q的直接A)
HKLM\SYSTEM\CurrentControlSet\Enum\USB
下进行枚举(最后请注意USB
)VID_xxxx&PID_xxxx*
,其中xxxx
为十六进制,最后可能会有一些额外的功能数据"FriendlyName"
,其中某些时候具有COM的parantheses,例如“虚拟串行端口(COM6)”HKLM\SYSTEM\CurrentControlSet\Enum\USB\VID_xxxx&PID_xxxx*\*\Device Parameters\
的值为"PortName"
System.IO.Ports.SerialPort.GetPortNames()
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<RegistryKey> 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<UsbSerialPort> 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);
}
}
答案 4 :(得分:1)
好的,使用ManagementObjectSearcher(它提供COM端口索引和VID以及PID,如果它们存在):
List < List <string>> USBCOMlist = new List<List<string>>();
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_PnPEntity");
foreach (ManagementObject queryObj in searcher.Get())
{
if (queryObj["Caption"].ToString().Contains("(COM"))
{
List<string> DevInfo = new List<string>();
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);
}