/* WinUSBNet library
* (C) 2010 Thomas Bleeker (www.madwizard.org)
*
* Licensed under the MIT license, see license.txt or:
* http://www.opensource.org/licenses/mit-license.php
*/
using System;
namespace MadWizard.WinUSBNet
{
///
/// Delegate for event handler methods handing USB events
///
/// The source of the event
/// Details of the event
public delegate void USBEventHandler(object sender, USBEvent e);
///
/// Event type enumeration for WinUSB events
///
public enum USBEventType
{
///
/// A device has been connected to the system
///
DeviceArrival,
///
/// A device has been disconnected from the system
///
DeviceRemoval,
}
///
/// Contains the details of a USB event
///
public class USBEvent : EventArgs
{
///
/// WinUSB interface GUID of the device as specified in the WinUSBNotifier
///
public Guid Guid;
///
/// Device pathname that identifies the device
///
public string DevicePath;
///
/// Type of event that occurred
///
public USBEventType Type;
internal USBEvent(USBEventType type, Guid guid, string devicePath)
{
this.Guid = guid;
this.DevicePath = devicePath;
this.Type = type;
}
}
///
/// Helper class to receive notifications on USB device changes such as
/// connecting or removing a device.
///
public class USBNotifier : IDisposable
{
private readonly DeviceNotifyHook _hook;
private Guid _guid;
private readonly WPinternals.AsyncAutoResetEvent NodeChangeEvent = new(false);
///
/// Event triggered when a new USB device that matches the USBNotifier's GUID is connected
///
private event EventHandler _Arrival;
public event EventHandler Arrival
{
// Heathcliff74 - Also notify currently connected USB devices
add
{
_Arrival -= value;
_Arrival += value;
foreach (USBDeviceInfo Device in USBDevice.GetDevices(Guid))
{
_Arrival(this, new USBEvent(USBEventType.DeviceArrival, Guid, Device.DevicePath));
}
}
remove
{
_Arrival -= value;
}
}
///
/// Event triggered when a new USB device that matches the USBNotifier's GUID is disconnected
///
public event EventHandler Removal;
///
/// The interface GUID of devices this USBNotifier will watch
///
public Guid Guid
{
get
{
return _guid;
}
}
///
/// Constructs a new USBNotifier that will watch for events on
/// devices matching the given interface GUID. A Windows Forms control
/// is needed since the notifier relies on window messages.
///
/// A control that will be used internally for device notification messages.
/// You can use a Form object for example.
/// The interface GUID string of the devices to watch.
public USBNotifier(string guidString) :
this(new Guid(guidString))
{
// Handled in other constructor
}
///
/// Constructs a new USBNotifier that will watch for events on
/// devices matching the given interface GUID. A Windows Forms control
/// is needed since the notifier relies on window messages.
///
/// A control that will be used internally for device notification messages.
/// You can use a Form object for example.
/// The interface GUID of the devices to watch.
public USBNotifier(Guid guid)
{
_guid = guid;
_hook = new DeviceNotifyHook(this, _guid);
}
///
/// Triggers the arrival event
///
/// Device pathname of the device that has been connected
protected void OnArrival(string devicePath)
{
_Arrival?.Invoke(this, new USBEvent(USBEventType.DeviceArrival, _guid, devicePath));
}
///
/// Triggers the removal event
///
/// Device pathname of the device that has been connected
protected void OnRemoval(string devicePath)
{
Removal?.Invoke(this, new USBEvent(USBEventType.DeviceRemoval, _guid, devicePath));
}
internal int HandleDeviceChange(int msg, IntPtr wParam, IntPtr lParam)
{
if (msg != API.DeviceManagement.WM_DEVICECHANGE)
{
throw new USBException("Invalid device change message."); // should not happen
}
//switch ((int)wParam)
//{
// case API.DeviceManagement.DBT_DEVICEARRIVAL:
// WPinternals.LogFile.Log(Guid.ToString() + " - DBT_DEVICEARRIVAL", WPinternals.LogType.FileOnly);
// break;
// case API.DeviceManagement.DBT_DEVICEREMOVECOMPLETE:
// WPinternals.LogFile.Log(Guid.ToString() + " - DBT_DEVICEREMOVECOMPLETE", WPinternals.LogType.FileOnly);
// break;
// case API.DeviceManagement.DBT_DEVNODES_CHANGED:
// WPinternals.LogFile.Log(Guid.ToString() + " - DBT_DEVNODES_CHANGED", WPinternals.LogType.FileOnly);
// break;
// case API.DeviceManagement.DBT_QUERYCHANGECONFIG:
// WPinternals.LogFile.Log(Guid.ToString() + " - DBT_QUERYCHANGECONFIG", WPinternals.LogType.FileOnly);
// break;
// default:
// WPinternals.LogFile.Log(Guid.ToString() + " - wParam: 0x" + ((int)wParam).ToString("X8"), WPinternals.LogType.FileOnly);
// break;
//}
if ((int)wParam == API.DeviceManagement.DBT_DEVICEARRIVAL)
{
string devName = API.DeviceManagement.GetNotifyMessageDeviceName(lParam, _guid);
if (devName != null)
{
OnArrival(devName);
}
}
if ((int)wParam == API.DeviceManagement.DBT_DEVICEREMOVECOMPLETE)
{
string devName = API.DeviceManagement.GetNotifyMessageDeviceName(lParam, _guid);
if (devName != null)
{
OnRemoval(devName);
}
}
if ((int)wParam == API.DeviceManagement.DBT_DEVNODES_CHANGED)
{
NodeChangeEvent.Set();
}
if ((int)wParam == API.DeviceManagement.DBT_QUERYCHANGECONFIG)
{
return 1; // Give permission
}
return 0;
}
public async System.Threading.Tasks.Task WaitForNextNodeChange()
{
await NodeChangeEvent.WaitAsync(System.Threading.Timeout.InfiniteTimeSpan);
}
///
/// Disposes the USBNotifier object and frees all resources.
/// Call this method when the object is no longer needed.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Disposes the object's resources.
///
/// True when dispose is called manually, false when called by the finalizer.
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_hook.Dispose();
}
}
}
}