回答
尝试运行在Win32_SerialPort类WMI查询下载WmiCodeCreator进行实验,并自动生成的C#代码
我不知道为什么,但在我的使用WMI的系统上找不到COM1以外的任何东西。即使指定一个已知的端口,例如'Select * from Win32_SerialPort',其中Name ='COM11'也不会返回任何内容。尽管如此,setupapi解决方案仍然完美。任何想法为什么WMI只知道COM1? – 2011-02-02 12:10:19
@蒂姆 - 从来没有听说过这个失败,不知道。 – 2011-02-02 12:34:14
@Hans Passant:根据此[链接](http://www.creativecodedesign.com/node/39),使用WMI查询“SELECT * FROM Win32_SerialPort”并不总是返回所有COM端口。该链接提供了另一种解决方案。 – markyd13 2012-04-25 19:53:42
发帖今晚的代码,每个人的享受:。
public class SetupDiWrap
{
static public string ComPortNameFromFriendlyNamePrefix(string friendlyNamePrefix)
{
const string className = "Ports";
Guid[] guids = GetClassGUIDs(className);
System.Text.RegularExpressions.Regex friendlyNameToComPort =
new System.Text.RegularExpressions.Regex(@".? \((COM\d+)\)$"); // "..... (COMxxx)" -> COMxxxx
foreach (Guid guid in guids)
{
// We start at the "root" of the device tree and look for all
// devices that match the interface GUID of a disk
Guid guidClone = guid;
IntPtr h = SetupDiGetClassDevs(ref guidClone, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_PROFILE);
if (h.ToInt32() != INVALID_HANDLE_VALUE)
{
int nDevice = 0;
while (true)
{
SP_DEVINFO_DATA da = new SP_DEVINFO_DATA();
da.cbSize = (uint)Marshal.SizeOf(da);
if (0 == SetupDiEnumDeviceInfo(h, nDevice++, ref da))
break;
uint RegType;
byte[] ptrBuf = new byte[BUFFER_SIZE];
uint RequiredSize;
if (SetupDiGetDeviceRegistryProperty(h, ref da,
(uint)SPDRP.FRIENDLYNAME, out RegType, ptrBuf,
BUFFER_SIZE, out RequiredSize))
{
const int utf16terminatorSize_bytes = 2;
string friendlyName = System.Text.UnicodeEncoding.Unicode.GetString(ptrBuf, 0, (int)RequiredSize - utf16terminatorSize_bytes);
if (!friendlyName.StartsWith(friendlyNamePrefix))
continue;
if (!friendlyNameToComPort.IsMatch(friendlyName))
continue;
return friendlyNameToComPort.Match(friendlyName).Groups[1].Value;
}
} // devices
SetupDiDestroyDeviceInfoList(h);
}
} // class guids
return null;
}
/// <summary>
/// The SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct SP_DEVINFO_DATA
{
/// <summary>Size of the structure, in bytes.</summary>
public uint cbSize;
/// <summary>GUID of the device interface class.</summary>
public Guid ClassGuid;
/// <summary>Handle to this device instance.</summary>
public uint DevInst;
/// <summary>Reserved; do not use.</summary>
public uint Reserved;
}
[StructLayout(LayoutKind.Sequential)]
private struct SP_DEVICE_INTERFACE_DATA
{
public Int32 cbSize;
public Guid interfaceClassGuid;
public Int32 flags;
private UIntPtr reserved;
}
const int BUFFER_SIZE = 1024;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
public int cbSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
public string DevicePath;
}
private enum SPDRP
{
DEVICEDESC = 0x00000000,
HARDWAREID = 0x00000001,
COMPATIBLEIDS = 0x00000002,
NTDEVICEPATHS = 0x00000003,
SERVICE = 0x00000004,
CONFIGURATION = 0x00000005,
CONFIGURATIONVECTOR = 0x00000006,
CLASS = 0x00000007,
CLASSGUID = 0x00000008,
DRIVER = 0x00000009,
CONFIGFLAGS = 0x0000000A,
MFG = 0x0000000B,
FRIENDLYNAME = 0x0000000C,
LOCATION_INFORMATION = 0x0000000D,
PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E,
CAPABILITIES = 0x0000000F,
UI_NUMBER = 0x00000010,
UPPERFILTERS = 0x00000011,
LOWERFILTERS = 0x00000012,
MAXIMUM_PROPERTY = 0x00000013,
}
[DllImport("setupapi.dll", SetLastError = true)]
static extern bool SetupDiClassGuidsFromName(string ClassName,
ref Guid ClassGuidArray1stItem, UInt32 ClassGuidArraySize,
out UInt32 RequiredSize);
[DllImport("setupapi.dll")]
internal static extern IntPtr SetupDiGetClassDevsEx(IntPtr ClassGuid,
[MarshalAs(UnmanagedType.LPStr)]String enumerator,
IntPtr hwndParent, Int32 Flags, IntPtr DeviceInfoSet,
[MarshalAs(UnmanagedType.LPStr)]String MachineName, IntPtr Reserved);
[DllImport("setupapi.dll")]
internal static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern Boolean SetupDiEnumDeviceInterfaces(
IntPtr hDevInfo,
IntPtr optionalCrap, //ref SP_DEVINFO_DATA devInfo,
ref Guid interfaceClassGuid,
UInt32 memberIndex,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData
);
[DllImport("setupapi.dll")]
private static extern Int32 SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet,
Int32 MemberIndex, ref SP_DEVINFO_DATA DeviceInterfaceData);
[DllImport("setupapi.dll")]
private static extern Int32 SetupDiClassNameFromGuid(ref Guid ClassGuid,
StringBuilder className, Int32 ClassNameSize, ref Int32 RequiredSize);
[DllImport("setupapi.dll")]
private static extern Int32 SetupDiGetClassDescription(ref Guid ClassGuid,
StringBuilder classDescription, Int32 ClassDescriptionSize, ref Int32 RequiredSize);
[DllImport("setupapi.dll")]
private static extern Int32 SetupDiGetDeviceInstanceId(IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
StringBuilder DeviceInstanceId, Int32 DeviceInstanceIdSize, ref Int32 RequiredSize);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
static extern IntPtr SetupDiGetClassDevs( // 1st form using a ClassGUID only, with null Enumerator
ref Guid ClassGuid,
IntPtr Enumerator,
IntPtr hwndParent,
int Flags
);
[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern Boolean SetupDiGetDeviceInterfaceDetail(
IntPtr hDevInfo,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData,
UInt32 deviceInterfaceDetailDataSize,
out UInt32 requiredSize,
ref SP_DEVINFO_DATA deviceInfoData
);
/// <summary>
/// The SetupDiGetDeviceRegistryProperty function retrieves the specified device property.
/// This handle is typically returned by the SetupDiGetClassDevs or SetupDiGetClassDevsEx function.
/// </summary>
/// <param Name="DeviceInfoSet">Handle to the device information set that contains the interface and its underlying device.</param>
/// <param Name="DeviceInfoData">Pointer to an SP_DEVINFO_DATA structure that defines the device instance.</param>
/// <param Name="Property">Device property to be retrieved. SEE MSDN</param>
/// <param Name="PropertyRegDataType">Pointer to a variable that receives the registry data Type. This parameter can be NULL.</param>
/// <param Name="PropertyBuffer">Pointer to a buffer that receives the requested device property.</param>
/// <param Name="PropertyBufferSize">Size of the buffer, in bytes.</param>
/// <param Name="RequiredSize">Pointer to a variable that receives the required buffer size, in bytes. This parameter can be NULL.</param>
/// <returns>If the function succeeds, the return value is nonzero.</returns>
[DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetupDiGetDeviceRegistryProperty(
IntPtr DeviceInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
uint Property,
out UInt32 PropertyRegDataType,
byte[] PropertyBuffer,
uint PropertyBufferSize,
out UInt32 RequiredSize);
const int DIGCF_DEFAULT = 0x1;
const int DIGCF_PRESENT = 0x2;
const int DIGCF_ALLCLASSES = 0x4;
const int DIGCF_PROFILE = 0x8;
const int DIGCF_DEVICEINTERFACE = 0x10;
const int INVALID_HANDLE_VALUE = -1;
private static Guid[] GetClassGUIDs(string className)
{
UInt32 requiredSize = 0;
Guid[] guidArray = new Guid[1];
bool status = SetupDiClassGuidsFromName(className, ref guidArray[0], 1, out requiredSize);
if (true == status)
{
if (1 < requiredSize)
{
guidArray = new Guid[requiredSize];
SetupDiClassGuidsFromName(className, ref guidArray[0], requiredSize, out requiredSize);
}
}
else
throw new System.ComponentModel.Win32Exception();
return guidArray;
}
}
我知道这是张贴在C#中,但我可以肯定这可以很容易地转换......
Public Function foo() As Integer
Try
Dim searcher As New ManagementObjectSearcher(_
"root\CIMV2", _
"SELECT * FROM Win32_SerialPort")
For Each queryObj As ManagementObject In searcher.Get()
Debug.WriteLine(queryObj("Caption"))
Debug.WriteLine(queryObj("Description"))
Debug.WriteLine(queryObj("DeviceID"))
Debug.WriteLine(queryObj("Name"))
Debug.WriteLine(queryObj("PNPDeviceID"))
Next
Catch err As ManagementException
Stop
End Try
End Function
Public Function bar() As Integer
Try
Dim searcher As New ManagementObjectSearcher(_
"root\CIMV2", _
"SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0")
For Each queryObj As ManagementObject In searcher.Get()
If queryObj("Caption").ToString.Contains("(COM") Then
Debug.WriteLine(queryObj("Caption"))
Debug.WriteLine(queryObj("Description"))
Debug.WriteLine(queryObj("DeviceID"))
Debug.WriteLine(queryObj("Name"))
Debug.WriteLine(queryObj("PNPDeviceID"))
End If
Next
Catch err As ManagementException
Stop
End Try
End Function
它发现我所有的COM端口,调制解调器,串口,USB和蓝牙的。
This article的代码为我做了这项工作(他链接到这篇文章,但似乎没有提供一个答案在这里自己)。下面是笔者的代码:
using System.Management;
internal class ProcessConnection {
public static ConnectionOptions ProcessConnectionOptions()
{
ConnectionOptions options = new ConnectionOptions();
options.Impersonation = ImpersonationLevel.Impersonate;
options.Authentication = AuthenticationLevel.Default;
options.EnablePrivileges = true;
return options;
}
public static ManagementScope ConnectionScope(string machineName, ConnectionOptions options, string path)
{
ManagementScope connectScope = new ManagementScope();
connectScope.Path = new ManagementPath(@"\\" + machineName + path);
connectScope.Options = options;
connectScope.Connect();
return connectScope;
}
}
public class COMPortInfo
{
public string Name { get; set; }
public string Description { get; set; }
public COMPortInfo() { }
public static List<COMPortInfo> GetCOMPortsInfo()
{
List<COMPortInfo> comPortInfoList = new List<COMPortInfo>();
ConnectionOptions options = ProcessConnection.ProcessConnectionOptions();
ManagementScope connectionScope = ProcessConnection.ConnectionScope(Environment.MachineName, options, @"\root\CIMV2");
ObjectQuery objectQuery = new ObjectQuery("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");
ManagementObjectSearcher comPortSearcher = new ManagementObjectSearcher(connectionScope, objectQuery);
using (comPortSearcher)
{
string caption = null;
foreach (ManagementObject obj in comPortSearcher.Get())
{
if (obj != null)
{
object captionObj = obj["Caption"];
if (captionObj != null)
{
caption = captionObj.ToString();
if (caption.Contains("(COM"))
{
COMPortInfo comPortInfo = new COMPortInfo();
comPortInfo.Name = caption.Substring(caption.LastIndexOf("(COM")).Replace("(", string.Empty).Replace(")",
string.Empty);
comPortInfo.Description = caption;
comPortInfoList.Add(comPortInfo);
}
}
}
}
}
return comPortInfoList;
}
}
用法:
foreach (COMPortInfo comPort in COMPortInfo.GetCOMPortsInfo())
{
Console.WriteLine(string.Format("{0} – {1}", comPort.Name, comPort.Description));
}
这工作完美!感谢您重新发布! – 2014-08-12 17:28:42
您还可能要为我发现WMI很慢(5或6秒)考虑使用注册表
在我的案例我想识别具有已知友好名称的设备的COM端口名称。使用regedit我搜索注册表中的友好名称在一个密钥也包含COM端口。因为我找到的密钥是某种随机ID以及其他10个密钥,所以我上了几个级别以找到适合在其中搜索的密钥。
我想出的代码如下:
Dim searchFriendlyName = "Your Device Name".ToLower
Dim k0 = Registry.LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\Enum\USB\", False)
For Each k1Name In k0.GetSubKeyNames
Dim k1 = k0.OpenSubKey(k1Name, False)
For Each k2name In k1.GetSubKeyNames
Dim k2 = k1.OpenSubKey(k2name, False)
If k2.GetValueNames.Contains("FriendlyName") AndAlso k2.GetValue("FriendlyName").ToString.ToLower.Contains(searchFriendlyName) Then
If k2.GetSubKeyNames.Contains("Device Parameters") Then
Dim k3 = k2.OpenSubKey("Device Parameters", False)
If k3.GetValueNames.Contains("PortName") Then
For Each s In SerialPort.GetPortNames
If k3.GetValue("PortName").ToString.ToLower = s.ToLower Then
Return s
End If
Next
End If
End If
End If
Next
Next
这当然需要根据您的设备如何以及在何处显示了在注册表中,但如果你正在尝试“自动检测到被修改'Com端口的特定类型的设备,那么你应该能够做到这一点。
请记住,如果您必须递归搜索大量密钥,那么这会减慢上述解决方案的速度,因此请尝试在注册表中找到合适的位置。
我还包括WMI代码的情况下,注册表中搜索注册表搜索空手而归后:
Dim mg As New System.Management.ManagementClass("Win32_SerialPort")
Try
For Each i In mg.GetInstances()
Dim name = i.GetPropertyValue("Name")
If name IsNot Nothing AndAlso name.ToString.ToLower.Contains(searchFriendlyName.ToLower) Then
Return i.GetPropertyValue("DeviceId").ToString
End If
Next
Finally
mg.Dispose()
End Try
帕维尔的SetupDiWrap
类的伟大工程,它只是需要为Windows 7
稍微调整希望此更新能够帮助其他人挣扎(像我一样)在Windows 7中从VCP名称中获取COM端口号。
1)SP_DEVINFO_DATA
已在Windows 7中更改,总长度不再是28字节,它是长度为32个字节。这对我很有用:
private struct SP_DEVINFO_DATA
{
/// <summary>Size of the structure, in bytes.</summary>
public int cbSize;
/// <summary>GUID of the device interface class.</summary>
public Guid ClassGuid;
/// <summary>Handle to this device instance.</summary>
public int DevInst;
/// <summary>Reserved; do not use.</summary>
public ulong Reserved;
}
注意ulong代表保留,而不是int。将uint cbSize
更改为int cbSize
稍后为我保留了演员表,否则您可以将其保留为uint。
2)I也写行:
da.cbSize = (uint)Marshal.SizeOf(da);
有点不同,为清楚起见,以获得CBSIZE到32位:
da.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
3)I改变
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
static extern IntPtr SetupDiGetClassDevs(
ref Guid ClassGuid,
IntPtr Enumerator,
IntPtr hwndParent,
int Flags
);
至
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SetupDiGetClassDevs(
ref Guid ClassGuid,
UInt32 Enumerator,
IntPtr hwndParent,
UInt32 Flags
);
枚举器不再是IntPtr
,所以你需要调用SetupDiGetClassDevs
这样的:
IntPtr h = SetupDiGetClassDevs(ref guidClone, 0, IntPtr.Zero, DIGCF_PRESENT | DIGCF_PROFILE);
注“0”,而不是通过枚举器时IntPtr.Zero
。
代码现在在Windows 7中像魅力一样运行!
你为什么不编辑我的答案?让我们让人们去一个地方。 – 2013-12-14 03:17:51
我使用com0com生成的虚拟端口。 有了您能够为要命名的端口 - 所以我口字幕喜欢如下: "com0com - bus for serial port pair emulator 0 (COMA <-> COMB)"
有了上面贴WMI代码,那么你将得到名"COMA <-> COMB"
该端口。 似乎这样的结构是没有端口,但上面的代码将它视为串口...
顺便说一句,"COMA"
是一个完全有效的名称为端口...(这意味着,只查找数字在结局不够)。
所以我不知道我怎么能够可靠有效的,现有的串行端口名称,这样奇特的结构区分...
如果你是专门使用的USB设备,而不是一些其他类型的COM端口,交叉平台USB库012有一个example您可以运行,显示如何根据COM端口的USB产品ID和供应商ID查找COM端口名称。
这是一个与试图在设备管理器中使用友好名称不同但可能更好的选择。也许libusbp可以扩展为允许访问友好名称,如果你真的想要的话。
- 1. Java中COM端口的友好名称?
- 2. 如何在Windows中获得COM端口的友好名称?
- 3. 枚举友好名称
- 4. Android蓝牙友好名称
- 5. Python - 如何通过名称打开输入文件
- 6. 如何打开XML名称?
- 7. 获取窗口开始菜单项/快捷方式文件的“友好”名称
- 8. 在Delphi中从Windows消息获取串行端口友好名称
- 9. 如何通过名称
- 10. 如何通过名称
- 11. 以编程方式获取友好端口名称
- 12. Google使用OpenID的友好名称?
- 13. 设置证书友好名称
- 14. 如何提醒打开窗口的脚本名称
- 15. 如何使强制关闭窗口显示友好的应用程序名称而不是包名称?
- 16. C# - 通过反射获取简单类型的用户友好名称?
- 17. C#打开Outlook电子邮件和友好的名字加入
- 18. 名称和友好名称有什么区别?
- 19. 如何取回Facebook好友的群组名称?
- 20. 如何获得“友好”操作系统版本名称?
- 21. 如何从课堂外找回CSLA物业的友好名称?
- 22. 使用Java中的参数通过名称打开文件
- 23. 我如何在单获得串口的“友好”名称,并保持它的跨平台
- 24. 如何打开COMXX文件(串口)
- 25. 如何关闭打开的串口?
- 26. 如何用pyserial打开一个串口?
- 27. 我如何通过任何阵列的窗口window.open()被打开
- 28. 通过SSH打开端口3306
- 29. 通过命令行打开端口5900?
- 30. 通过javascript打开Facebook连接窗口?
像“COM1”,“COM2”等?或“Aten USB Serial(COM1)”。如果前者然后SerialPort1.Portname =“COM1”那么SerialPort1.open – dbasnett 2010-05-30 10:41:23
后者,不幸的是 – 2010-05-30 13:09:42
WMI - 两个查询在“root \ CIMV2”。 1)“SELECT * FROM Win32_SerialPort”或2)“SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0”。正如所建议的使用WMICodeCreator的具体细节。查询结果将需要扫描。 – dbasnett 2010-05-31 12:18:17