基于此处的答案组合,这是一个获取 COM 编号、VID / PID 和友好名称等的解决方案。
这是一些用于获取已连接设备列表的示例代码。
public static class SerialPortUtils
{
private static Guid GUID_DEVCLASS_PORTS = new Guid(0x4d36e978u, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18);
private unsafe static bool GetPortRegistryProperty(HDEVINFO classHandle, SP_DEVINFO_DATA* deviceInfo, uint spdrp, out string result)
{
DWORD size;
SetupAPI.SetupDiGetDeviceRegistryPropertyW(classHandle, deviceInfo, spdrp, null, null, 0, &size);
if (size == 0)
{
result = null;
return false;
}
var resultBuffer = new byte[(int)size];
fixed (byte* resultBufferPtr = resultBuffer)
{
if (SetupAPI.SetupDiGetDeviceRegistryPropertyW(classHandle, deviceInfo, spdrp, null, resultBufferPtr, size, null))
{
result = Encoding.Unicode.GetString(resultBufferPtr, (int)size - sizeof(char));
return true;
}
else
{
result = null;
return false;
}
}
}
public unsafe static List<SerialPortDeviceDesc> GetSerialPortDevices()
{
var results = new List<SerialPortDeviceDesc>();
// get present ports handle
var classHandle = SetupAPI.SetupDiGetClassDevsW(ref GUID_DEVCLASS_PORTS, null, IntPtr.Zero, SetupAPI.DIGCF_PRESENT);
if (classHandle == Common.INVALID_HANDLE_VALUE || classHandle == HDEVINFO.Zero) throw new Exception("SetupDiGetClassDevsW failed");
// enumerate all ports
var deviceInfo = new SP_DEVINFO_DATA();
uint deviceInfoSize = (uint)Marshal.SizeOf<SP_DEVINFO_DATA>();
deviceInfo.cbSize = deviceInfoSize;
uint index = 0;
while (SetupAPI.SetupDiEnumDeviceInfo(classHandle, index, &deviceInfo))
{
// get port name
string portName;
HKEY regKey = SetupAPI.SetupDiOpenDevRegKey(classHandle, &deviceInfo, SetupAPI.DICS_FLAG_GLOBAL, 0, SetupAPI.DIREG_DEV, WinNT.KEY_READ);
if (regKey == Common.INVALID_HANDLE_VALUE || regKey == IntPtr.Zero) continue;
using (var regHandle = new SafeRegistryHandle(regKey, true))
using (var key = RegistryKey.FromHandle(regHandle))
{
portName = key.GetValue("PortName") as string;
if (string.IsNullOrEmpty(portName)) continue;
}
// get registry values
if (!GetPortRegistryProperty(classHandle, &deviceInfo, SetupAPI.SPDRP_FRIENDLYNAME, out string friendlyName)) continue;
if (!GetPortRegistryProperty(classHandle, &deviceInfo, SetupAPI.SPDRP_HARDWAREID, out string hardwareID)) continue;
// add device
results.Add(new SerialPortDeviceDesc(friendlyName, portName, hardwareID));
// setup for next device
++index;
deviceInfo = new SP_DEVINFO_DATA();
deviceInfo.cbSize = deviceInfoSize;
}
// finish
SetupAPI.SetupDiDestroyDeviceInfoList(classHandle);
return results;
}
}
这是 SerialPortDeviceDesc 类
public enum SerialPortType
{
Unknown,
COM
}
public class SerialPortDeviceDesc
{
public readonly string friendlyName, portName, hardwareID;
public readonly string vid, pid;
public readonly int portNumber = -1;
public readonly SerialPortType portType = SerialPortType.Unknown;
public SerialPortDeviceDesc(string friendlyName, string portName, string hardwareID)
{
this.friendlyName = friendlyName;
this.portName = portName;
this.hardwareID = hardwareID;
if (portName.StartsWith("COM") && int.TryParse(portName.Substring("COM".Length), out portNumber))
{
portType = SerialPortType.COM;
}
else
{
portNumber = -1;
}
var rx = Regex.Match(hardwareID, @"VID_(\w*)&PID_(\w*)", RegexOptions.IgnoreCase);
if (rx.Success)
{
vid = rx.Groups[1].Value;
pid = rx.Groups[2].Value;
}
}
}