User Tools

Site Tools

prog:csharp:2024-821-01:index

C#: 取得所有連接到電腦的 Serial Port 詳細資訊 (2024-08-21)

部分解

方法一

  • 最簡單的方法,就是直接利用 SerialPort 這個 Class 來取得。
  • // A string array consists of port names.
    string[] ports2 = SerialPort.GetPortNames(); 
  • 所以假如你電腦上連接 Arduino(COM7),我們就可以把收到的 Port 放在一個 ComboBox 下拉式選單裡。
  • 摁?要是不看裝置管理員還真不知道 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 不見了!
  • 事實上,連接在 COM6 上的是一個 USB 轉 TTL/RS232 序列傳輸介面,由於他只是一個類似轉接頭的東西,並不是一個裝置,所以用第二個方法會把這個 Port 給漏掉,不過如果沒有此需求的話,其實這樣就可以了。
  • 用這個方法記得要在專案中加入參考 System.Management,才可以編譯成功。位置在主選單的專案→加入參考→組件→勾選 System.Management→確定。

完整解

  • 為了找到 USB 轉 TTL/RS232 序列傳輸介面,只好沿用第一個方法補上。另外,為了存放這些 Port 的名稱跟描述,自己寫了一個 ComProt 的結構去做存取。
  •         /*************************************************** 
             * 搜尋所有COM Port 
             * 入口: Task_GetAllComPorts()
             *************************************************** 
            */
            List<ComPortQuery> gAllComPorts;
            struct ComPortQuery
            {
                public string name;
                public string description;
    
                public ComPortQuery(string name, string description)
                {
                    this.name = name;
                    this.description = description;
                }
            }
            // Method 2 function
            private List<ComPortQuery> GetSerialPort2()
            {
                List<ComPortQuery> ports = new List<ComPortQuery>();
                var searcher = new ManagementObjectSearcher("SELECT DeviceID,Caption FROM WIN32_SerialPort");
                foreach (ManagementObject port in searcher.Get())
                {
                    // show the service
                    ComPortQuery c = new ComPortQuery();
                    c.name = port.GetPropertyValue("DeviceID").ToString();
                    c.description = port.GetPropertyValue("Caption").ToString();
                    ports.Add(c);
                }
                return ports;
            }
            private void Task_GetAllComPorts()
            {
                /* 掃描所有COM Port,接結果存於 List<ComPortQuery>gAllComPorts 中 */
                if (gAllComPorts == null)
                    gAllComPorts = new List<ComPortQuery>();
                gAllComPorts.Clear(); /* 清除 */
                // 用 Method 2 初步掃描
                List<ComPortQuery> ports = GetSerialPort2();
                foreach (ComPortQuery port in ports)
                {
                    gAllComPorts.Add(port);
                }
                // 用 Method 1 再次掃描
                string[] ports2 = SerialPort.GetPortNames();
                foreach (string port in ports2)
                {
                    // 只需檢查Port Name是否有重複的
                    if (!gAllComPorts.Exists(x => x.name == port))
                    {
                        gAllComPorts.Add(new ComPortQuery(port, port));
                    }
                }
                return;
            }
     
  • GetAllPorts 涵式中,做了一些檢查以免有 Port 重複出現,這樣就可以獲取到所有連接到電腦上的裝置了,把得到的 Port 們放到一個 ComboBox 下拉式選單裡。
  • 搞定!

題外話

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

參考資料

Reference

  • Source - 取得所有連接到電腦上的 Serial Port 詳細資訊
  • 85 person(s) visited this page until now.

Permalink prog/csharp/2024-821-01/index.txt · Last modified: 2024/08/21 10:47 by jethro

oeffentlich