在Windows上检测所有可用串口的正确方法是什么?

10

在Windows下列出串口的几种方法,但我不确定哪种是正确的方式:能够检测到所有可用的串口。

一个很好的代码示例是http://www.naughter.com/enumser.html - 这里有9(九!)种枚举串行设备的方法。

问题是:最优的方法是什么。

要求:

  • 不要打开端口以检查它们是否可用。
  • 能够检测到名称与COMx不同的端口。
  • 适用于Windows XP SP2或更高版本
7个回答

9
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

}

4
这行代码并不起作用:lpTargetPath [10000]; - HS.
更倾向于使用动态的lpTargetPath,然后在INSUFFICIENT_BUFFER分支中:lpTargetPath = realloc(lpTargetPath, bufSize); bufSize*=2; i--; - Sam Ginrich

6

修改了 @Dženan 的答案,使用了宽字符并返回整数列表。

#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;
}

5
如果您可以访问注册表,HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM键包含Windows当前支持的COM端口列表(在某些情况下,这些信息可能过时/不正确;例如,我怀疑当提供串行端口的即插即用设备未完成检测/安装或最近已被移除时)。
这是.NET Framework的SerialPort.GetPortNames()方法报告可用COM端口的方式,上述信息来自链接页面。

在Windows 10中找不到此注册表路径。 - Sam Ginrich
@SamGinrich:我在W11上也没有看到它。 - Doc

4
这是@michael-jacob-mathew答案的现代化版本:
#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;
}

在我的电脑上,它会产生以下输出:

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

3
串行端口是非常简单的设备,属于计算机硬件的石器时代。它们不支持即插即用,无法检测到有人插入设备。你唯一能做的就是发现哪些端口可用,SerialPort.GetPortNames()函数返回一个列表。某些USB仿真器可以为端口名称生成描述性名称,你可以使用WMI中的Win32_SerialPort类来发现它们。
所有这些都无法帮助你发现哪个COM端口连接到了特定的设备。只有人知道,她将电缆物理地插入连接器。你需要提供一个配置界面,让用户选择端口号。一个下拉框可以完成这项工作。保存选择在你的配置数据中,很可能下次程序启动时设备仍然连接在同一端口上。

我使用SerialPort.GetPortNames()。 - dbasnett
6
串口实在是太被低估了!有时候我不想要那些复杂的即插即用设备......我只想要插上一根电缆然后就可以打字。RS232万岁! - Lightness Races in Orbit
@LightnessRacesinOrbit 当你需要尝试检测串口何时被添加时,串口是很好的,但一旦处于这种位置,它们就会变成地狱。 - Pharap
有一种方法可以使用RegisterDeviceNotificationA(https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerdevicenotificationa?redirectedfrom=MSDN)检测到新的COM端口可用。 - Pedro Ferreira

0
你可以检查Windows注册表来列出所有的COM端口。这是我的代码 > github文件

-3
CUIntArray ports;
EnumerateSerialPorts(ports);

for (int i = 0; i<ports.GetSize(); i++)
{
    CString str;
    str.Format(_T("COM%d"), ports.ElementAt(i));
    m_ctlPort.AddString(str);
}

1
或者准确地说,这指的是哪个库。 - Mikhail

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接