2009-03-06 4 views
50

Глядя на возможности, сделав USB распределенное приложение
, который будет автозапуск при вставке на палке USB и выключение при снятии палки
Обнаружение вставки USB диска и удаление с помощью службы Windows и C#

будет использовать .Net и C#.
Ищете предложение, как подойти к этому с помощью C#?


Обновление: два возможных решения, реализующих это как сервис.
- переопределить WndProc
или
- используя запрос WMI с ManagementEventWatcher

+1

Хороший вопрос о службе отлова это событие. Моя первая мысль заключается в том, что вы должны пометить свою службу как «разрешить взаимодействие с рабочим столом», а затем создать скрытое окно. Более безопасный вариант, вероятно, для создания приложения Windows, которое запускается при запуске - он может создать окно, а затем связаться с svc –

+0

. Связанный: http: // stackoverflow.com/questions/6003822/how-to-detect-a-usb-drive-has-was-заглушен – DuckMaestro

ответ

44

Вы можете использовать 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(); 

И вот это :)

+4

Это прекрасно работает, но как я могу получить букву с диска USB? –

+0

[Эта статья] (http://www.ravichaganti.com/blog/monitoring-volume-change-events-in-powershell-using-wmi/), похоже, получает эту информацию в Powershell. Не следует слишком сложно перевести это на C#. – VitalyB

+3

В вашем обработчике событий 'e.NewEvent.Properties [" DriveName "]. Value.ToString()' – lambinator

5

Вы также можете использовать WMI для обнаружения событий вставки. Это немного сложнее, чем мониторинг сообщений WM_CHANGEDEVICE, но для этого не требуется дескриптор окна, который может быть полезен, если вы работаете в фоновом режиме как служба.

+2

@ Джон Конрад: +1 WMI - хороший выбор. Также была найдена тема SO: http://stackoverflow.com/questions/39704/wmi-and-win32devicechangeevent-wrong-event-type-returned –

+0

На самом деле WMI - гораздо более простое решение. Я отправляю его ниже в качестве другого решения. – VitalyB

4

Вот что мы сделали с C# .NET 4.0 под приложение WPF. Мы все еще ищем ответ на «Как узнать тип устройства был вставлен/удален», но это только начало:

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

} 
+2

Какие-либо улучшения в отношении определения того, какое устройство было вставлено? – Kcvin

+0

@Kevin это можно легко найти в другом месте, чтобы получить список устройств. Вот полное решение, которое я получил в первую очередь. Только WM_DEVICECHANGE уволен для меня. https://social.msdn.microsoft.com/Forums/vstudio/en-US/ea183afd-d070-4abd-8e00-a1784fdfedc5/detecting-usb-device-insertion-and-removal?forum=csharpgeneral – CularBytes

19

Добавление к сообщению VitalyB в.

Чтобы вызвать событие, когда вставлен ANY 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. Он даже работает с DAQ National Instruments, который я пытаюсь автоматически обнаружить.

+0

@Lee Taylor That работает отлично, но как я могу получить букву диска с вставленным USB? –

+0

@NeverQuit - я только отредактировал вопрос, спросите @Syn! Кроме того, если у вас есть новый вопрос, не стесняйтесь его создавать. –

+0

@Syn Это работает отлично, но как я могу получить букву диска с вставленным USB? –

29

Это хорошо работает для меня, а также вы можете узнать больше информации об устройстве.

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

Работает отлично. Не запускает несколько событий, например, некоторые из других ответов здесь при вставке/удалении. Это должен быть принятый ответ. – samuelesque

+0

Я согласен с @samuelAndThe, это кажется лучшим aproach. Если вы ищете также обнаружение изменений на жестких дисках, а не только USB-накопители, вы можете использовать класс «Win32_DiskDrive» –

+0

'private void backgroundWorker1_DoWork (object sender, DoWorkEventArgs e)', почему у вас есть (объект отправителя, DoWorkEventArgs e) '??? (я сделал предложение для редактирования для этого.) – Turtle

11

Ответ 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(); 
     } 
    } 
} 
+0

Это замечательно, но по какой-то причине оно запускает событие несколько раз каждый раз, когда я подключаю или выхожу из устройства - знаете ли вы, почему это может быть и как его предотвратить? – colmde

+0

Поскольку вы не разместили свой код, его сложно сказать, но, возможно, вы присоединяете событие более одного раза. –

+0

это не *** полный *** код !!! поэтому вам нужно заменить несколько строк ответа VitalyB на это. – Turtle

2

Немного едит на все выше ответ:

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