C++ 在 Windows 上检测所有可用串行端口的正确方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2674048/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is proper way to detect all available serial ports on Windows?
提问by sorin
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.
有几种方法可以在 Windows 下列出串行端口,但我不确定什么是正确的方法:确实检测所有可用串行端口的方法。
One good code example is http://www.naughter.com/enumser.html- where there are 9 (nine!) ways of enumerating serial devices.
一个很好的代码示例是http://www.naughter.com/enumser.html- 其中有 9(九种!)枚举串行设备的方法。
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
- 不打开端口以检查它们是否可用。
- 能够检测名称与
COMx
. - 在 Windows XP SP2 或更高版本上工作
回答by Michael Jacob Mathew
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
}
回答by Doc
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).
如果您可以访问注册表,该HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
键包含 Windows 当前支持的 COM 端口列表(在某些情况下,此信息可能过时/不正确;例如,我怀疑,当提供串行端口的即插即用设备尚未完成检测时/安装或最近已删除)。
This is the way .NET Framework's SerialPort.GetPortNames()
method reports available COM ports, and the above information is derived from the linked page.
这是 .NET Framework 的SerialPort.GetPortNames()
方法报告可用 COM 端口的方式,以上信息来自链接页面。
回答by Hans Passant
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.
串口是非常简单的设备,可以追溯到计算硬件的石器时代。他们不支持即插即用,无法知道有人插入了设备。您唯一能做的就是发现哪些端口可用,SerialPort.GetPortNames() 返回列表。一些 USB 模拟器可以生成一个描述性名称来配合端口名称,您可以发现那些带有 WMI、Win32_SerialPort 类的模拟器。
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 verylikely that the device is still connected to the same port the next time your program starts.
这些都无法帮助您发现连接到特定设备的 COM 端口。只有人类知道,她将电缆实际插入连接器中。您需要提供一个配置 UI,让用户选择端口号。组合框可以完成工作。将选择保存在您的配置数据中,下次程序启动时,该设备很可能仍连接到同一端口。
回答by D?enan
This is a modernized version of @michael-jacob-mathew's answer:
这是@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;
}
It produces the following output on my computer:
它在我的电脑上产生以下输出:
COM1: \Device\Serial0
COM3: \Device\VCP0
回答by Zby?ek Zapadlík
Modified @D?enan answer to use wide characters and returning list of ints
修改 @D?enan 答案以使用宽字符并返回整数列表
#include <string>
#include <list>
list<int> RS232_Port::getAvailablePorts()
{
wchar_t lpTargetPath[5000]; // buffer to store the path of the COMPORTS
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;
}
回答by The Learner
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);
}