问题
As following i able to get usb com port names attached to 32bit win7OS machine, by given pid and vid,but when running in x64 it stuck in the following line:
comports.Add((string)rk6.GetValue("PortName"));
This is my code
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;
}
actual code get here, So how to get com port names in x64, any suggestion?
回答1:
By reading your code, I found out that the current path you're looking at in registry does not contain any information about ports. But I found a way to read it by doing this little change:
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;
}
It did work perfectly. Thank you for your code, by the way... It helped me a lot!
回答2:
While I was testing the answer from Youkko under Windows 10 x64 I was getting some strange results and looking at the registry on my machine the LocationInformation
keys contained strings such as Port_#0002.Hub_#0003
so they are related to the USB hub / port the device is connected to not the COM port allocated by Windows.
So in my case I was getting COM2 included which is a hardware port on my motherboard and it skipped the COM5 port I was expecting but that was located under the PortName
registry key. I'm not sure if something has changed since the version of Windows you were using but I think your main problem might have been not checking for null values on the keys.
The following slightly modified version seems to work fine on a variety or Windows 7 / 10 and x32 / 64 systems and I've also added a to check of SerialPort.GetPortNames()
to make sure the device is available and plugged into the system before returning it:
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;
}
回答3:
I think ManagementObjectSearcher may be a better approach than directly reading the registry.
Here's an example for virtual COM ports.
回答4:
Here is my take on this (even if it is not a direct A to the Q)
- USB devices is always (and has always) enumerated under
HKLM\SYSTEM\CurrentControlSet\Enum\USB
(noteUSB
at the end) - Device nodes have the format
VID_xxxx&PID_xxxx*
wherexxxx
is hexadecimal, there might be some extra function data at the end
- Device nodes have the format
- Each device node has a sub identifier node based on serialnumber or other data of the device and functions
- identifier node can have value
"FriendlyName"
which some times have the COM in parantheses such as "Virtual Serial Port (COM6)"
- identifier node can have value
- Resulting path:
HKLM\SYSTEM\CurrentControlSet\Enum\USB\VID_xxxx&PID_xxxx*\*\Device Parameters\
has value named"PortName"
- Resulting path:
- Currently available com ports is listed by
System.IO.Ports.SerialPort.GetPortNames()
OpenSubKey
implementsIDisposable
and should haveusing
or.Dispose()
on themusing 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); } }
回答5:
Ok, using ManagementObjectSearcher (it gives COM-port index and VID and PID if they exist):
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);
}
来源:https://stackoverflow.com/questions/10350340/identify-com-port-using-vid-and-pid-for-usb-device-attached-to-x64