TK.
TK.

Reputation: 47913

C# check if a COM (Serial) port is already open

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.

Upvotes: 25

Views: 105019

Answers (9)

Mike
Mike

Reputation: 19

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.

Upvotes: 0

Jack
Jack

Reputation: 161

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

Upvotes: 1

Tono Nam
Tono Nam

Reputation: 36080

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($"COM port {item} is in use");
}

Upvotes: 1

Farrukh Azad
Farrukh Azad

Reputation: 19

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

Upvotes: 0

user12761381
user12761381

Reputation:

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.

Upvotes: 0

Jeff
Jeff

Reputation: 677

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

Upvotes: 15

Funky81
Funky81

Reputation: 1677

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 **/
  }
}

Upvotes: -2

gimel
gimel

Reputation: 86492

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

Upvotes: 0

Fionn
Fionn

Reputation: 11285

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
}

Upvotes: 18

Related Questions