C# 检查 COM(串行)端口是否已打开

发布于 2024-07-06 09:26:56 字数 217 浏览 5 评论 0原文

有没有一种简单的方法可以以编程方式检查串行 COM 端口是否已打开/正在使用?

通常我会使用:

try
{
    // open port
}
catch (Exception ex)
{
    // handle the exception
}

但是,我想以编程方式进行检查,以便我可以尝试使用另一个 COM 端口或类似端口。

Is there an easy way of programmatically checking if a serial COM port is already open/being used?

Normally I would use:

try
{
    // open port
}
catch (Exception ex)
{
    // handle the exception
}

However, I would like to programatically check so I can attempt to use another COM port or some such.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

御守 2024-07-13 09:26:56

我前段时间需要类似的东西来搜索设备。

我获得了可用 COM 端口的列表,然后简单地迭代它们,如果它没有抛出异常,我会尝试与设备进行通信。 有点粗糙但有效。

var portNames = SerialPort.GetPortNames();

foreach(var port in portNames) {
    //Try for every portName and break on the first working
}

I needed something similar some time ago, to search for a device.

I obtained a list of available COM ports and then simply iterated over them, if it didn't throw an exception i tried to communicate with the device. A bit rough but working.

var portNames = SerialPort.GetPortNames();

foreach(var port in portNames) {
    //Try for every portName and break on the first working
}
念﹏祤嫣 2024-07-13 09:26:56

我就是这样做的:

      [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();
        }

This is how I did it:

      [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);

then later on

        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();
        }
那支青花 2024-07-13 09:26:56

对于无法使用 SerialPort.GetPortNames(); 的人,因为他们不是针对 .net 框架(就像在我的例子中,我使用的是 .Net Core 而不是 .Net Framework)这就是我最终要做的:

在命令提示符下,如果您键入模式,您会得到如下内容:

在此处输入图像描述

模式是位于 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");
}

For people that cannot use SerialPort.GetPortNames(); because they are not targeting .net framework (like in my case I am using .Net Core and NOT .Net Framework) here is what I ended up doing:

In command prompt if you type mode you get something like this:

enter image description here

mode is an executable located at C:\Windows\System32\mode.com. Just parse the results of that executable with a regex like this:

// 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();

Now if you want to parse the output this is how I do it:

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(
quot;COM port {item} is in use");
}
淡水深流 2024-07-13 09:26:56

我想打开下一个可用端口并这样做。
请注意,这不是针对 WPF 而是针对 Windows 窗体。
我用可用的 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();
    }
}

I wanted to open the next available port and did it like this.
Please note, is it not for WPF but for Windows Forms.
I populated a combobox with the com ports available.
Then I try to open the first one. If it fails, I select the next available item from the combobox. If the selected index did not change in the end, there were no alternate com ports available and we show a message.

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();
    }
}
不寐倦长更 2024-07-13 09:26:56

SerialPort 类 有一个 打开方法,这会抛出一些异常。
上面的参考文献包含详细的示例。

另请参阅 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);
        }
    }
  }
}

The SerialPort class has an Open method, which will throw a few exceptions.
The reference above contains detailed examples.

See also, the IsOpen property.

A simple test:

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);
        }
    }
  }
}
标点 2024-07-13 09:26:56

分享对我有用的方法(一个简单的辅助方法):

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 类

更多信息此处。

- 对于 Arduino 设备,我会将端口保持打开状态。

- 如果需要捕获异常,建议使用 Try Catch 块。

- 还检查:“TimeoutException”

- 有关如何获取 SerialPort(开放)异常的更多信息
此处

Sharing what worked for me (a simple helper method):

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

Notes:

- For more advanced technique(s) I recommend using ManagementObjectSearcher Class.

More info Here.

- For Arduino devices I would leave the Port Open.

- Recommend using a Try Catch block if you need to catch exceptions.

- Check also: "TimeoutException"

- More information on how to get SerialPort (Open) Exceptions Here.

瀟灑尐姊 2024-07-13 09:26:56
  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 ");
        }
    }
  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 ");
        }
    }
孤独患者 2024-07-13 09:26:56

我已经和这个问题斗争了几个星期了。 感谢此处和网站上的建议, https://www.dreamincode.net/forums/topic/91090-c%23-serial-port-unauthorizedaccessexception/

我终于想出了一个似乎可行的解决方案。

我正在开发的应用程序允许用户连接到 USB 设备并显示其中的数据。

我正在解决的问题。除了我正在编写的应用程序之外,我还使用另一个串行终端应用程序来进行测试。 有时我忘记断开其他应用程序正在使用的 COM 端口。 如果我这样做,并尝试连接我正在编写的应用程序,我将收到“UnAuthorizedAccessException”错误。 伴随此异常而来的是一些副作用,例如吐出双行数据以及应用程序在关闭时锁定。

我的解决方案

感谢此处的建议和引用的其他网站,这是我的解决方案。

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

该例程连接到一个组合框,其中包含可供选择的可用端口。 如果某个端口已被其他应用程序使用,则该端口名称将不会出现在组合框中。

I have been fighting with this problem for a few weeks now. Thanks to the suggestions on here and from the site, https://www.dreamincode.net/forums/topic/91090-c%23-serial-port-unauthorizedaccessexception/ .

I finally came up with a solution that seems to work.

The application I am working on allows a user to connect to a USB device and display data from it.

The Problem I was battling. Along side the application I am writing, I use another serial terminal application for doing my testing. Sometimes I forget to disconnect the COMport being used on the other application. If I do, and try to connect with the application I am writing, I would get an “UnAuthorizedAccessException” error. Along with this exception came some side effects, such as double lines of data being spit out and the application locking up on closing down.

My Solution

Thanks to the advice on here and the other site referenced, this was my solution.

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

This routine connects to a combobox which holds the available Comports for selection. If a Comport is already, in use by another application, that port name will not appear in the combo box.

围归者 2024-07-13 09:26:56

您可以尝试以下代码来检查端口是否已打开。 我假设您不知道具体要检查哪个端口。

foreach (var portName in Serial.GetPortNames()
{
  SerialPort port = new SerialPort(portName);
  if (port.IsOpen){
    /** do something **/
  }
  else {
    /** do something **/
  }
}

You can try folloing code to check whether a port already open or not. I'm assumming you dont know specificaly which port you want to check.

foreach (var portName in Serial.GetPortNames()
{
  SerialPort port = new SerialPort(portName);
  if (port.IsOpen){
    /** do something **/
  }
  else {
    /** do something **/
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文