Taking the WMI Management route a bit further, I've come up with a wrapper class which hooks on to the Win32_SerialPorts events and dynamically populated a list of SerialPorts for Arduino and Digi International (X-Bee) devices, complete with PortNames and BaudRates.
For now, I've used the devices Description field in the Win32_SerialPorts entry as the Key for the Dictionary, but this can easily be changed.
It has been tested to a limited capacity with an Arduino UNO and it seems to be stable.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Management;
using System.Runtime.CompilerServices;
using ArduinoLibrary.Annotations;
namespace ArduinoLibrary
{
public sealed class ArduinoDeviceManager : IDisposable, INotifyPropertyChanged
{
private readonly ManagementEventWatcher _deviceWatcher = new ManagementEventWatcher(new WqlEventQuery(
"SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2 OR EventType = 3"));
private Dictionary<string, SerialPort> _serialPorts = new Dictionary<string, SerialPort>();
public ArduinoDeviceManager()
{
_deviceWatcher.EventArrived += _deviceWatcher_EventArrived;
_deviceWatcher.Start();
DiscoverArduinoDevices();
}
public Dictionary<string, SerialPort> SerialPorts
{
get { return _serialPorts; }
private set
{
_serialPorts = value;
OnPropertyChanged();
}
}
public void Dispose()
{
_deviceWatcher.Stop();
}
public event PropertyChangedEventHandler PropertyChanged;
private void _deviceWatcher_EventArrived(object sender, EventArrivedEventArgs e)
{
DiscoverArduinoDevices();
}
private void DiscoverArduinoDevices()
{
var dict = new Dictionary<string, SerialPort>();
try
{
foreach (ManagementObject device in
new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_SerialPort").Get())
{
if (!device["PNPDeviceID"].ToString().Contains("VID_2341") &&
!device["PNPDeviceID"].ToString().Contains("VID_04d0")) continue;
var port = new SerialPort();
var config = device.GetRelated("Win32_SerialPortConfiguration")
.Cast<ManagementObject>().ToList().FirstOrDefault();
port.PortName = device["DeviceID"].ToString();
port.BaudRate = (config != null)
? int.Parse(config["BaudRate"].ToString())
: int.Parse(device["MaxBaudRate"].ToString());
dict.Add(device["Description"].ToString(), port);
}
SerialPorts = dict;
}
catch (ManagementException mex)
{
Debug.WriteLine(@"An error occurred while querying for WMI data: " + mex.Message);
}
}
[NotifyPropertyChangedInvocator]
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}