有没有一种简单的编程方法可以检查串口是否已经打开/正在使用?
通常我会使用以下方法:
try
{
// open port
}
catch (Exception ex)
{
// handle the exception
}
然而,我希望能够通过编程来检查,以便我可以尝试使用另一个COM端口或类似的东西。
有没有一种简单的编程方法可以检查串口是否已经打开/正在使用?
通常我会使用以下方法:
try
{
// open port
}
catch (Exception ex)
{
// handle the exception
}
然而,我希望能够通过编程来检查,以便我可以尝试使用另一个COM端口或类似的东西。
前段时间我需要寻找一种类似的方法,用于搜索设备。
我获得了可用COM端口的列表,然后简单地迭代这些端口,如果没有出现异常,我尝试与设备通信。有点粗糙,但有效。
var portNames = SerialPort.GetPortNames();
foreach(var port in portNames) {
//Try for every portName and break on the first working
}
我是这样做的:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr securityAttrs, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
后来
int dwFlagsAndAttributes = 0x40000000;
var portName = "COM5";
var isValid = SerialPort.GetPortNames().Any(x => string.Compare(x, portName, true) == 0);
if (!isValid)
throw new System.IO.IOException(string.Format("{0} port was not found", portName));
//Borrowed from Microsoft's Serial Port Open Method :)
SafeFileHandle hFile = CreateFile(@"\\.\" + portName, -1073741824, 0, IntPtr.Zero, 3, dwFlagsAndAttributes, IntPtr.Zero);
if (hFile.IsInvalid)
throw new System.IO.IOException(string.Format("{0} port is already open", portName));
hFile.Close();
using (var serialPort = new SerialPort(portName, 115200, Parity.None, 8, StopBits.One))
{
serialPort.Open();
}
我想打开下一个可用端口,方法如下。 请注意,这不是针对WPF而是Windows Forms的。 我使用可用的com端口填充了一个组合框。 然后我尝试打开第一个端口。如果失败了,我从组合框中选择下一个可用项。如果最终选择的索引没有改变,那么就没有可替代的com端口可用,我们会显示一条消息。
private void GetPortNames()
{
comboBoxComPort.Items.Clear();
foreach (string s in SerialPort.GetPortNames())
{
comboBoxComPort.Items.Add(s);
}
comboBoxComPort.SelectedIndex = 0;
}
private void OpenSerialPort()
{
try
{
serialPort1.PortName = comboBoxComPort.SelectedItem.ToString();
serialPort1.Open();
}
catch (Exception ex)
{
int SelectedIndex = comboBoxComPort.SelectedIndex;
if (comboBoxComPort.SelectedIndex >= comboBoxComPort.Items.Count - 1)
{
comboBoxComPort.SelectedIndex = 0;
}
else
{
comboBoxComPort.SelectedIndex++;
}
if (comboBoxComPort.SelectedIndex == SelectedIndex)
{
buttonOpenClose.Text = "Open Port";
MessageBox.Show("Error accessing port." + Environment.NewLine + ex.Message, "Port Error!!!", MessageBoxButtons.OK);
}
else
{
OpenSerialPort();
}
}
if (serialPort1.IsOpen)
{
StartAsyncSerialReading();
}
}
对于那些无法使用SerialPort.GetPortNames();
的人,因为他们没有针对.net framework
(就像我一样,我正在使用.Net Core而不是.Net Framework),这是我最终做的事情:
在命令提示符中,如果您键入mode,会得到类似于此的内容:
mode是一个可执行文件,位于C:\Windows\System32\mode.com
。只需使用以下正则表达式解析该可执行文件的结果:
// Code that answers the question
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = @"C:\Windows\System32\mode.com",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
proc.WaitForExit(4000); // wait up to 4 seconds. It usually takes less than a second
// get ports being used
var output = proc.StandardOutput.ReadToEnd();
List<string> comPortsBeingUsed = new List<string>();
Regex.Replace(output, @"(?xi) status [\s\w]+? (COM\d) \b ", regexCapture =>
{
comPortsBeingUsed.Add(regexCapture.Groups[1].Value);
return null;
});
foreach(var item in comPortsBeingUsed)
{
Console.WriteLine($"COM port {item} is in use");
}
mode.com
。但是请注意,对于多语言使用,因为 mode.com
是本地化的,所以正则表达式可能会在 Windows 安装时失败,当“status”的翻译不同时。 (在德语中,它是相同的单词。) - Beautymode.com
列出,而已使用的COM端口则不可见。 - Beauty我已经与这个问题斗争了几周了。感谢这里和https://www.dreamincode.net/forums/topic/91090-c%23-serial-port-unauthorizedaccessexception/网站上的建议。
最终,我想出了一个看起来可行的解决方案。
我正在开发的应用程序允许用户连接到USB设备并显示其中的数据。
我所遇到的问题。除了我正在编写的应用程序之外,我还使用另一个串行终端应用程序进行测试。有时我会忘记断开其他应用程序上使用的COM端口。如果我这样做,并尝试连接我正在编写的应用程序,我会收到“未经授权的访问异常”错误。除此之外,还会出现一些副作用,例如输出双倍的数据行以及关闭时应用程序锁定。
我的解决方案
感谢这里和其他网站上的建议,这是我的解决方案。
private void checkAndFillPortNameList()
{
SerialPort _testingSerialPort;
AvailablePortNamesFound.Clear();
List<string> availablePortNames = new List<string>();//mySerial.GetAvailablePortNames();
foreach (string portName in SerialPortDataAccess.GetAvailablePortNames())
{
try
{
_testingSerialPort = new SerialPort(portName);
_testingSerialPort.Open();
if (_testingSerialPort.IsOpen)
{
availablePortNames.Add(portName);
_testingSerialPort.Close();
}
}
catch (Exception ex)
{
}
}
availablePortNames.Sort();
AvailablePortNamesFound = new ObservableCollection<string>(availablePortNames);
}
这个程序连接到一个组合框,其中包含可供选择的串口。如果某个串口已经被其他应用程序使用,则该端口名称将不会出现在组合框中。
public void MobileMessages(string ComNo, string MobileMessage, string MobileNo)
{
if (SerialPort.IsOpen )
SerialPort.Close();
try
{
SerialPort.PortName = ComNo;
SerialPort.BaudRate = 9600;
SerialPort.Parity = Parity.None;
SerialPort.StopBits = StopBits.One;
SerialPort.DataBits = 8;
SerialPort.Handshake = Handshake.RequestToSend;
SerialPort.DtrEnable = true;
SerialPort.RtsEnable = true;
SerialPort.NewLine = Constants.vbCrLf;
string message;
message = MobileMessage;
SerialPort.Open();
if (SerialPort.IsOpen )
{
SerialPort.Write("AT" + Constants.vbCrLf);
SerialPort.Write("AT+CMGF=1" + Constants.vbCrLf);
SerialPort.Write("AT+CMGS=" + Strings.Chr(34) + MobileNo + Strings.Chr(34) + Constants.vbCrLf);
SerialPort.Write(message + Strings.Chr(26));
}
else
("Port not available");
SerialPort.Close();
System.Threading.Thread.Sleep(5000);
}
catch (Exception ex)
{
message.show("The port " + ComNo + " does not exist, change port no ");
}
}
SerialPort类有一个Open方法,会抛出一些异常。上面的参考文献包含了详细的例子。
另外,请参阅IsOpen属性。
一个简单的测试:
using System;
using System.IO.Ports;
using System.Collections.Generic;
using System.Text;
namespace SerPort1
{
class Program
{
static private SerialPort MyPort;
static void Main(string[] args)
{
MyPort = new SerialPort("COM1");
OpenMyPort();
Console.WriteLine("BaudRate {0}", MyPort.BaudRate);
OpenMyPort();
MyPort.Close();
Console.ReadLine();
}
private static void OpenMyPort()
{
try
{
MyPort.Open();
}
catch (Exception ex)
{
Console.WriteLine("Error opening my port: {0}", ex.Message);
}
}
}
}
分享一下我用过的一个简单的辅助方法:
private string portName { get; set; } = string.Empty;
/// <summary>
/// Returns SerialPort Port State (Open / Closed)
/// </summary>
/// <returns></returns>
internal bool HasOpenPort()
{
bool portState = false;
if (portName != string.Empty)
{
using (SerialPort serialPort = new SerialPort(portName))
{
foreach (var itm in SerialPort.GetPortNames())
{
if (itm.Contains(serialPort.PortName))
{
if (serialPort.IsOpen) { portState = true; }
else { portState = false; }
}
}
}
}
else { System.Windows.Forms.MessageBox.Show("Error: No Port Specified."); }
return portState;
}
注意事项:
- 对于更高级的技术,建议使用ManagementObjectSearcher Class。
更多信息请参见此处。
- 对于Arduino设备,建议保持端口开放。
- 如果需要捕获异常,请使用Try Catch块。
- 还要检查:"TimeoutException"
- 有关如何获取SerialPort(Open)异常的更多信息,请参见此处。
foreach (var portName in Serial.GetPortNames()
{
SerialPort port = new SerialPort(portName);
if (port.IsOpen){
/** do something **/
}
else {
/** do something **/
}
}