2012-05-11 65 views
5

我的C#應用​​程序使用COM端口。我遇到了一些大多數程序都應該遇到的困難。當Portname列表發生更改時,我需要獲取一個事件。我有一個選擇框,用戶可以從可用端口名稱列表中進行選擇。有沒有人有這個代碼片段?謝謝。新的COM端口可用事件

+1

我猜想你可以看到一個通用的'新USB設備'或'新PNP設備'系統事件,但你可能需要等待一秒鐘才能讓設備在新COM端口出現之前完成初始化。 – Rup

+1

@Rup - 你是對的。設備通知和System.IO.Ports.SerialPort.GetPortNames()將反映更改之間存在滯後。這就是爲什麼當清單更新時得到通知真的很棒。 – GTAE86

回答

2

COM端口改變是一種罕見的事件,不常見。

最簡單的方法是定時器,每10-30秒枚舉COM端口列表,如果更改,更新列表。

更妙的是,提供一個「刷新列表」按鈕 - 該列表將基本上只有改變,如果用戶在插入一個USB串口適配器

+2

http://www.codeproject.com/Articles/60579/A-USB-Library-to-Detect-USB-Devices會告訴你如何偵聽USB連接/分離事件。另外,10-30秒對於用戶來說可能太長,對於刷新按鈕來說是+1。 – Simon

2

創建一個簡單的窗體應用程序,並把下面的代碼形式。

protected override void WndProc(ref Message m) 
{ 
    switch (m.Msg) 
    { 
     case 537: //WM_DEVICECHANGE 
      var ports = SerialPort.GetPortNames().OrderBy(name => name); 

      foreach (var portName in ports) 
      { 
       Debug.Print(portName); 
      } 
      break; 
    } 
    base.WndProc(ref m); 
} 
+0

這可以在Windows Service消息泵中工作嗎?操作系統:Win7。如果沒有,那麼任何解決方法? –

+0

@AdrianSalazar:不知道,從來沒有嘗試過。但我看不出有什麼理由不應該這樣做。只需嘗試一下,如果它不起作用,就問題提出一個新問題。 – Oliver

+0

這個小小的「覆蓋」關鍵字是我所擔心的。從來沒有在Windows服務中看到這個特定的方法,所以,注意重寫。 –

4

它也可以用 「ManagementEventWatcher」 的幫助下完成的:

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.ComponentModel.Composition; 
using System.Linq; 
using System.Text; 
using System.Management; 
using System.IO.Ports; 
using System.Threading; 
using System.Threading.Tasks; 

namespace HmxFlashLoader 
{ 
/// <summary> 
/// Make sure you create this watcher in the UI thread if you are using the com port list in the UI 
/// </summary> 
[Export] 
[PartCreationPolicy(CreationPolicy.Shared)] 
public sealed class SerialPortWatcher : IDisposable 
{ 
    public SerialPortWatcher() 
    { 
     _taskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 
     ComPorts = new ObservableCollection<string>(SerialPort.GetPortNames().OrderBy(s => s)); 

     WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent"); 

     _watcher = new ManagementEventWatcher(query);   
     _watcher.EventArrived += (sender, eventArgs) => CheckForNewPorts(eventArgs); 
     _watcher.Start();  
    } 

    private void CheckForNewPorts(EventArrivedEventArgs args) 
    { 
     // do it async so it is performed in the UI thread if this class has been created in the UI thread 
     Task.Factory.StartNew(CheckForNewPortsAsync, CancellationToken.None, TaskCreationOptions.None, _taskScheduler); 
    } 

    private void CheckForNewPortsAsync() 
    { 
     IEnumerable<string> ports = SerialPort.GetPortNames().OrderBy(s => s); 

     foreach (string comPort in ComPorts) 
     { 
      if (!ports.Contains(comPort)) 
      { 
       ComPorts.Remove(comPort); 
      } 
     } 

     foreach (var port in ports) 
     {   
      if (!ComPorts.Contains(port)) 
      { 
       AddPort(port); 
      } 
     } 
    } 

    private void AddPort(string port) 
    { 
     for (int j = 0; j < ComPorts.Count; j++) 
     { 
      if (port.CompareTo(ComPorts[j]) < 0) 
      { 
       ComPorts.Insert(j, port); 
       break; 
      } 
     } 

    } 

    public ObservableCollection<string> ComPorts { get; private set; } 

    #region IDisposable Members 

    public void Dispose() 
    { 
     _watcher.Stop();  
    } 

    #endregion 

    private ManagementEventWatcher _watcher; 
    private TaskScheduler _taskScheduler; 
} 

}

+0

非常整潔的解決方案!謝了哥們! – Ian

+0

我認爲這個代碼會在迭代ComPorts時更新ComPorts時引發異常.... – GTAE86