Last active
December 15, 2015 00:38
-
-
Save jasonbrice/5173849 to your computer and use it in GitHub Desktop.
Simple class to detect insertion/removal of Human Interface Device (e.g., user sticks a thumb drive into a USB port)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Runtime.InteropServices; | |
namespace HID | |
{ | |
public static class Constants | |
{ | |
// Windows constants for dealing with HID devices | |
public const int WM_DEVICECHANGE = 0x0219; // Generic plug & play event | |
public const int DBT_DEVICEARRIVAL = 0x8000; // Device ready for use | |
public const int DBT_DEVTYP_VOLUME = 2; // Removable device | |
public const int DBT_DEVICEREMOVEPENDING = 0x8003; // Device about to be removed | |
public const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // Device Removed | |
} | |
public enum EVENT : int | |
{ | |
DEVICE_AVAILABLE, | |
DEVICE_DISCONNECTED, | |
} | |
// Serves as a standard header for information related to a device | |
// event reported through the WM_DEVICECHANGE message. | |
[StructLayout(LayoutKind.Sequential)] | |
struct DEV_BROADCAST_HDR | |
{ | |
public int Size; | |
public int DeviceType; | |
public int reserved; | |
} | |
// Contains information about a logical volume. | |
[StructLayout(LayoutKind.Sequential)] | |
struct DEV_BROADCAST_VOLUME | |
{ | |
public DEV_BROADCAST_HDR Header; | |
public int UnitMask; | |
public int Flags; | |
} | |
public class HIDDevice | |
{ | |
public static event EventHandler<HIDMessageArgs> OnUsbDriveConnect = delegate { }; | |
public static event EventHandler<HIDMessageArgs> OnUsbDriveDisconnect = delegate { }; | |
public static event EventHandler<HIDMessageArgs> OnUsbDriveDisconnectPending = delegate { }; | |
private string driveLetter; | |
public string DriveLetter { get { return driveLetter; } } | |
public bool IsAvailable | |
{ | |
get | |
{ | |
if (string.IsNullOrEmpty(DriveLetter)) return false; | |
foreach (string s in Environment.GetLogicalDrives()) | |
{ | |
if (s.Equals(DriveLetter)) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
} | |
public HIDDevice(ref System.Windows.Forms.Message m) | |
{ | |
DEV_BROADCAST_HDR hdr = new DEV_BROADCAST_HDR(); | |
switch (m.WParam.ToInt32()) | |
{ | |
// at this point the USB device is ready for use. | |
case Constants.DBT_DEVICEARRIVAL: | |
// get a handle on the device header | |
hdr = (DEV_BROADCAST_HDR)(Marshal.PtrToStructure(m.LParam, typeof(HID.DEV_BROADCAST_HDR))); | |
// is a removable device? | |
if (hdr.DeviceType == Constants.DBT_DEVTYP_VOLUME) | |
{ | |
// get a handle on the volume | |
DEV_BROADCAST_VOLUME vlm = new DEV_BROADCAST_VOLUME(); | |
vlm = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(HID.DEV_BROADCAST_VOLUME)); | |
char drv = GetDriveLetter((ulong)vlm.UnitMask); | |
this.driveLetter = drv.ToString() + @":\"; | |
// fire an event off to anybody listening | |
// for new HID messages. | |
OnUsbDriveConnect(this, new HIDMessageArgs(EVENT.DEVICE_AVAILABLE, drv)); | |
} | |
else | |
{ | |
Console.WriteLine("Not a removeable device"); | |
} | |
break; | |
// devive about to be removed | |
case Constants.DBT_DEVICEREMOVEPENDING: | |
// get a handle on the device header | |
hdr = (DEV_BROADCAST_HDR)(Marshal.PtrToStructure(m.LParam, typeof(HID.DEV_BROADCAST_HDR))); | |
// is a removable device? | |
if (hdr.DeviceType == Constants.DBT_DEVTYP_VOLUME) | |
{ | |
// get a handle on the volume | |
DEV_BROADCAST_VOLUME vlm = new DEV_BROADCAST_VOLUME(); | |
vlm = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(HID.DEV_BROADCAST_VOLUME)); | |
char drv = GetDriveLetter((ulong)vlm.UnitMask); | |
OnUsbDriveDisconnectPending(this, new HIDMessageArgs(EVENT.DEVICE_AVAILABLE, drv)); | |
} | |
break; | |
// device removal complete | |
case Constants.DBT_DEVICEREMOVECOMPLETE: | |
Console.WriteLine("Device disconnected."); | |
// fire an event off to anybody listening | |
// for new UDPMessages. | |
OnUsbDriveDisconnect(this, new HIDMessageArgs(EVENT.DEVICE_DISCONNECTED)); | |
break; | |
default: | |
//Lots of these... safe to ignore | |
//Console.WriteLine("Unknown action: " + m.WParam.ToInt32()); | |
break; | |
} | |
} | |
// return the drive letter given an unsigned long int | |
private static char GetDriveLetter(ulong m) | |
{ | |
int i; | |
for (i = 0; i < 26; ++i) | |
{ | |
if ((m & 0x1L) != 0) | |
break; | |
m = m >> 1; | |
} | |
return (char)(i + 'A'); | |
} | |
} | |
// These args will be delivered to any class | |
// listening for USB attach / detach events. | |
public class HIDMessageArgs : EventArgs | |
{ | |
private EVENT _eventType; | |
private char driveLetter; | |
public char DriveLetter { get { return driveLetter; } } | |
public EVENT EventType { get { return _eventType; } } | |
public HIDMessageArgs(EVENT type) | |
{ | |
_eventType = type; | |
} | |
public HIDMessageArgs(EVENT type, char driveLetter) | |
{ | |
_eventType = type; | |
this.driveLetter = driveLetter; | |
} | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public Form1() | |
{ | |
InitializeComponent(); | |
HID.HIDDevice.OnUsbDriveConnect += new EventHandler<HID.HIDMessageArgs>(DriveConnected); | |
HID.HIDDevice.OnUsbDriveDisconnectPending += new EventHandler<HID.HIDMessageArgs>(DriveDisconnectedPending); | |
HID.HIDDevice.OnUsbDriveDisconnect += new EventHandler<HID.HIDMessageArgs>(DriveDisconnected); | |
} | |
// Listen for windows messages | |
protected override void DefWndProc(ref Message m) | |
{ | |
try | |
{ | |
// quite a number of these can be generated during | |
// the plug & play process... | |
if (m.Msg == HID.Constants.WM_DEVICECHANGE) | |
{ | |
HID.HIDDevice device = new HID.HIDDevice(ref m); | |
} | |
else | |
base.DefWndProc(ref m); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine(ex.StackTrace); | |
} | |
} | |
private void DriveConnected(object sender, HID.HIDMessageArgs e) | |
{ | |
HID.HIDDevice usb = (HID.HIDDevice)sender; | |
Console.WriteLine("Detected drive " + usb.DriveLetter + " connected"); | |
} | |
private void DriveDisconnectedPending(object sender, HID.HIDMessageArgs e) | |
{ | |
HID.HIDDevice usb = (HID.HIDDevice)sender; | |
Console.WriteLine("Detected drive " + usb.DriveLetter + " disconnect pending"); | |
} | |
private void DriveDisconnected(object sender, HID.HIDMessageArgs e) | |
{ | |
HID.HIDDevice usb = (HID.HIDDevice)sender; | |
Console.WriteLine("Detected drive disconnected"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment