Detectando inserção drive USB e remoção usando o serviço de janelas e c #
-
03-07-2019 - |
Pergunta
Olhando para possibilidade de fazer uma aplicação distribuída USB
que irá iniciar automaticamente na inserção de um stick USB e desligamento quando retirar a vara
Vai usar .Net e C #.
Procurando por sugestão de como abordar isso usando C #?
Update:. Duas soluções possíveis de execução do presente como um serviço
- override WndProc
ou
- usando consulta WMI com ManagementEventWatcher
Solução
Você pode usar o WMI, é fácil e ele funciona muito melhor do que a solução WndProc com os serviços.
Aqui está um exemplo simples:
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();
Outras dicas
Isso funciona bem para mim, e você pode descobrir mais informações sobre o dispositivo.
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);
}
Adicionando ao post de VitalyB.
Para levantar um evento onde ANY dispositivo USB é inserido, use o seguinte:
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();
Isso vai elevar um evento sempre que um dispositivo USB é conectado. Ele funciona até mesmo com um Instruments DAQ Nacional que eu estou tentando detectar automaticamente.
O VitalyB resposta does't tampa remove do dispositivo. Eu mudei um pouco para disparar o evento tanto quando a mídia é Inserida e removido e também código para obter a letra da unidade da mídia inserida.
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();
}
}
}
A edição bit pouco sobre tudo resposta acima:
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();
}
}
Você também pode usar WMI para detectar eventos de inserção. É um pouco mais complicado do que monitorar para mensagens WM_CHANGEDEVICE, mas não requer um identificador de janela que pode ser útil se você estiver executando em segundo plano como um serviço.
Tente WM_CHANGEDEVICE manipulação .
Aqui está o que fizemos com C # .Net 4.0 sob um aplicativo WPF. Ainda estamos à procura de uma resposta à pergunta "Como saber qual tipo de dispositivo foi inserido / removido", mas este é um começo:
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;
}
}
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();
}
}
}