如何在C#中发现已知PID和VID的虚拟COM端口名称
How to discover the virtual COM port name knowing the PID and VID in C#
如果我知道 PID 和 VID,我正在尝试找到查找 COM 端口名称的正确方法。到目前为止,我写了解决方法,但我不认为没有更优雅和正确的方法。顺便说一句(我知道我可以使用 REGEX)。这只是为了测试解决方法。
我知道有很多 space 需要改进,我不要求代码审查
欢迎任何想法:)
namespace ConsoleApplication1
{
using System;
using System.Globalization;
using System.Collections.Generic;
using System.Management;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
VCOMDetect VCOMPorts = new VCOMDetect(0x0483, 0xA27D);
Console.WriteLine("BootPort: {0}", VCOMPorts.BootPort() ?? "Not detected");
Console.WriteLine("Oscilloscope Port: {0}", VCOMPorts.OscilloscopePort() ?? "Not detected");
Console.WriteLine("Serial/USB Port: {0}", VCOMPorts.SerialPort() ?? "Not detected");
Console.WriteLine("Programming Port: {0}", VCOMPorts.ProgPort() ?? "Not detected");
Console.Read();
}
}
class VCOMDetect
{
private const string USB_BOOTLOADER_SERIAL = "000000000b00";
private const string USB_OSCILLOSCOPE_SERIAL = "000000000c00";
private const string USB_VCOM_SERIAL = "000000000d00";
private const string USB_PRG_SERIAL = "000000000e00";
private List<VCOM_USBDeviceInfo> PortsList;
public VCOMDetect(UInt16 vid, UInt16 pid)
{
PortsList = GetUSBDevices(vid, pid);
}
public string BootPort()
{
foreach(VCOM_USBDeviceInfo VCOM in PortsList)
{
if (VCOM.Serial.ToLower() == USB_BOOTLOADER_SERIAL.ToLower()) return VCOM.COMPort;
}
return null;
}
public string OscilloscopePort()
{
foreach (VCOM_USBDeviceInfo VCOM in PortsList)
{
if (VCOM.Serial.ToLower() == USB_OSCILLOSCOPE_SERIAL.ToLower()) return VCOM.COMPort;
}
return null;
}
public string SerialPort()
{
foreach (VCOM_USBDeviceInfo VCOM in PortsList)
{
if (VCOM.Serial.ToLower() == USB_VCOM_SERIAL.ToLower()) return VCOM.COMPort;
}
return null;
}
public string ProgPort()
{
foreach (VCOM_USBDeviceInfo VCOM in PortsList)
{
if (VCOM.Serial.ToLower() == USB_PRG_SERIAL.ToLower()) return VCOM.COMPort;
}
return null;
}
private List<VCOM_USBDeviceInfo> GetUSBDevices(UInt16 vid, UInt16 pid)
{
List<VCOM_USBDeviceInfo> VCOM_devices = new List<VCOM_USBDeviceInfo>();
ManagementObjectCollection collection;
using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_PnPEntity"))
collection = searcher.Get();
foreach (var device in collection)
{
var USBInfo = new VCOM_USBDeviceInfo((string)device.GetPropertyValue("DeviceID"));
if (USBInfo.PID == 0 || USBInfo.VID == 0) continue;
if (USBInfo.PID != pid || USBInfo.VID != vid) continue;
USBInfo.Caption = (string)device.GetPropertyValue("Caption");
if (USBInfo.COMPort == "") continue;
USBInfo.PnpDeviceID = (string)device.GetPropertyValue("PNPDeviceID");
USBInfo.Description = (string)device.GetPropertyValue("Description");
VCOM_devices.Add(USBInfo);
}
collection.Dispose();
return VCOM_devices;
}
}
class VCOM_USBDeviceInfo
{
private UInt16 _PID, _VID;
private string _Caption;
private void _ResetData()
{
this.PID = 0;
this.VID = 0;
this.COMnumber = -1;
this.COMPort = "";
this.Serial = "";
}
public VCOM_USBDeviceInfo(string DeviceID)
{
int VIDIndex = DeviceID.IndexOf("VID_");
int PIDIndex = DeviceID.IndexOf("PID_");
int VIDIndexEnd = -1;
int PIDIndexEnd = -1;
string PIDSubstring, VIDSubstring;
if (PIDIndex == -1 || VIDIndex == -1)
{
_ResetData();
}
else
{
bool result = true;
PIDSubstring = DeviceID.Substring(PIDIndex + 4);
VIDSubstring = DeviceID.Substring(VIDIndex + 4);
PIDIndexEnd = PIDSubstring.IndexOf("\");
VIDIndexEnd = VIDSubstring.IndexOf("&");
if(PIDIndexEnd == -1 || VIDIndexEnd == -1)
{
_ResetData();
}
else
{
result = result && UInt16.TryParse(PIDSubstring.Substring(0, PIDIndexEnd), NumberStyles.AllowHexSpecifier, null, out _PID) && UInt16.TryParse(VIDSubstring.Substring(0, VIDIndexEnd), NumberStyles.AllowHexSpecifier, null, out _VID);
if(!result)
{
_ResetData();
}
else
{
PID = _PID;
VID = _VID;
Serial = PIDSubstring.Substring(PIDIndexEnd + 1);
}
}
}
}
public string DeviceID { get; set; }
public string PnpDeviceID { get; set; }
public string Description { get; set; }
public string Caption
{
get
{
return _Caption;
}
set
{
int COMindex = value.IndexOf("(COM");
string tmpCOMPort = COMindex == -1 ? "" : value.Substring(COMindex + 1, 4);
if(COMPort == null || COMPort.Length == 0)
{
COMPort = tmpCOMPort;
}
else
{
if(COMPort != tmpCOMPort)
{
Console.WriteLine("Inconsistent COM port information");
}
}
_Caption = value;
}
}
public UInt16 PID { get; set; }
public UInt16 VID { get; set; }
public string Serial { get; set; }
public int COMnumber { get; set; }
public string COMPort { get; set; }
}
}
它完成了工作 - 但我不喜欢它
其实我觉得你的代码看起来不错。是的,我会使用正则表达式,并且在某些地方可以压缩内容。但是,这些东西无助于提高性能或做任何其他事情。只是,主要是让代码更小。我还假设此应用仅在 Windows 上 运行。
无论如何,这段代码有帮助吗:
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text.RegularExpressions;
namespace PortNames
{
class Program
{
static List<string> ComPortNames(String VID, String PID)
{
RegistryKey rk1 = Registry.LocalMachine;
RegistryKey rk2 = rk1.OpenSubKey("SYSTEM\CurrentControlSet\Enum");
String pattern = String.Format("^VID_{0}.PID_{1}", VID, PID);
Regex _rx = new Regex(pattern, RegexOptions.IgnoreCase);
List<string> ports = new List<string>();
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");
ports.Add((string)rk6.GetValue("PortName"));
}
}
}
}
return ports;
}
static void Main(string[] args)
{
List<string> names = ComPortNames("0403", "6001");
if (names.Count > 0) foreach (String s in SerialPort.GetPortNames()) { Console.WriteLine(s); }
Console.ReadLine();
}
}
}
或
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text.RegularExpressions;
namespace PortNames
{
class Program
{
private const string vidPattern = @"VID_([0-9A-F]{4})";
private const string pidPattern = @"PID_([0-9A-F]{4})";
struct ComPort // custom struct with our desired values
{
public string name;
public string vid;
public string pid;
public string description;
}
private static List<ComPort> GetSerialPorts()
{
using (var searcher = new ManagementObjectSearcher
("SELECT * FROM WIN32_SerialPort"))
{
var ports = searcher.Get().Cast<ManagementBaseObject>().ToList();
return ports.Select(p =>
{
ComPort c = new ComPort();
c.name = p.GetPropertyValue("DeviceID").ToString();
c.vid = p.GetPropertyValue("PNPDeviceID").ToString();
c.description = p.GetPropertyValue("Caption").ToString();
Match mVID = Regex.Match(c.vid, vidPattern, RegexOptions.IgnoreCase);
Match mPID = Regex.Match(c.vid, pidPattern, RegexOptions.IgnoreCase);
if (mVID.Success)
c.vid = mVID.Groups[1].Value;
if (mPID.Success)
c.pid = mPID.Groups[1].Value;
return c;
}).ToList();
}
}
static void Main(string[] args)
{
List<ComPort> ports = GetSerialPorts();
//if we want to find one device
ComPort com = ports.FindLast(c => c.vid.Equals("0483") && c.pid.Equals("5740"));
//or if we want to extract all devices with specified values:
List<ComPort> coms = ports.FindAll(c => c.vid.Equals("0483") && c.pid.Equals("5740"));
Console.ReadLine();
}
}
}
如果我知道 PID 和 VID,我正在尝试找到查找 COM 端口名称的正确方法。到目前为止,我写了解决方法,但我不认为没有更优雅和正确的方法。顺便说一句(我知道我可以使用 REGEX)。这只是为了测试解决方法。
我知道有很多 space 需要改进,我不要求代码审查
欢迎任何想法:)
namespace ConsoleApplication1
{
using System;
using System.Globalization;
using System.Collections.Generic;
using System.Management;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
VCOMDetect VCOMPorts = new VCOMDetect(0x0483, 0xA27D);
Console.WriteLine("BootPort: {0}", VCOMPorts.BootPort() ?? "Not detected");
Console.WriteLine("Oscilloscope Port: {0}", VCOMPorts.OscilloscopePort() ?? "Not detected");
Console.WriteLine("Serial/USB Port: {0}", VCOMPorts.SerialPort() ?? "Not detected");
Console.WriteLine("Programming Port: {0}", VCOMPorts.ProgPort() ?? "Not detected");
Console.Read();
}
}
class VCOMDetect
{
private const string USB_BOOTLOADER_SERIAL = "000000000b00";
private const string USB_OSCILLOSCOPE_SERIAL = "000000000c00";
private const string USB_VCOM_SERIAL = "000000000d00";
private const string USB_PRG_SERIAL = "000000000e00";
private List<VCOM_USBDeviceInfo> PortsList;
public VCOMDetect(UInt16 vid, UInt16 pid)
{
PortsList = GetUSBDevices(vid, pid);
}
public string BootPort()
{
foreach(VCOM_USBDeviceInfo VCOM in PortsList)
{
if (VCOM.Serial.ToLower() == USB_BOOTLOADER_SERIAL.ToLower()) return VCOM.COMPort;
}
return null;
}
public string OscilloscopePort()
{
foreach (VCOM_USBDeviceInfo VCOM in PortsList)
{
if (VCOM.Serial.ToLower() == USB_OSCILLOSCOPE_SERIAL.ToLower()) return VCOM.COMPort;
}
return null;
}
public string SerialPort()
{
foreach (VCOM_USBDeviceInfo VCOM in PortsList)
{
if (VCOM.Serial.ToLower() == USB_VCOM_SERIAL.ToLower()) return VCOM.COMPort;
}
return null;
}
public string ProgPort()
{
foreach (VCOM_USBDeviceInfo VCOM in PortsList)
{
if (VCOM.Serial.ToLower() == USB_PRG_SERIAL.ToLower()) return VCOM.COMPort;
}
return null;
}
private List<VCOM_USBDeviceInfo> GetUSBDevices(UInt16 vid, UInt16 pid)
{
List<VCOM_USBDeviceInfo> VCOM_devices = new List<VCOM_USBDeviceInfo>();
ManagementObjectCollection collection;
using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_PnPEntity"))
collection = searcher.Get();
foreach (var device in collection)
{
var USBInfo = new VCOM_USBDeviceInfo((string)device.GetPropertyValue("DeviceID"));
if (USBInfo.PID == 0 || USBInfo.VID == 0) continue;
if (USBInfo.PID != pid || USBInfo.VID != vid) continue;
USBInfo.Caption = (string)device.GetPropertyValue("Caption");
if (USBInfo.COMPort == "") continue;
USBInfo.PnpDeviceID = (string)device.GetPropertyValue("PNPDeviceID");
USBInfo.Description = (string)device.GetPropertyValue("Description");
VCOM_devices.Add(USBInfo);
}
collection.Dispose();
return VCOM_devices;
}
}
class VCOM_USBDeviceInfo
{
private UInt16 _PID, _VID;
private string _Caption;
private void _ResetData()
{
this.PID = 0;
this.VID = 0;
this.COMnumber = -1;
this.COMPort = "";
this.Serial = "";
}
public VCOM_USBDeviceInfo(string DeviceID)
{
int VIDIndex = DeviceID.IndexOf("VID_");
int PIDIndex = DeviceID.IndexOf("PID_");
int VIDIndexEnd = -1;
int PIDIndexEnd = -1;
string PIDSubstring, VIDSubstring;
if (PIDIndex == -1 || VIDIndex == -1)
{
_ResetData();
}
else
{
bool result = true;
PIDSubstring = DeviceID.Substring(PIDIndex + 4);
VIDSubstring = DeviceID.Substring(VIDIndex + 4);
PIDIndexEnd = PIDSubstring.IndexOf("\");
VIDIndexEnd = VIDSubstring.IndexOf("&");
if(PIDIndexEnd == -1 || VIDIndexEnd == -1)
{
_ResetData();
}
else
{
result = result && UInt16.TryParse(PIDSubstring.Substring(0, PIDIndexEnd), NumberStyles.AllowHexSpecifier, null, out _PID) && UInt16.TryParse(VIDSubstring.Substring(0, VIDIndexEnd), NumberStyles.AllowHexSpecifier, null, out _VID);
if(!result)
{
_ResetData();
}
else
{
PID = _PID;
VID = _VID;
Serial = PIDSubstring.Substring(PIDIndexEnd + 1);
}
}
}
}
public string DeviceID { get; set; }
public string PnpDeviceID { get; set; }
public string Description { get; set; }
public string Caption
{
get
{
return _Caption;
}
set
{
int COMindex = value.IndexOf("(COM");
string tmpCOMPort = COMindex == -1 ? "" : value.Substring(COMindex + 1, 4);
if(COMPort == null || COMPort.Length == 0)
{
COMPort = tmpCOMPort;
}
else
{
if(COMPort != tmpCOMPort)
{
Console.WriteLine("Inconsistent COM port information");
}
}
_Caption = value;
}
}
public UInt16 PID { get; set; }
public UInt16 VID { get; set; }
public string Serial { get; set; }
public int COMnumber { get; set; }
public string COMPort { get; set; }
}
}
它完成了工作 - 但我不喜欢它
其实我觉得你的代码看起来不错。是的,我会使用正则表达式,并且在某些地方可以压缩内容。但是,这些东西无助于提高性能或做任何其他事情。只是,主要是让代码更小。我还假设此应用仅在 Windows 上 运行。
无论如何,这段代码有帮助吗:
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text.RegularExpressions;
namespace PortNames
{
class Program
{
static List<string> ComPortNames(String VID, String PID)
{
RegistryKey rk1 = Registry.LocalMachine;
RegistryKey rk2 = rk1.OpenSubKey("SYSTEM\CurrentControlSet\Enum");
String pattern = String.Format("^VID_{0}.PID_{1}", VID, PID);
Regex _rx = new Regex(pattern, RegexOptions.IgnoreCase);
List<string> ports = new List<string>();
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");
ports.Add((string)rk6.GetValue("PortName"));
}
}
}
}
return ports;
}
static void Main(string[] args)
{
List<string> names = ComPortNames("0403", "6001");
if (names.Count > 0) foreach (String s in SerialPort.GetPortNames()) { Console.WriteLine(s); }
Console.ReadLine();
}
}
}
或
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text.RegularExpressions;
namespace PortNames
{
class Program
{
private const string vidPattern = @"VID_([0-9A-F]{4})";
private const string pidPattern = @"PID_([0-9A-F]{4})";
struct ComPort // custom struct with our desired values
{
public string name;
public string vid;
public string pid;
public string description;
}
private static List<ComPort> GetSerialPorts()
{
using (var searcher = new ManagementObjectSearcher
("SELECT * FROM WIN32_SerialPort"))
{
var ports = searcher.Get().Cast<ManagementBaseObject>().ToList();
return ports.Select(p =>
{
ComPort c = new ComPort();
c.name = p.GetPropertyValue("DeviceID").ToString();
c.vid = p.GetPropertyValue("PNPDeviceID").ToString();
c.description = p.GetPropertyValue("Caption").ToString();
Match mVID = Regex.Match(c.vid, vidPattern, RegexOptions.IgnoreCase);
Match mPID = Regex.Match(c.vid, pidPattern, RegexOptions.IgnoreCase);
if (mVID.Success)
c.vid = mVID.Groups[1].Value;
if (mPID.Success)
c.pid = mPID.Groups[1].Value;
return c;
}).ToList();
}
}
static void Main(string[] args)
{
List<ComPort> ports = GetSerialPorts();
//if we want to find one device
ComPort com = ports.FindLast(c => c.vid.Equals("0483") && c.pid.Equals("5740"));
//or if we want to extract all devices with specified values:
List<ComPort> coms = ports.FindAll(c => c.vid.Equals("0483") && c.pid.Equals("5740"));
Console.ReadLine();
}
}
}