Detecting USB drive insertion and removal using windows service and c#

95,246

Solution 1

You can use WMI, it is easy and it works a lot better than WndProc solution with services.

Here is a simple example:

using System.Management;

ManagementEventWatcher watcher = new ManagementEventWatcher();
WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2");
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcher.Query = query;
watcher.Start();
watcher.WaitForNextEvent();

Solution 2

This works well for me, plus you can find out more information about the device.

using System.Management;

private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
{
    ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
    foreach (var property in instance.Properties)
    {
        Console.WriteLine(property.Name + " = " + property.Value);
    }
}

private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
    ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
    foreach (var property in instance.Properties)
    {
        Console.WriteLine(property.Name + " = " + property.Value);
    }
}            

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    WqlEventQuery insertQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");

    ManagementEventWatcher insertWatcher = new ManagementEventWatcher(insertQuery);
    insertWatcher.EventArrived += new EventArrivedEventHandler(DeviceInsertedEvent);
    insertWatcher.Start();

    WqlEventQuery removeQuery = new WqlEventQuery("SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'");
    ManagementEventWatcher removeWatcher = new ManagementEventWatcher(removeQuery);
    removeWatcher.EventArrived += new EventArrivedEventHandler(DeviceRemovedEvent);
    removeWatcher.Start();

    // Do something while waiting for events
    System.Threading.Thread.Sleep(20000000);
}

Solution 3

Adding to VitalyB's post.

To raise an event where ANY USB device is inserted, use the following:

var watcher = new ManagementEventWatcher();
var query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcher.Query = query;
watcher.Start();

This will raise an event whenever a USB device is plugged. It even works with a National Instruments DAQ that I'm trying to auto-detect.

Solution 4

VitalyB's answer does't cover remove of the device. I changed it a bit to trigger the event both when media is inserted and removed and also code to get the drive letter of the inserted media.

using System;
using System.Management;

namespace MonitorDrives
{
    class Program
    {
        public enum EventType
        {
            Inserted = 2,
            Removed = 3
        }

        static void Main(string[] args)
        {
            ManagementEventWatcher watcher = new ManagementEventWatcher();
            WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2 or EventType = 3");

            watcher.EventArrived += (s, e) =>
            {
                string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
                EventType eventType = (EventType)(Convert.ToInt16(e.NewEvent.Properties["EventType"].Value));

                string eventName = Enum.GetName(typeof(EventType), eventType);

                Console.WriteLine("{0}: {1} {2}", DateTime.Now, driveName, eventName);
            };

            watcher.Query = query;
            watcher.Start();

            Console.ReadKey();
        }
    }
}

Solution 5

A little bit edit on all above answer:

using System.Management;

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();

        bgwDriveDetector.DoWork += bgwDriveDetector_DoWork;
        bgwDriveDetector.RunWorkerAsync();
    }

    private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
    {
        string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
        MessageBox.Show(driveName + " inserted");
    }

    private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
    {
        string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
        MessageBox.Show(driveName + " removed");
    }

    void bgwDriveDetector_DoWork(object sender, DoWorkEventArgs e)
    {
        var insertQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
        var insertWatcher = new ManagementEventWatcher(insertQuery);
        insertWatcher.EventArrived += DeviceInsertedEvent;
        insertWatcher.Start();

        var removeQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
        var removeWatcher = new ManagementEventWatcher(removeQuery);
        removeWatcher.EventArrived += DeviceRemovedEvent;
        removeWatcher.Start();
    }
}
Share:
95,246
Kb.
Author by

Kb.

Currently trying to migrate complex scheduling data using C#, Teams and SQL with Dapper

Updated on September 19, 2021

