I am interfacing with a USB-to-serial port that can be inserted or removed at any time. I've found that I can use WMI (particularly with the use of WMI Code Creator) to query for device changes in the PC.
In the generated snippet below, the Win32_DeviceChangeEvent is subscribed to. However, this event doesn't reveal which device (e.g. USB, serial port, etc) caused the event. Is there a way to only receive notifications when serial ports are inserted or removed?
To clarify, the point of the code is not to detect opening/closing of serial ports, it is to detect whether a new port has been added to the machine or a previous port was removed.
using System;
using System.Management;
using System.Windows.Forms;
namespace WMISample
{
public class WMIReceiveEvent
{
public WMIReceiveEvent()
{
try
{
WqlEventQuery query = new WqlEventQuery(
"SELECT * FROM Win32_DeviceChangeEvent");
ManagementEventWatcher watcher = new ManagementEventWatcher(query);
Console.WriteLine("Waiting for an event...");
watcher.EventArrived +=
new EventArrivedEventHandler(
HandleEvent);
// Start listening for events
watcher.Start();
// Do something while waiting for events
System.Threading.Thread.Sleep(10000);
// Stop listening for events
watcher.Stop();
return;
}
catch(ManagementException err)
{
MessageBox.Show("An error occurred while trying to receive an event: " + err.Message);
}
}
private void HandleEvent(object sender,
EventArrivedEventArgs e)
{
Console.WriteLine("Win32_DeviceChangeEvent event occurred.");
}
public static void Main()
{
WMIReceiveEvent receiveEvent = new WMIReceiveEvent();
return;
}
}
}
No. Go find out what happened to SerialPort.GetPortNames(). Listening for the WM_DEVICECHANGE message in a window can give you better info.
Your device change event can be used with the WMI - PNP Entity. The following will return device details - in the code below it shows the device name.
Also see code to access other PNP properties that could be used to filtered or monitored for change:
I ended up using WMI and @Hans' advice to check what serial ports are new/missing.
The
MonitorDeviceChanges
method actually sees all device changes (like Device Manager), but checking the serial ports allows us to only raise an event when those have changed.To use the code, simply subscribe to the
PortsChanged
event, e.g.SerialPortService.PortsChanged += (sender1, changedArgs) => DoSomethingSerial(changedArgs.SerialPorts);
Oh, and the
.Raise
method is just an extension method I picked up somewhere:NB: I tried to post this as a comment on @Pat's answer, but don't have enough reputation to do that.
Further to @2pietjuh2's comment, the RaisePortsChangedIfNecessary() can be changed to the following:
Raised events then include the serial port inserted/removed, rather than the list of serial ports available after the insertion/removal.
Here is a stripped down version of a
DeviceChangeEvents
notification class I wrote some time ago, though I never fully completed it. I stripped out everything except the PortArrived event as it's quite fugly otherwise.