2009-03-06 8 views
50

Patrząc na możliwości dokonywania USB aplikacji rozproszonej
że będzie autostart na wstawienie pamięci USB i wyłączania podczas wyjmowania kij
Wykrywanie włożenie dysku USB i usuwanie za pomocą usługi Windows i C#

Używa NET i DO#.
Szukasz sugestii, jak podejść do tego przy użyciu C#?


Aktualizacja: Dwa możliwe rozwiązania implementujące to jako usługę.
- przesłonić WndProc
lub
- przy użyciu WMI frazę ManagementEventWatcher

+1

Dobre pytanie na służbie zatrzymującą to wydarzenie. Najpierw myślę, że musisz oznaczyć swoją usługę jako "pozwól na interakcję z komputerem", a następnie utwórz ukryte okno. Bezpieczniejszą opcją jest prawdopodobnie stworzenie aplikacji Windows, która działa przy starcie - może stworzyć okno, a następnie komunikować się z svc –

+0

Powiązane: http: // stackoverflow.com/questions/6003822/how-to-detect-a-usb-drive-has-was-plugged – DuckMaestro

Odpowiedz

44

Możesz używać WMI, jest to łatwe i działa dużo lepiej niż rozwiązanie WndProc z usługami.

Oto prosty przykład:

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

I to wszystko :)

+4

To działa dobrze, ale jak mogę uzyskać literę napędu z włożonego USB? –

+0

[Ten artykuł] (http://www.ravichaganti.com/blog/monitoring-volume-change-events-in-powershell-using-wmi/) wydaje się uzyskiwać tę informację w PowerShell. Nie powinno być zbyt trudne do przetłumaczenia tego na C#. – VitalyB

+3

W programie obsługi zdarzeń: 'e.NewEvent.Properties [" Nazwa dysku "]. Wartość.ToString()' – lambinator

5

Można również użyć WMI, aby wykryć zdarzenia wstawiania. Jest to nieco bardziej skomplikowane niż monitorowanie wiadomości WM_CHANGEDEVICE, ale nie wymaga uchwytu okna, który może być przydatny, jeśli działasz w tle jako usługa.

+2

@John Conrad: +1 WMI to dobry wybór. Znaleźliśmy również temat na ten temat: http://stackoverflow.com/questions/39704/wmi-and-win32devicechangeevent-wrong-event-type-returned –

+0

W rzeczywistości WMI jest znacznie prostszym rozwiązaniem. Zamieszczam to poniżej jako inne rozwiązanie. – VitalyB

4

Oto, co zrobiliśmy z C# .NET 4.0 w ramach aplikacji WPF. Jesteśmy wciąż szukają odpowiedzi na „jak stwierdzić, jaki typ urządzenia został dodany/usunięty”, ale jest to 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; 
    } 

} 
+2

Jakieś ulepszenia, aby dowiedzieć się, które urządzenie zostało włożone? – Kcvin

+0

@Kevin to można łatwo znaleźć gdzie indziej, aby uzyskać listę urządzeń. Oto pełne rozwiązanie, które dostałem jako pierwsze. Tylko WM_DEVICECHANGE został zwolniony za mnie. https://social.msdn.microsoft.com/Forums/vstudio/en-US/ea183afd-d070-4abd-8e00-a1784fdfedc5/detecting-usb-device-insertion-and-removal?forum=csharpgeneral – CularBytes

19

Dodawanie do postu vitalyb użytkownika.

Aby podnieść zdarzenie gdzie jest wstawiony ANY urządzenie USB, użyj następujących:

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

To podniesie zdarzenie, gdy urządzenie USB jest podłączone. Działa nawet z DAQ National Instruments, którą próbuję automatycznie wykryć.

+0

@Lee Taylor That działa dobrze, ale jak mogę uzyskać literę napędu z włożonego USB? –

+0

@NeverQuit - Edytowałem tylko pytanie, zapytaj @Syn! Ponadto, jeśli masz nowe pytanie, możesz je utworzyć. –

+0

@Syn To działa dobrze, ale jak mogę uzyskać literę napędu z włożonego USB? –

29

To działa dobrze dla mnie, plus możesz dowiedzieć się więcej informacji o urządzeniu.

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

Działa idealnie. Nie uruchamia wielu zdarzeń, takich jak niektóre z innych odpowiedzi tutaj podczas wstawiania/usuwania. To powinna być zaakceptowana odpowiedź. – samuelesque

+0

Zgadzam się z @samuelAnd, to wydaje się najlepszym podejściem. Jeśli szukasz również wykrywania zmian na dyskach twardych i nie tylko dyskach usb, możesz użyć klasy "Win32_DiskDrive" –

+0

'private void backgroundWorker1_DoWork (object sender, DoWorkEventArgs e)', dlaczego masz '(object sender, DoWorkEventArgs e) '??? (Popełniłem sugestię edycji dla tego.) – Turtle

11

Odpowiedź VitalyB nie obejmuje usunięcia urządzenia. Zmieniłem go trochę, aby wywołać zdarzenie, zarówno gdy nośniki wstawiono i usunięty, a także kod, aby uzyskać literę napędu włożonego nośnika.

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

To świetnie, ale z jakiegoś powodu wielokrotnie uruchamia zdarzenie za każdym razem, gdy podłączam lub odłączam urządzenie - czy wiesz, dlaczego tak się stało i jak temu zapobiec? – colmde

+0

Trudno powiedzieć, że nie opublikowałeś swojego kodu, ale być może dołączasz to wydarzenie więcej niż raz. –

+0

to nie jest *** pełny *** kod !!! więc musisz zastąpić kilka linii odpowiedzi VitalyB na to. – Turtle

2

Trochę edycji na wszystkie powyższe odpowiedzi:

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(); 
    } 
} 
Powiązane problemy