nom convivial = le nom qui apparaît dans le "Gestionnaire de périphériques" sous « Ports (COM & LPT)Comment ouvrir un port série par nom convivial?
EDIT:... Deux solutions fournies ci-dessous un avec WMI et une autre avec SetupAPI
nom convivial = le nom qui apparaît dans le "Gestionnaire de périphériques" sous « Ports (COM & LPT)Comment ouvrir un port série par nom convivial?
EDIT:... Deux solutions fournies ci-dessous un avec WMI et une autre avec SetupAPI
Essayez d'exécuter une requête WMI sur la classe Win32_SerialPort Télécharger WmiCodeCreator d'expérimenter et de générer automatiquement le code C#
Je ne sais pas pourquoi, mais je ne pouvais pas trouver autre chose que COM1 sur mon système en utilisant WMI. Même en spécifiant un port connu comme 'Select * from Win32_SerialPort où Name = 'COM11'' n'a rien retourné. La solution setupapi a parfaitement fonctionné. Une idée de pourquoi WMI ne connaît que COM1? –
@Tim - jamais entendu parler de cet échec avant, aucune idée. –
@Hans Passant: Selon ce [link] (http://www.creativecodedesign.com/node/39), l'utilisation de la requête WMI "SELECT * FROM Win32_SerialPort" ne retourne pas toujours tous les ports COM. Le lien fournit une solution alternative. – markyd13
affichage du code de ce soir, pour le plaisir de tout le monde:..
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;
}
}
Je voulais juste revenir et dire que j'ai utilisé la merde de ce code. J'ai eu beaucoup de projets travaillant avec des périphériques série dernièrement. MERCI! –
Merci pour cela, plutôt tardivement. – Robinson
Je n'arrive pas à faire fonctionner cet exemple ... Qu'est-ce qui est censé être passé en tant que friendlyNamePrefix? J'ai essayé de passer au nom du port mais il renvoie toujours juste :( – NickG
Je sais que cela a été publié en C#, mais je suis certain que cela peut facilement être converti ...
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
Il trouve tous mes ports COM, modem, série, USB et Bluetooth.
Le code de This article a fait le travail pour moi (il lie à ce poste, mais ne semble pas avoir fourni une réponse ici lui-même). Voici le code de l'auteur:
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;
}
}
Utilisation:
foreach (COMPortInfo comPort in COMPortInfo.GetCOMPortsInfo())
{
Console.WriteLine(string.Format("{0} – {1}", comPort.Name, comPort.Description));
}
Cela a fonctionné parfaitement! Merci de reporter cela! –
Vous pouvez également envisager d'utiliser le registre comme je l'ai trouvé WMI assez lent (5 ou 6 secondes)
Dans mon cas Je voulais identifier le nom du port COM d'un périphérique avec un nom convivial connu. En utilisant regedit j'ai cherché dans le registre le nom convivial dans une clé qui contenait aussi le port COM. Parce que la clé que j'ai trouvée était une sorte d'ID aléatoire avec 10 autres, j'ai remonté quelques niveaux pour trouver une clé appropriée pour chercher à l'intérieur.
Le code que je suis venu avec est la suivante:
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
Ce sera bien sûr besoin d'être modifié en fonction de comment et où votre appareil apparaît dans le registre, mais si vous essayez de « détection automatique "Le Port Com d'un type spécifique de divin alors vous devriez être en mesure de faire ce travail. Rappelez-vous que si vous devez effectuer une recherche récursive sur un grand nombre de clés, cela ralentira la solution ci-dessus. Essayez donc de trouver le bon emplacement dans le registre.
J'ai aussi inclus le code WMI après la recherche de registre dans le cas où la recherche de registre est venu vide:
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
classe SetupDiWrap
de Pavel fonctionne très bien, il a juste besoin de quelques petits réglages pour Windows 7.
Heureusement, cette mise à jour aidera d'autres personnes qui luttent (comme moi) pour obtenir des numéros de port COM à partir de noms VCP dans Windows 7.
1) Le SP_DEVINFO_DATA
a changé dans Windows 7, la longueur totale n'est plus 28 octets, il est 32 octets de long. C'est ce qui fonctionne pour moi:
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;
}
Note ulong pour Réservé au lieu d'un int.Changer uint cbSize
à int cbSize
m'a sauvé un casting plus tard, sinon vous pouvez le laisser comme uint.
2) J'ai écrit aussi la ligne:
da.cbSize = (uint)Marshal.SizeOf(da);
un peu différent, pour plus de clarté, pour obtenir le cbSize à 32 bits:
da.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
3) J'ai changé
[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
);
Le recenseur n'est plus IntPtr
, vous devez donc appeler SetupDiGetClassDevs
comme ceci:
IntPtr h = SetupDiGetClassDevs(ref guidClone, 0, IntPtr.Zero, DIGCF_PRESENT | DIGCF_PROFILE);
Note « 0 » au lieu de IntPtr.Zero
lors du passage du recenseur.
Le code fonctionne maintenant comme un charme dans Windows 7! J'utilise les ports virtuels générés par com0com
Pourquoi ne modifiez-vous pas ma réponse? Faisons les gens aller à un endroit. –
Avec que vous êtes en mesure de nommer les ports que vous voulez - donc je l'ai sous-titres port comme suit: "com0com - bus for serial port pair emulator 0 (COMA <-> COMB)"
Avec le code affiché ci-dessus WMI vous obtiendrez alors le nom "COMA <-> COMB"
pour ce port. Il semble que ces constructions ne sont pas des ports, mais le code ci-dessus le traitera comme port série ...
BTW, "COMA"
est un nom totalement valide pour un port ... (cela signifie, la recherche de numéros seulement à la la fin ne suffit pas).
Je me demande comment je peux distinguer de façon fiable entre un valide, existant nom du port série et ces constructions étranges ...
Pourquoi définissez-vous la "réponse n'est pas utile"? – Mich0815
Mich0815 - Je suspecte parce que ceci te donne juste un autre port faux et un nom pour relayer au port inconnu. Il aurait toujours le problème de devoir découvrir automatiquement le port réel du périphérique pour configurer cette carte en premier lieu. – etropic
Si vous utilisez spécifiquement les périphériques USB et non pas un autre type de port COM, la croisée bibliothèque USB plate-forme libusbp a un example vous pouvez exécuter qui montre comment trouver le nom du port COM basé sur l'ID du produit USB et l'ID du fournisseur du port COM.
C'est un choix différent mais probablement préférable à l'utilisation du nom convivial dans le Gestionnaire de périphériques. Peut-être que libusbp pourrait être étendu pour permettre l'accès au nom convivial si vous le voulez vraiment.
Comme "COM1", "COM2", etc? Ou "Aten USB Serial (COM1)". Si l'ancien puis SerialPort1.Portname = "COM1" alors SerialPort1.open – dbasnett
Ce dernier, malheureusement –
WMI - deux requêtes dans "root \ CIMV2". 1) "SELECT * FROM Win32_SerialPort" ou 2) "SELECT * FROM Win32_PnPEntity O Conf ConfigManagerErrorCode = 0". Comme cela a été suggéré, utilisez WMICodeCreator pour plus de détails. Les résultats des requêtes devront être analysés. – dbasnett