How to get a friendly COM port name in Windows?

I have a GSM modem connected via USB. The modem creates 2 serial ports. The first is automatically connected to the modem, the second is displayed in the device manager as "HUAWEI Mobile Connect - PC interface for 3G PC (COM6)"

The second port is used to receive important information from the modem, for example, signal quality; send and receive text messages; and a host of other features.

I am writing an application that completes some of the functions provided by the second port. What I need is a valid fire alarm method that indicates which COM port is spare. Port iteration and checking the response to "ATE0" are not enough. The modem port, as a rule, has a lower number, and when the connection to the dial-up connection is inactive, it will respond to "ATE0" in the same way as the second port.

What I was going to do was iterate through the ports and check their friendly name, as shown in the device manager. Thus, I can associate a port in my application with a port labeled "HUAWEI Mobile Connect - PC-to-PC Interface (COM6)" in the device manager. I just did not find any information that would allow me to get this name programmatically.

+12
windows serial-port device-manager
source share
6 answers

Once upon a time, I wrote a utility for a client to do just that, but for GPS, not for a modem.

I just looked at it, and bits that might be useful are:

GUID guid = GUID_DEVCLASS_PORTS; SP_DEVICE_INTERFACE_DATA interfaceData; ZeroMemory(&interfaceData, sizeof(interfaceData)); interfaceData.cbSize = sizeof(interfaceData); SP_DEVINFO_DATA devInfoData; ZeroMemory(&devInfoData, sizeof(devInfoData)); devInfoData.cbSize = sizeof(devInfoData); if(SetupDiEnumDeviceInfo( hDeviceInfo, // Our device tree nDevice, // The member to look for &devInfoData )) { DWORD regDataType; BYTE hardwareId[300]; if(SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, hardwareId, sizeof(hardwareId), NULL)) { ... 

(You call this bit in a loop in nDevice increments)

and then

 BYTE friendlyName[300]; if(SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, friendlyName, sizeof(friendlyName), NULL)) { strFriendlyNames += (LPCTSTR)friendlyName; strFriendlyNames += '\n'; } 

which finds the name of the device.

Hope this helps you in the right direction.

+7
source share

After you have identified the serial port device, you want (by looking at its friendly name, checking its parent device, etc.), the correct way to get the port name is likely to be as follows:

  • invoke SetupDiOpenDevRegKey(hDevInfo, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) to get the HKEY for the so-called device key
  • query this registry key for REG_SZ "Port Name"
  • don't forget to close HKEY :)

However, this may require so many interactions in C # that it’s not even funny, so I don’t blame you if you stick to the string parsing solution.

+3
source share

The information provided by Will Dean was most helpful. This is the code that ultimately worked for me. Everything in the PInvoke class was taken verbatim from http://www.pinvoke.net . I had to change the data type here or there to make it work (for example, when using an enumeration instead of uint), but this should be easy to figure out.

 internal static string GetComPortByDescription(string Description) { string Result = string.Empty; Guid guid = PInvoke.GUID_DEVCLASS_PORTS; uint nDevice = 0; uint nBytes = 300; byte[] retval = new byte[nBytes]; uint RequiredSize = 0; uint PropertyRegDataType = 0; PInvoke.SP_DEVINFO_DATA devInfoData = new PInvoke.SP_DEVINFO_DATA(); devInfoData.cbSize = Marshal.SizeOf(typeof(PInvoke.SP_DEVINFO_DATA)); IntPtr hDeviceInfo = PInvoke.SetupDiGetClassDevs( ref guid, null, IntPtr.Zero, PInvoke.DIGCF.DIGCF_PRESENT); while (PInvoke.SetupDiEnumDeviceInfo(hDeviceInfo, nDevice++, ref devInfoData)) { if (PInvoke.SetupDiGetDeviceRegistryProperty( hDeviceInfo, ref devInfoData, PInvoke.SPDRP.SPDRP_FRIENDLYNAME, out PropertyRegDataType, retval, nBytes, out RequiredSize)) { if (System.Text.Encoding.Unicode.GetString(retval).Substring(0, Description.Length).ToLower() == Description.ToLower()) { string tmpstring = System.Text.Encoding.Unicode.GetString(retval); Result = tmpstring.Substring(tmpstring.IndexOf("COM"),tmpstring.IndexOf(')') - tmpstring.IndexOf("COM")); } // if retval == description } // if (PInvoke.SetupDiGetDeviceRegistryProperty( ... SPDRP_FRIENDLYNAME ... } // while (PInvoke.SetupDiEnumDeviceInfo(hDeviceInfo, nDevice++, ref devInfoData)) PInvoke.SetupDiDestroyDeviceInfoList(hDeviceInfo); return Result; } 

I think the line Result = tmpstring.Substring(tmpstring.IndexOf("COM"),tmpstring.IndexOf(')') - tmpstring.IndexOf("COM")); a bit awkward, suggestions for cleaning it up will be appreciated.

Thank you for your help in this matter. Without you, I will still look for google.

+2
source share

Glad it worked.

You can try:

Regex.Match (tmpstring, @ "COM \ s \ d +"). Tostring ()

to match your string.

As a .NET style point, I would add “using System.Text” and I would not start the names of local variables with capitals, and if I felt really virtuous, I would probably put SetupDiDestroyDeviceInfoList in the final {}.

+1
source share

C ++ version based on @Will Dean answer.

 #include <windows.h> #include <initguid.h> #include <devguid.h> #include <setupapi.h> void enumerateSerialPortsFriendlyNames() { SP_DEVINFO_DATA devInfoData = {}; devInfoData.cbSize = sizeof(devInfoData); // get the tree containing the info for the ports HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0, nullptr, DIGCF_PRESENT ); if (hDeviceInfo == INVALID_HANDLE_VALUE) { return; } // iterate over all the devices in the tree int nDevice = 0; while (SetupDiEnumDeviceInfo(hDeviceInfo, // Our device tree nDevice++, // The member to look for &devInfoData)) { DWORD regDataType; DWORD reqSize = 0; // find the size required to hold the device info SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, nullptr, nullptr, 0, &reqSize); BYTE hardwareId[reqSize > 1 ? reqSize : 1]; // now store it in a buffer if (SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, hardwareId, sizeof(hardwareId), nullptr)) { // find the size required to hold the friendly name reqSize = 0; SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, nullptr, 0, &reqSize); BYTE friendlyName[reqSize > 1 ? reqSize : 1]; // now store it in a buffer if (!SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, friendlyName, sizeof(friendlyName), nullptr)) { // device does not have this property set memset(friendlyName, 0, reqSize > 1 ? reqSize : 1); } // use friendlyName here } } } 
+1
source share

The method sent by LiGenChen is used . The ComPortSetupAPISetupDiClassGuids method gave a better time and friendly name.

0
source share

All Articles