What is proper way to detect all available serial ports on Windows?

43,551

Solution 1

void SelectComPort() //added function to find the present serial 
{

    TCHAR lpTargetPath[5000]; // buffer to store the path of the COMPORTS
    DWORD test;
    bool gotPort=0; // in case the port is not found

    for(int i=0; i<255; i++) // checking ports from COM0 to COM255
    {
        CString str;
        str.Format(_T("%d"),i);
        CString ComName=CString("COM") + CString(str); // converting to COM0, COM1, COM2

        test = QueryDosDevice(ComName, (LPSTR)lpTargetPath, 5000);

            // Test the return value and error if any
        if(test!=0) //QueryDosDevice returns zero if it didn't find an object
        {
            m_MyPort.AddString((CString)ComName); // add to the ComboBox
            gotPort=1; // found port
        }

        if(::GetLastError()==ERROR_INSUFFICIENT_BUFFER)
        {
            lpTargetPath[10000]; // in case the buffer got filled, increase size of the buffer.
            continue;
        }

    }

    if(!gotPort) // if not port
    m_MyPort.AddString((CString)"No Active Ports Found"); // to display error message incase no ports found

}

Solution 2

If you can access the registry, the HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM key contains a list of COM ports Windows currently supports (in some cases, this information may be stale/incorrect; like, I suspect, when a plug & play device providing serial ports has not completed detection/installation or has been recently removed).

This is the way .NET Framework's SerialPort.GetPortNames() method reports available COM ports, and the above information is derived from the linked page.

Solution 3

Modified @Dženan answer to use wide characters and returning list of ints

#include <string>
#include <list>

list<int> getAvailablePorts()
{
    wchar_t lpTargetPath[5000]; // buffer to store the path of the COM PORTS
    list<int> portList;

    for (int i = 0; i < 255; i++) // checking ports from COM0 to COM255
    {
        wstring str = L"COM" + to_wstring(i); // converting to COM0, COM1, COM2
        DWORD res = QueryDosDevice(str.c_str(), lpTargetPath, 5000);

        // Test the return value and error if any
        if (res != 0) //QueryDosDevice returns zero if it didn't find an object
        {
            portList.push_back(i);
            //std::cout << str << ": " << lpTargetPath << std::endl;
        }
        if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
        {
        }
    }
    return portList;
}

Solution 4

This is a modernized version of @michael-jacob-mathew's answer:

#include <iostream>
#include <string>
#include <Windows.h>

bool SelectComPort() //added function to find the present serial 
{
    char lpTargetPath[5000]; // buffer to store the path of the COMPORTS
    bool gotPort = false; // in case the port is not found

    for (int i = 0; i < 255; i++) // checking ports from COM0 to COM255
    {
        std::string str = "COM" + std::to_string(i); // converting to COM0, COM1, COM2
        DWORD test = QueryDosDevice(str.c_str(), lpTargetPath, 5000);

        // Test the return value and error if any
        if (test != 0) //QueryDosDevice returns zero if it didn't find an object
        {
            std::cout << str << ": " << lpTargetPath << std::endl;
            gotPort = true;
        }

        if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
        {
        }
    }

    return gotPort;
}

It produces the following output on my computer:

COM1: \Device\Serial0
COM3: \Device\VCP0

Solution 5

Serial ports are very simple devices, dating from the stone age of computing hardware. They don't support Plug & Play, there is no way to tell that somebody plugged in a device. The only thing you can do is discover what ports are available, the SerialPort.GetPortNames() returns the list. Some USB emulators can generate a descriptive name to go with the port name, you can discover those with WMI, Win32_SerialPort class.

None of which helps you discover what COM port is connected to a particular device. Only a human knows, she physically plugged the cable in the connector. You'll need to provide a config UI that lets the user select the port number. A combo box gets the job done. Save the selection in your config data, it is very likely that the device is still connected to the same port the next time your program starts.

Share:
43,551
sorin
Author by

sorin

Another geek still trying to decipher the meaning of “42”. It seems that amount his main interest are: online communities of practice and the way they evolve in time product design, simplicity in design and accessibility productivity and the way the IT solutions are impacting it

Updated on January 06, 2021

Comments

  • sorin
    sorin over 3 years

    There are several ways to list serial ports under Windows but I'm not sure what is the proper way: the way that does detect all serial ports that are available.

    One good code example is http://www.naughter.com/enumser.html - where there are 9 (nine!) ways of enumerating serial devices.

    The question is: what is the optimal way of doing it.

    Requirements:

    • to not open ports in order to check if they are available.
    • to be able to detect ports with different names than COMx.
    • to work on Windows XP SP2 or above
  • dbasnett
    dbasnett about 14 years
    I use SerialPort.GetPortNames().
  • Lightness Races in Orbit
    Lightness Races in Orbit over 8 years
    Serial ports are so under-rated! Sometimes I don't want any of that complicated plug & play malarky.. I just want to plug in a cable and type. Long live RS232!
  • Pharap
    Pharap over 6 years
    @LightnessRacesinOrbit Com ports are fine until you're in the position where you have to try to detect when one has been added, then they're hell.
  • Mikhail
    Mikhail over 6 years
    Or exactly which library this references
  • HS.
    HS. over 5 years
    This line does not do anything: lpTargetPath[10000];
  • Sam Ginrich
    Sam Ginrich about 2 years
    Don't see this registry path in windows 10
  • Sam Ginrich
    Sam Ginrich about 2 years
    Would prefer to work with dynamic lpTargetPath, then in the INSUFFICIENT_BUFFER branch: lpTargetPath = realloc(lpTargetPath, bufSize); bufSize*=2; i--;