C#提供了标准的serial库,如何获取串口列表不在这里谈论,但并没有提供获取更多串口信息的方法,不能做到获取详细信息 设备描述、PID、VID等,如上图:
不多说,上代码:
public struct PORT_INFO
{
public string port_name;
public string description;
public string hardware_id;
}
private const short INVALID_HANDLE_VALUE = -1;
public const uint DIGCF_DEFAULT = 0x00000001; // only valid with DIGCF_DEVICEINTERFACE
public const uint DIGCF_PRESENT = 0x00000002;
public const uint DIGCF_ALLCLASSES = 0x00000004;
public const uint DIGCF_PROFILE = 0x00000008;
public const uint DIGCF_DEVICEINTERFACE = 0x00000010;
private const int MAX_DEV_LEN = 256;//返回值最大长度
private const int SPDRP_FRIENDLYNAME = (0x0000000C);// FriendlyName (R/W)
private const int SPDRP_DEVICEDESC = (0x00000000);// DeviceDesc (R/W)
private const int SPDRP_HARDWAREID = (0x00000001);// HardwareID (R/W)
private const int DICS_FLAG_GLOBAL = 0x00000001;
public struct SP_DEVINFO_DATA
{
public uint cbSize;
public Guid ClassGuid;
public uint DevInst;
public IntPtr Reserved;
}
[DllImport("SetupAPI.dll")]
public static extern bool SetupDiEnumDeviceInfo(
IntPtr DeviceInfoSet,
uint MemberIndex,
ref SP_DEVINFO_DATA DeviceInfoData
);
[DllImport("SetupAPI.dll")]
public static extern IntPtr SetupDiGetClassDevs(
ref Guid ClassGuid,
uint Enumerator,
IntPtr hwndParent,
uint Flags
);
[DllImport("SetupAPI.dll")]
private static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
[DllImport("setupapi.dll")]
private static extern IntPtr SetupDiOpenDevRegKey(
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
uint Scope,
uint HwProfile,
uint KeyType,
uint samDesired
);
[DllImport("setupapi.dll")]
private static extern bool SetupDiGetDeviceRegistryPropertyW(
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
uint Property,
ref uint PropertyRegDataType,
byte[] PropertyBuffer,
uint PropertyBufferSize,
IntPtr RequiredSize
);
[DllImport("ADVAPI32.dll", CharSet = CharSet.Unicode, BestFitMapping = false)]
internal static extern int RegQueryValueEx(IntPtr hKey, string lpValueName,
int[] lpReserved, ref int lpType, [Out] byte[] lpData,
ref int lpcbData);
[DllImport("ADVAPI32.dll", SetLastError = false)]
internal static extern int RegCloseKey(IntPtr handle);
public static List<PORT_INFO> list_ports()
{
Guid GUID_DEVCLASS_PORTS = new Guid("4d36e978-e325-11ce-bfc1-08002be10318");
Guid GUID_DEVCLASS_MODEM = new Guid("4d36e96d-e325-11ce-bfc1-08002be10318");
Guid GUID_DEVINTERFACE_COMPORT = new Guid("86E0D1E0-8089-11D0-9CE4-08003E301F73");
Guid GUID_DEVINTERFACE_MODEM = new Guid("2c7089aa-2e0e-11d1-b114-00c04fc2aae4");
List<PORT_INFO> ports = new List<PORT_INFO>();
Guid[] ClassGuid = new Guid[4];
ClassGuid[0] = GUID_DEVCLASS_PORTS;
ClassGuid[1] = GUID_DEVCLASS_MODEM;
ClassGuid[2] = GUID_DEVINTERFACE_COMPORT;
ClassGuid[3] = GUID_DEVINTERFACE_MODEM;
uint[] dwFlag = new uint[4];
dwFlag[0] = DIGCF_PRESENT;
dwFlag[1] = DIGCF_PRESENT;
dwFlag[2] = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE;
dwFlag[3] = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE;
List<string> temp_portname_list = new List<string>();//用于判断是否有重复的
for (int index = 0; index < ClassGuid.Length; index++)
{
IntPtr hDevInfo = (IntPtr)INVALID_HANDLE_VALUE;
//函数返回一个包含本机上所有被请求的设备信息的设备信息集句柄
hDevInfo = SetupDiGetClassDevs(ref ClassGuid[index], 0, IntPtr.Zero, dwFlag[index]);
if (hDevInfo == (IntPtr)INVALID_HANDLE_VALUE)
{
return ports;
}
SP_DEVINFO_DATA DeviceInfoData = new SP_DEVINFO_DATA();
DeviceInfoData.cbSize = (uint)Marshal.SizeOf(new SP_DEVINFO_DATA());
//在64位系统上cbSize 是32 32位系统上是28,如果不对则会读取出错
DeviceInfoData.DevInst = 0;
DeviceInfoData.ClassGuid = Guid.Empty;
DeviceInfoData.Reserved = IntPtr.Zero;
//枚举设备信息
uint i = 0;
while (SetupDiEnumDeviceInfo(hDevInfo, i++, ref DeviceInfoData))
{
//Get port name
const uint DIREG_DEV = 0x00000001;
const uint KEY_READ = 0x00020019;
//打开枚举成功的设备注册表句柄hkey,并获取该设备对应的相关信息 DeviceInfoData
IntPtr hkey = SetupDiOpenDevRegKey(
hDevInfo,
ref DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
KEY_READ);
//根据句柄 和关键词获取 portName
string portName = GetStringValue(hkey, "PortName");
//关闭注册表句柄
RegCloseKey(hkey);
if (portName.Length == 0 || portName.ToString().Contains("LPT")) continue;//并口跳过
if (temp_portname_list.IndexOf(portName) >= 0) continue;//重复的跳过
temp_portname_list.Add(portName);
// Get port friendly name 从DeviceInfoData中获取DeviceName信息
byte[] DeviceName = new byte[MAX_DEV_LEN];
uint PropertyRegDataType = 0;
if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, ref DeviceInfoData, SPDRP_FRIENDLYNAME,
ref PropertyRegDataType, DeviceName, MAX_DEV_LEN, IntPtr.Zero))
{
DeviceName = new byte[MAX_DEV_LEN];
}
// Get DeviceDsc 从DeviceInfoData中获取DeviceDsc信息
byte[] DeviceDsc = new byte[MAX_DEV_LEN];
if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, ref DeviceInfoData, SPDRP_DEVICEDESC,
ref PropertyRegDataType, DeviceDsc, MAX_DEV_LEN, IntPtr.Zero))
{
DeviceDsc = new byte[MAX_DEV_LEN];
}
// Get hardware ID 从DeviceInfoData中获取 hardware ID 信息
byte[] hardwareID = new byte[MAX_DEV_LEN];
if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, ref DeviceInfoData, SPDRP_HARDWAREID,
ref PropertyRegDataType, hardwareID, MAX_DEV_LEN, IntPtr.Zero))
{
hardwareID = new byte[MAX_DEV_LEN];
}
PORT_INFO temp_port;
temp_port.port_name = portName.Split('\0').Length > 0 ? portName.Split('\0')[0] : "";
var str_arry = Encoding.Unicode.GetString(DeviceDsc).Split('\0');
temp_port.description = str_arry.Length > 0 ? str_arry[0] : "";
str_arry = Encoding.Unicode.GetString(hardwareID).Split('\0');
temp_port.hardware_id = str_arry.Length > 0 ? str_arry[0] : "";
ports.Add(temp_port);
}
SetupDiDestroyDeviceInfoList(hDevInfo);//
}
return ports;
}
public static string GetStringValue(IntPtr hkey, string valName)
{
int type = 0;
int datasize = 0;
int ret = RegQueryValueEx(hkey, valName, null, ref type, null, ref datasize);
if (ret == 0)
if (type == 1)
{
byte[] blob = new byte[datasize];
ret = RegQueryValueEx(hkey, valName, null, ref type, blob, ref datasize);
UnicodeEncoding unicode = new UnicodeEncoding();
return unicode.GetString(blob);
}
return null;
}
函数调用了windows steupAPI 里的接口获取了串口列表信息
另外,指定PID、VID获取对应串口的方法:
/// <summary>
/// 根据给定的PID VID 搜寻 对应的串口
/// </summary>
/// <param name="pid"></param> PID 注意进制,如 0x5656
/// <param name="vid"></param> VID 注意进制,如 0x5656
/// <returns></returns> 返回的是符合 PID 和VID 的串口名称列表
public string[] GetCOMFromPIDVID(int pid, int vid)
{
List<PORT_INFO> COM_ports = list_ports();
string pid_s = pid.ToString("X4");
string vid_s = vid.ToString("X4");
ArrayList list = new ArrayList();
foreach (var port in COM_ports)
{
if (port.hardware_id.Contains(pid_s) && port.hardware_id.Contains(vid_s))
{
list.Add(port.port_name);
}
}
return (string[])list.ToArray(typeof(string));
}
完整demo工程
https://download.csdn.net/download/m0_54012127/88487604?spm=1001.2014.3001.5503