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

发布于 2024-07-14 06:01:40 字数 289 浏览 9 评论 0原文

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

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


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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

终止放荡 2024-07-21 06:01:41

您可以使用 WMI,它很简单,而且比带有服务的 WndProc 解决方案工作得更好。

这是一个简单的例子:

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

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();
霊感 2024-07-21 06:01:41

这对我来说效果很好,而且您还可以找到有关该设备的更多信息。

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

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);
}
妞丶爷亲个 2024-07-21 06:01:41

添加到 VitalyB 的帖子。

要在插入任何 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();

这将在插入 USB 设备时引发事件。 它甚至可以与我尝试自动检测的 National Instruments DAQ 配合使用。

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.

似狗非友 2024-07-21 06:01:41

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

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();
        }
    }
}
你对谁都笑 2024-07-21 06:01:41

对以上所有答案进行一点编辑:

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

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();
    }
}
最终幸福 2024-07-21 06:01:41

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

You can also use WMI to 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.

并安 2024-07-21 06:01:41

尝试 WM_CHANGEDEVICE 处理。

Try WM_CHANGEDEVICE handling.

流云如水 2024-07-21 06:01:41

我的完整答案可以在此处找到,作为要点,

我找到了确定驱动器盘符的答案此问题/答案的序列号
如何获取驱动器盘符使用 WMI 的 USB 设备

我修改了 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);
        }

My complete answer can be found here as 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

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

   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);
        }
梦里兽 2024-07-21 06:01:41

以下是我们在 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;
    }

}

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:

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

}
极度宠爱 2024-07-21 06:01:41
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();

       }





}

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

       }





}

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文