C# 串口操作中一些相关问题总结

  我在查找关于用C# 监控USB转串口 的插入和拨出消息时 ,网上找了很多资料基本都是下边这一个代码

 1 #region 检测USB串口的热拔插
 2         // usb消息定义
 3         public const int WM_DEVICE_CHANGE = 0x219;
 4         public const int DBT_DEVICEARRIVAL = 0x8000;
 5         public const int DBT_DEVICE_REMOVE_COMPLETE = 0x8004;
 6         public const UInt32 DBT_DEVTYP_PORT = 0x00000003;
 7         [StructLayout(LayoutKind.Sequential)]
 8         struct DEV_BROADCAST_HDR
 9         {
10             public UInt32 dbch_size;
11             public UInt32 dbch_devicetype;
12             public UInt32 dbch_reserved;
13         }
14 
15         [StructLayout(LayoutKind.Sequential)]
16         protected struct DEV_BROADCAST_PORT_Fixed
17         {
18             public uint dbcp_size;
19             public uint dbcp_devicetype;
20             public uint dbcp_reserved;
21             // Variable?length field dbcp_name is declared here in the C header file.
22         }
23 
24         /// <summary>
25         /// 检测USB串口的拔插
26         /// </summary>
27         /// <param name="m"></param>
28         protected override void WndProc(ref Message m)
29         {
30             DEV_BROADCAST_HDR dbhdr;
31             if(m.Msg == WM_DEVICE_CHANGE)        // 捕获USB设备的拔出消息WM_DEVICECHANGE
32             {
33                 switch(m.WParam.ToInt32())
34                 {
35                 case DBT_DEVICE_REMOVE_COMPLETE:    // USB拔出  
36                     dbhdr = (DEV_BROADCAST_HDR)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_HDR));
37                     if(dbhdr.dbch_devicetype == DBT_DEVTYP_PORT)
38                     {
39                         string portName = Marshal.PtrToStringUni((IntPtr)(m.LParam.ToInt32() + Marshal.SizeOf(typeof(DEV_BROADCAST_PORT_Fixed))));
40                         Console.WriteLine("Port '" + portName + "' removed.");
41 
42                         if(portName.CompareTo(serial.PortName) == 0)
43                         {
44                             serial_port_close();
45                         }
46                     }
47                     break;
48                 case DBT_DEVICEARRIVAL:             // USB插入获取对应串口名称
49                     dbhdr = (DEV_BROADCAST_HDR)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_HDR));
50                     if(dbhdr.dbch_devicetype == DBT_DEVTYP_PORT)
51                     {
52                         string portName = Marshal.PtrToStringUni((IntPtr)(m.LParam.ToInt32() + Marshal.SizeOf(typeof(DEV_BROADCAST_PORT_Fixed))));
53                         Console.WriteLine("Port '" + portName + "' arrived.");
54                     }
55                     break;
56                 }
57             }
58             base.WndProc(ref m);
59         }
60  #endregion

 这段代码我在笔记本上测试的,发现只能捕获到WM_DEVICE_CHANGE消息,并且m.WParam.ToInt32()的值始终为7,目前仍然没有找到原因,有知道原因的朋友麻烦告诉我一下,所以这种方法没办法监测USB转串口。

  第2种办法是能获取USB转串口的一些信息,不再是单单的COM多少多少,而是能分辨出那个USB转的串口 代码如下

 1     ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * From " + "Win32_SerialPort");
 2     foreach (ManagementObject mo in searcher.Get())
 3     {
 4         txt_show_recv.AppendText("============" + "串口" + "开始======\r\n");
 5         foreach (PropertyData pd in mo.Properties)
 6         {
 7             txt_show_recv.Text += pd.Name + " : ";
 8             if (pd.Value != null)
 9             {
10                 txt_show_recv.Text += pd.Value.ToString();
11             }
12            txt_show_recv.Text += "\r\n";
13         }
14         txt_show_recv.AppendText("============" + "串口" + "结束======\r\n\r\n\");
15         
16     }

上边这段代码打印出的信息如下 从这些信息里取自己想要的即可

============串口信息开始======
Availability : 2
Binary : True
Capabilities : 
CapabilityDescriptions : 
Caption : USB Serial Port (COM3)
ConfigManagerErrorCode : 0
ConfigManagerUserConfig : False
CreationClassName : Win32_SerialPort
Description : USB Serial Port
DeviceID : COM3
ErrorCleared : 
ErrorDescription : 
InstallDate : 
LastErrorCode : 
MaxBaudRate : 115200
MaximumInputBufferSize : 0
MaximumOutputBufferSize : 0
MaxNumberControlled : 
Name : USB Serial Port (COM3)
OSAutoDiscovered : True
PNPDeviceID : USB\VID_04D8&PID_00DF&MI_00\6&248B9296&0&0000
PowerManagementCapabilities : System.UInt16[]
PowerManagementSupported : False
ProtocolSupported : 
ProviderType : Modem Device
SettableBaudRate : True
SettableDataBits : True
SettableFlowControl : True
SettableParity : True
SettableParityCheck : True
SettableRLSD : True
SettableStopBits : True
Status : OK
StatusInfo : 3
Supports16BitMode : False
SupportsDTRDSR : True
SupportsElapsedTimeouts : True
SupportsIntTimeouts : True
SupportsParityCheck : True
SupportsRLSD : True
SupportsRTSCTS : False
SupportsSpecialCharacters : False
SupportsXOnXOff : False
SupportsXOnXOffSet : False
SystemCreationClassName : Win32_ComputerSystem
SystemName : PC-20161106GRIO
TimeOfLastReset : 
============串口信息结束======

第3种办法 下边这个办法就类似于设备管理器那样,从系统里枚举出设备信息 然后筛选出所有的串口设备,不过我测试稍 在获取列表时稍为有点时间长,有差不1S左右,不过可以把那个enum HardwareEnum里的信息删除一部分不需要的 速度就快了。

        /// <summary>
        /// 枚举win32 api
        /// </summary>
        public enum HardwareEnum
        {
            // 硬件
            Win32_Processor, // CPU 处理器
            Win32_PhysicalMemory, // 物理内存条
            Win32_Keyboard, // 键盘
            Win32_PointingDevice, // 点输入设备,包括鼠标。
            Win32_FloppyDrive, // 软盘驱动器
            Win32_DiskDrive, // 硬盘驱动器
            Win32_CDROMDrive, // 光盘驱动器
            Win32_BaseBoard, // 主板
            Win32_BIOS, // BIOS 芯片
            Win32_ParallelPort, // 并口
            Win32_SerialPort, // 串口
            Win32_SerialPortConfiguration, // 串口配置
            Win32_SoundDevice, // 多媒体设置,一般指声卡。
            Win32_SystemSlot, // 主板插槽 (ISA & PCI & AGP)
            Win32_USBController, // USB 控制器
            Win32_NetworkAdapter, // 网络适配器
            Win32_NetworkAdapterConfiguration, // 网络适配器设置
            Win32_Printer, // 打印机
            Win32_PrinterConfiguration, // 打印机设置
            Win32_PrintJob, // 打印机任务
            Win32_TCPIPPrinterPort, // 打印机端口
            Win32_POTSModem, // MODEM
            Win32_POTSModemToSerialPort, // MODEM 端口
            Win32_DesktopMonitor, // 显示器
            Win32_DisplayConfiguration, // 显卡
            Win32_DisplayControllerConfiguration, // 显卡设置
            Win32_VideoController, // 显卡细节。
            Win32_VideoSettings, // 显卡支持的显示模式。

            // 操作系统
            Win32_TimeZone, // 时区
            Win32_SystemDriver, // 驱动程序
            Win32_DiskPartition, // 磁盘分区
            Win32_LogicalDisk, // 逻辑磁盘
            Win32_LogicalDiskToPartition, // 逻辑磁盘所在分区及始末位置。
            Win32_LogicalMemoryConfiguration, // 逻辑内存配置
            Win32_PageFile, // 系统页文件信息
            Win32_PageFileSetting, // 页文件设置
            Win32_BootConfiguration, // 系统启动配置
            Win32_ComputerSystem, // 计算机信息简要
            Win32_OperatingSystem, // 操作系统信息
            Win32_StartupCommand, // 系统自动启动程序
            Win32_Service, // 系统安装的服务
            Win32_Group, // 系统管理组
            Win32_GroupUser, // 系统组帐号
            Win32_UserAccount, // 用户帐号
            Win32_Process, // 系统进程
            Win32_Thread, // 系统线程
            Win32_Share, // 共享
            Win32_NetworkClient, // 已安装的网络客户端
            Win32_NetworkProtocol, // 已安装的网络协议
            Win32_PnPEntity,//all device
        }
 /// <summary>
        /// WMI取硬件信息
        /// </summary>
        /// <param name="hardType"></param>
        /// <param name="propKey"></param>
        /// <returns></returns>
        public static string[] MulGetHardwareInfo(HardwareEnum hardType, string propKey)
        {

            List<string> strs = new List<string>();
            try
            {
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + hardType))
                {
                    var hardInfos = searcher.Get();
                    foreach (var hardInfo in hardInfos)
                    {
              if (hardInfo.Properties[propKey].Value != null)  {

                if (hardInfo.Properties[propKey].Value.ToString().Contains("COM"))   {   strs.Add(hardInfo.Properties[propKey].Value.ToString());   }                } } searcher.Dispose(); } return strs.ToArray(); } catch { return null; } finally { strs = null; } } //通过WMI获取COM端口 string[] ss = MulGetHardwareInfo(HardwareEnum.Win32_PnPEntity, "Name");

