使用windows服务和c#检测USB驱动器的插入和移除

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/620144/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 10:33:28  来源:igfitidea点击:

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

c#.netwindowswindows-serviceswmi

提问by Kb.

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

研究制作 USB 分布式应用程序的可能性,该应用程序
将在插入 USB 记忆棒时自动启动并在移除记忆棒时关闭

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

将使用 .Net 和 C#。
寻找如何使用 C# 解决这个问题的建议?



更新:将此作为服务实现的两种可能的解决方案。


- 覆盖 WndProc





- 使用 WMI 查询与 ManagementEventWatcher

采纳答案by VitalyB

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

您可以使用 WMI,它很简单,而且比 WndProc 解决方案和服务要好得多。

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();

回答by Mike Marshall

Try WM_CHANGEDEVICEhandling.

尝试WM_CHANGEDEVICE处理。

回答by John Conrad

You can also use WMIto detect insertion events. It's a little bit more complicated than monitoring for WM_CHANGEDEVICE messages, but it does not require a window handle which may be useful if you are running in the background as a service.

您还可以使用WMI来检测插入事件。它比监视 WM_CHANGEDEVICE 消息稍微复杂一点,但它不需要窗口句柄,如果您作为服务在后台运行,这可能很有用。

回答by Lance Cleveland

Here is what we did with C# .Net 4.0 under a WPF app. We are still searching for an answer to "how to tell WHICH device type was inserted/removed", but this is a start:

这是我们在 WPF 应用程序下使用 C# .Net 4.0 所做的。我们仍在寻找“如何判断插入/删除了哪种设备类型”的答案,但这是一个开始:

    using System.Windows.Interop;
...
public partial class MainWindow : Window
 {
    ...
    public MainWindow()
    {
    ...
    }

    //============================================================
    // WINDOWS MESSAGE HANDLERS
    // 

    private const int WM_DEVICECHANGE = 0x0219;  // int = 537
    private const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x00000004; 

    /// <summary>
    ///
    /// </summary>
    /// <param name="e"></param>
    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
        source.AddHook(WndProc);
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_DEVICECHANGE)
        {
            ReadDongleHeader();
        }
        return IntPtr.Zero;
    }

}

回答by Syn

Adding to VitalyB's post.

添加到 VitalyB 的帖子。

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

要引发插入任何USB 设备的事件,请使用以下命令:

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.

每当插入 USB 设备时,这都会引发一个事件。它甚至可以与我试图自动检测的 National Instruments DAQ 一起使用。

回答by Phil Minor

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);
}

回答by Ashkan Mobayen Khiabani

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

VitalyB 的回答不包括移除设备。我对其进行了一些更改,以在插入移除媒体时触发事件,以及获取插入媒体的驱动器号的代码。

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();
        }
    }
}

回答by lzutao

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();
    }
}

回答by Milind Morey

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management;
using System.ComponentModel;

namespace ConsoleApplication4
{
  public  class usbState
    {
       public usbState()
        {

        }

   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);
       }
   } 

    public  void bgwDriveDetector_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();
    }

}



class Class1
{
       private static void Main(string[] args)
      {
          usbState  usb= new usbState();



          BackgroundWorker bgwDriveDetector = new BackgroundWorker();
          bgwDriveDetector.DoWork += usb.bgwDriveDetector_DoWork;
          bgwDriveDetector.RunWorkerAsync();
          bgwDriveDetector.WorkerReportsProgress = true;
          bgwDriveDetector.WorkerSupportsCancellation = true;

         // System.Threading.Thread.Sleep(100000);
           Console.ReadKey();

       }





}

}

回答by dtwk2

My complete answer can be found hereas a gist

我的完整答案可以在这里找到作为要点

I found the answer to determining the drive letter from the serial # from this question/answer How to get the drive letter of USB device using WMI

我从这个问题/答案中找到了从序列号中确定驱动器号的答案 How to get the drive letter of USB device using WMI

And I modified Phil Minor's code to make it reactive:

我修改了 Phil Minor 的代码以使其具有反应性:

   public class UsbDetector : IUsbDetector
    {
        private const string Query = "SELECT * FROM {0} WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'";
        private const string CreationEvent = "__InstanceCreationEvent";
        private const string DeletionEvent = "__InstanceDeletionEvent";
        private const int ReplayNumber = 1;

        private readonly Subject<USBDeviceInfo> adds = new Subject<USBDeviceInfo>();
        private readonly Subject<USBDeviceInfo> removes = new Subject<USBDeviceInfo>();

        public UsbDetector()
        {
            var bgwDriveDetector = new BackgroundWorker();
            bgwDriveDetector.DoWork += DoWork;
            bgwDriveDetector.RunWorkerAsync();
        }

        public IObservable<USBDeviceInfo> Adds => adds.AsObservable();

        public IObservable<USBDeviceInfo> Removes => removes.AsObservable();


        private void DoWork(object sender, DoWorkEventArgs e)
        {
            SubscribeToEvent(CreationEvent, adds);
            SubscribeToEvent(DeletionEvent, removes);
        }

        private static void SubscribeToEvent(string eventType, IObserver<USBDeviceInfo> observer)
        {
            WqlEventQuery wqlEventQuery = new WqlEventQuery(string.Format(Query, eventType));
            ManagementEventWatcher insertWatcher = new ManagementEventWatcher(wqlEventQuery);

            var observable = Observable.FromEventPattern<EventArrivedEventHandler, EventArrivedEventArgs>(
                h => insertWatcher.EventArrived += h,
                h => insertWatcher.EventArrived -= h).Replay(ReplayNumber);

            observable.Connect();
            observable.Select(a => a.EventArgs).Select(MapEventArgs).Subscribe(observer);
            insertWatcher.Start();
        }


        private static USBDeviceInfo MapEventArgs(EventArrivedEventArgs e)
        {
            ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];

            string deviceId = (string)instance.GetPropertyValue("DeviceID");
            string serialNr = deviceId.Substring(deviceId.LastIndexOf('\')).Replace("\", "");
            char driveLetter = GetDriveLetter(serialNr).First();

            return new USBDeviceInfo(deviceId, serialNr, driveLetter);
        }