取得所有連接到電腦上的 Serial Port 詳細資訊

部分解

方法一

最簡單的方法,就是直接利用 SerialPort 這個 Class 來取得。

// A string array consists of port names.
string[] ports2 = SerialPort.GetPortNames(); 

所以假如你電腦上連接 Arduino(COM7),我們就可以把收到的 Port 放在一個 ComboBox 下拉式選單裡。

Port Name

摁?要是不看裝置管理員還真不知道 Arduino 被放在 COM7,這種方式雖然可行但太不直觀,於是我們想要取得更詳細一點的資訊,這時就可以利用方法二。

方法二

這個方法是利用 ManagementObjectSearcher 這個 Class 去向電腦撈取所有連接裝置的詳細資料。DeviceID 就是之後要連 Serial Port 時可以識別的字串,而 Caption 就是我們想要的連接埠註解,程式如下。

var searcher = new ManagementObjectSearcher("SELECT DeviceID,Caption FROM WIN32_SerialPort");
foreach (ManagementObject port in searcher.Get())
{
    // ex: COM7
    string name = port.GetPropertyValue("DeviceID").ToString();
    // ex: Arduino Uno (COM7)
    string description = port.GetPropertyValue("Caption").ToString();
    // do what ever you want...  
} 

讓我們來看看結果,成功…嗎?似乎少了什麼,第一張圖中的 COM6 這個 Port 不見了!

Port Descriptions

事實上,連接在 COM6 上的是一個 USB 轉 TTL/RS232 序列傳輸介面,由於他只是一個類似轉接頭的東西,並不是一個裝置,所以用第二個方法會把這個 Port 給漏掉,不過如果沒有此需求的話,其實這樣就可以了。

用這個方法記得要在專案中加入參考 System.Management,才可以編譯成功。位置在主選單的專案→加入參考→組件→勾選 System.Management→確定。

完整解

為了找到 USB 轉 TTL/RS232 序列傳輸介面,只好沿用第一個方法補上。另外,為了存放這些 Port 的名稱跟描述,自己寫了一個 ComProt 的結構去做存取。

// custom struct with our desired values
struct ComPort
{
    public string name;
    public string description;
    
    public ComPort(string name, string description)
    {
        this.name = name;
        this.description = description;
    }
}
// Method 2 function
private List<ComPort> GetSerialPort2()
{
    List<ComPort> ports = new List<ComPort>();
    var searcher = new ManagementObjectSearcher("SELECT DeviceID,Caption FROM WIN32_SerialPort");
    foreach (ManagementObject port in searcher.Get())
    {
        // show the service
        ComPort c = new ComPort();
        c.name = port.GetPropertyValue("DeviceID").ToString();
        c.description = port.GetPropertyValue("Caption").ToString();
        ports.Add(c);
    }
    return ports;
}
private List<ComPort> GetAllPorts()
{
    // Method 2
    List<ComPort> ports = GetSerialPort2();
    foreach (ComPort port in ports)
    {
      ports.Add(port);
    }
    // Method 1
    string[] ports2 = SerialPort.GetPortNames();
    foreach (string port in ports2)
    {
      // Only need to check the Port Name
        if (!ports.Exists(x => x.name == port))
        {
            ports.Add(new ComPort(port, port));
        }
    }
    return ports;
} 

在 GetAllPorts 涵式中,做了一些檢查以免有 Port 重複出現,這樣就可以獲取到所有連接到電腦上的裝置了,把得到的 Port 們放到一個 ComboBox 下拉式選單裡。

搞定!

題外話

關於方法二,其實是利用了 Windows 內建的 WMI 物件,想要快速查看某個類別裡有什麼東西時,也可以直接打開 Powershell 使用 gwmi 指令,例如方法二中我們想看的 Win32_DriveDisk

PS> gwmi Win32_DriveDisk

參考資料

  1. System.IO.Ports.SerialPort – Microsoft Docs

  2. ManagementObjectSearcher Class – Microsoft Docs

  3. 取得 WMI 物件 (Get-WmiObject) – Microsoft Docs