要想更快直接指定Win32_SerialPort,这样就比较快了,但是这样虚拟串口无法检测到,不过这样也不影响使用,毕竟实际环境中也不会用虚拟串口的

public string[] MulGetHardwareInfo(string hardType, string propKey)
        {

            List<string> strs = new List<string>();
            try
            {
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + hardType))
                {
                    var hardInfos = searcher.Get();
                    foreach (var hardInfo in hardInfos)
                    {
              if (hardInfo.Properties[propKey].Value != null) 
                        {

                if (hardInfo.Properties[propKey].Value.ToString().Contains("COM"))   {   strs.Add(hardInfo.Properties[propKey].Value.ToString());   }                }
             } 
              searcher.Dispose();
          }
              
return strs.ToArray();
       }
      catch { return null; }
      finally { strs = null; }
    }
//通过WMI获取COM端口
  string[] port_names = MulGetHardwareInfo("Win32_SerialPort", "Name"); 

第四种方法 就是直接调用C#封装好的类库的

    private void cbo_port_name_DropDown(object sender, EventArgs e)
        {
            string port_name_old = cbo_port_name.Text;string[] port_names = SerialPort.GetPortNames();
            Array.Sort(port_names, new CustomComparer());
            cbo_port_name.Items.Clear();
            cbo_port_name.Items.AddRange(port_names);

            cbo_port_name.Text = port_name_old;

            if((cbo_port_name.Items.Count > 0) && (cbo_port_name.SelectedIndex < 0))
            {
                cbo_port_name.SelectedIndex = 0;
            }
        }

第五种方法 直接调用open方法来依次打开端口,能打开说明端口存在,否则不存在

       for (int i = 0; i < 20; i++)//启动时搜索可用串口
            {
                try
                {
                    SerialPort sport = new SerialPort("COM" + (i + 1).ToString());
                    sport.Open();
                    sport.Close();
                    cmbBox_Port.Items.Add("COM" + (i + 1).ToString());
                    ComPort_Exit = true;
                }
                catch
                {
                    continue;
                }
                if (ComPort_Exit == true)
                {
                    cmbBox_Port.SelectedIndex = 0;//默认选择COM1;
                }
                else
                {
                    MessageBox.Show("没有找到可用串口", "错误提示");
                }
                
            }

 

posted @ 2016-12-05 21:20  流泪的冰淇淋  阅读(734)  评论(0编辑  收藏  举报