2015年7月3日金曜日

C#でシリアルポートのデバイス名を獲得する

C#のSystem.IO.Ports.GetPortNames()ではCOMxというそっけない文字列しか獲得できない
あんまり不便してないのだけど、試しにデバイス名を獲得してみた

C#でCOMポート番号とシリアル接続機器名を同時に取得する方法 - 真実の楽譜(フルスコア)というページを参考にした 手っ取り早く使いたいならこのページでどうぞ

さて、とりあえず試してみたソースコード

/*
 * 参考にしたページ : http://truthfullscore.hatenablog.com/entry/2014/01/10/180608
 */

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management;

namespace ShowSerialPortName {
    class Program {
        public static void Main() {

            Stopwatch sw = new Stopwatch();
            sw.Start();
            string[] ports = GetDeviceNames();
            sw.Stop();

            Array.Sort(ports, (a, b) => (DeviceNameToIndex(a) - DeviceNameToIndex(b)));

            for (int i = 0; i < ports.Length; i++) {
                Console.WriteLine(ports[i]);
            }

            Console.WriteLine((sw.ElapsedMilliseconds * 0.001).ToString() + "sec");
            Console.ReadLine();
        }

        public static int DeviceNameToIndex(string DeviceName) {
            System.Text.RegularExpressions.Regex check = new System.Text.RegularExpressions.Regex("(COM[1-9][0-9]?[0-9]?)");

            int i = DeviceName.LastIndexOf('(');

            if (i == -1) {
                return (0);
            }

            string str = DeviceName.Substring(i);

            if (!check.IsMatch(str)) {
                return (0);
            }

            if (str.Length <= 5) {
                return (0);
            }

            int index;
            if (!int.TryParse(str.Substring(4, str.Length - 5), out index)) {
                return (0);
            }

            return (index);
        }

        public static string[] GetDeviceNames() {
            List<string> deviceNameList = new List<string>();
            System.Text.RegularExpressions.Regex check = new System.Text.RegularExpressions.Regex("(COM[1-9][0-9]?[0-9]?)");

            ManagementClass mcPnPEntity = new ManagementClass("Win32_PnPEntity");
            ManagementObjectCollection manageObjCol = mcPnPEntity.GetInstances();

            foreach (ManagementObject manageObj in manageObjCol) {
                string name = manageObj.GetPropertyValue("Name") as string;

                if (check.IsMatch(name)) {
                    deviceNameList.Add(name);
                }
            }

            return (deviceNameList.ToArray());
        }
    }
}

僕の環境ではこうなった
たった5個のシリアルポート表を入手するだけで約0.3秒もかかる。これは200以上もあるデバイスすべてに総当りで探しているので仕方ないといえば仕方ないが。PCによってはもっと時間がかかる場合もあるだろうし、きれいなPCならもっと早いかもしれない。が、どちらにしろGetPortNamesよりははるかに長いだろう。GUIフォームで使用する場合はGUIスレッドをブロックしないような方法を考える必要がありそうだ。

それとデバイス名の最後にインデックスが表示されるのはあんまり好かない。LastIndexOfで(COMx)を切り出して前に移動する という処理をしたほうが読みやすいと思う。ただこれは僕がCOMポートのテーブルを把握しているからなので、どのポート番号がどのデバイスに接続されているかわからない場合はCOMx表示がどこにあっても関係ないかも?。

0 件のコメント:

コメントを投稿