Определите COM-порт с помощью VID и PID для USB-устройства, подключенного к x64
как показано ниже, я могу получить имена USB com-портов, подключенных к 32-битной машине win7OS, с помощью PID и vid, но при запуске в 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("SYSTEMCurrentControlSetEnum");
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;
}
фактический код здесь, так как получить имена COM-портов в x64, любое предложение?
5 ответов
прочитав ваш код, я обнаружил, что текущий путь, который вы смотрите в реестре, не содержит никакой информации о портах. Но я нашел способ прочитать его, сделав это небольшое изменение:
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;
}
он работал отлично. Кстати, спасибо за код... Это мне очень помогло!
пока я тестировал ответ от Youkko под Windows 10 x64 я получал некоторые странные результаты и смотрел на реестр на моей машине LocationInformation
ключи содержали строки, такие как Port_#0002.Hub_#0003
таким образом, они связаны с USB-концентратором / портом, устройство подключено не к COM-порту, выделенному Windows.
поэтому в моем случае я получал COM2, который является аппаратным портом на моей материнской плате, и он пропустил порт COM5, который я ожидал, но который был расположен под PortName
ключ реестра. Я не уверен, что что-то изменилось с версии Windows, которую вы использовали, но я думаю, что ваша главная проблема, возможно, не проверяла значения null на ключах.
следующая слегка измененная версия, похоже, отлично работает на различных системах Windows 7 / 10 и x32 / 64, и я также добавил a для проверки 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;
}
Я думаю ManagementObjectSearcher может быть лучшим подходом, чем прямое чтение реестра.
здесь пример для виртуальных COM-портов.
вот мой взгляд на это (даже если это не прямое A к Q)
- USB-устройства всегда (и всегда) перечислены в разделе
HKLM\SYSTEM\CurrentControlSet\Enum\USB
(ПримечаниеUSB
в конце) - узлы устройства имеют формат
VID_xxxx&PID_xxxx*
здесьxxxx
является шестнадцатеричным, могут быть некоторые дополнительные данные функции в конце
- узлы устройства имеют формат
- каждый узел устройства имеет узел идентификатора sub на основе serialnumber или других данных устройство и функции
- узел идентификатора может иметь значение
"FriendlyName"
которые несколько раз имеют COM в паратезах, таких как"виртуальный последовательный порт (COM6)"
- узел идентификатора может иметь значение
- путь:
HKLM\SYSTEM\CurrentControlSet\Enum\USB\VID_xxxx&PID_xxxx*\*\Device Parameters\
значение имени"PortName"
- путь:
- в настоящее время доступные COM-порты перечислены
System.IO.Ports.SerialPort.GetPortNames()
-
OpenSubKey
осуществляетIDisposable
а должно бытьusing
или.Dispose()
на их!--14-->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); } }
Ok, используя 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);
}