Comments

  • Kb.
    Kb. over 2 years

    Looking into possibility of making an USB distributed application
    that will autostart on insertion of an USB stick and shutdown when removing the stick

    Will use .Net and C#.
    Looking for suggestion how to approach this using C#?


    Update: Two possible solutions implementing this as a service.
    - override WndProc
    or
    - using WMI query with ManagementEventWatcher

  • Kb.
    Kb. about 15 years
    @John Conrad: +1 WMI is a good choice. Also found a SO topic on this: stackoverflow.com/questions/39704/…
  • VitalyB
    VitalyB almost 14 years
    Actually WMI is much simpler solution. I'm posting it below as another solution.
  • Never Quit
    Never Quit almost 11 years
    That works fine but How can I get drive letter of inserted USB?
  • Never Quit
    Never Quit almost 11 years
    @Lee Taylor That works fine but How can I get drive letter of inserted USB?
  • Lee Taylor
    Lee Taylor almost 11 years
    @NeverQuit - I only edited the question, ask @Syn! Also, if you have a new question then feel free to create one.
  • Never Quit
    Never Quit almost 11 years
    @Syn That works fine but How can I get drive letter of inserted USB?
  • Kcvin
    Kcvin almost 11 years
    Any improvements as to figuring out which device was inserted?
  • VitalyB
    VitalyB over 9 years
    This article seems to be getting this information in Powershell. Shouldn't be too hard to translate that to C#.
  • samuelesque
    samuelesque over 9 years
    Works perfectly. Doesn't fire multiple events like some of the other answers here on insertion/removal. This should be the accepted answer.
  • Amit Lipman
    Amit Lipman almost 9 years
    Hi it works great for USB insertion! the above comment with "SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2" I don't know why but it doesn't work for me. I want the event to run both for insertion and removal. Do you now the line string which will make it happen? or where I can see all the string which the wqleventQuery receive? It's not listed on the MSDN wqleventQuery CTOR page ..
  • CularBytes
    CularBytes about 8 years
    @Kevin this can easily be found elsewhere to get the list of devices. Here is a full solution which I got to first. Only WM_DEVICECHANGE is fired for me. social.msdn.microsoft.com/Forums/vstudio/en-US/…
  • lambinator
    lambinator almost 8 years
    In your event handler, e.NewEvent.Properties["DriveName"].Value.ToString()
  • helder.tavares.silva
    helder.tavares.silva almost 8 years
    I agree with @samuelAndThe, this seems the best aproach. If you are looking for also detect changes to hard drives and not only usb drives you can use the 'Win32_DiskDrive' class
  • komodosp
    komodosp over 7 years
    This is great, but for some reason it's firing the event multiple times each time I plug in or out a device - do you know why this might be and how to prevent it?
  • Ashkan Mobayen Khiabani
    Ashkan Mobayen Khiabani over 7 years
    As you haven't posted your code its hard to tell, but may be you are attaching the event more than once.
  • ch271828n
    ch271828n almost 7 years
    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e), why do you have (object sender, DoWorkEventArgs e)???(I committed an edit suggestion for this.)
  • ch271828n
    ch271828n almost 7 years
    this is not a full code!!! so you need to replace several lines of VitalyB's answer to this.
  • Fidel
    Fidel over 6 years
    Nice enhancements Ashkan, it's nice to know when a drive is ejected too.
  • icbytes
    icbytes over 6 years
    Will this run on mono? Just asking, because started recently with that, and wmi is ms pure.
  • Kasun Koswattha
    Kasun Koswattha over 5 years
    DeviceName is not found in the e.NewEven.Properties.
  • Pavlin Marinov
    Pavlin Marinov over 5 years
    Everything is awesome but please remove that Thread.Sleep ^_^
  • spy
    spy about 5 years
    the query is clearly for volume changes, which has nothing to do usb added/removed. It doesn't even work for volume changes, at least on my system
  • stackmalux
    stackmalux almost 5 years
    using the above query is eating cpu resources, any idea why wmi causes this issue?
  • Aditya
    Aditya over 4 years
    What's the purpose of Thread.Sleep? The DeviceInsertedEvent still fires event after the BackgroundWorker call ends after this sleep times out
  • leumasme
    leumasme over 4 years
    Does this instantly trigger the event or does it check in an interval? / Is it possible for another Program / the user to read/write files from the drive before the event fires?
  • Callum Rogers
    Callum Rogers about 4 years
    For removal, you just need to do WHERE EventType = 2 OR EventType = 3. EventType of 2 means addition, 3 means removal, as per docs.microsoft.com/en-us/windows/win32/cimwin32prov/…
  • AmirSina Mashayekh
    AmirSina Mashayekh almost 4 years
    I think that Thread.Sleep is there to simulate a long application code. You can simply remove it.
  • AmirSina Mashayekh
    AmirSina Mashayekh almost 4 years
    Is there any way to detect Any USB device in this method? As you know other answers fire multiple events which is not good.