2013-04-26 18 views
27

システムにデバイスが追加または削除されたときにイベントを発生させる方法があるかどうかを知りたい。私は、USBフラッシュドライブが追加されたかどうか、またはマウスなどを検出できるようにしたいと考えています。私は周りを探索しようとしたが、私はこれを行う方法の何かを見つけることができません。デバイスの変更(追加/削除)イベントを確認する

アイデア?

答えて

55

アプリケーションでウィンドウを持っている場合、あなたはこのようなものを使用することができます

using System; 
using System.Runtime.InteropServices; 

internal static class UsbNotification 
{ 
    public const int DbtDevicearrival = 0x8000; // system detected a new device   
    public const int DbtDeviceremovecomplete = 0x8004; // device is gone  
    public const int WmDevicechange = 0x0219; // device change event  
    private const int DbtDevtypDeviceinterface = 5; 
    private static readonly Guid GuidDevinterfaceUSBDevice = new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED"); // USB devices 
    private static IntPtr notificationHandle; 

    /// <summary> 
    /// Registers a window to receive notifications when USB devices are plugged or unplugged. 
    /// </summary> 
    /// <param name="windowHandle">Handle to the window receiving notifications.</param> 
    public static void RegisterUsbDeviceNotification(IntPtr windowHandle) 
    { 
     DevBroadcastDeviceinterface dbi = new DevBroadcastDeviceinterface 
     { 
      DeviceType = DbtDevtypDeviceinterface, 
      Reserved = 0, 
      ClassGuid = GuidDevinterfaceUSBDevice, 
      Name = 0 
     }; 

     dbi.Size = Marshal.SizeOf(dbi); 
     IntPtr buffer = Marshal.AllocHGlobal(dbi.Size); 
     Marshal.StructureToPtr(dbi, buffer, true); 

     notificationHandle = RegisterDeviceNotification(windowHandle, buffer, 0); 
    } 

    /// <summary> 
    /// Unregisters the window for USB device notifications 
    /// </summary> 
    public static void UnregisterUsbDeviceNotification() 
    { 
     UnregisterDeviceNotification(notificationHandle); 
    } 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags); 

    [DllImport("user32.dll")] 
    private static extern bool UnregisterDeviceNotification(IntPtr handle); 

    [StructLayout(LayoutKind.Sequential)] 
    private struct DevBroadcastDeviceinterface 
    { 
     internal int Size; 
     internal int DeviceType; 
     internal int Reserved; 
     internal Guid ClassGuid; 
     internal short Name; 
    } 
} 

は、ここでは、WPFウィンドウ(Windowsフォームが似ている)から、それを使用する方法は次のとおりです。

protected override void OnSourceInitialized(EventArgs e) 
    { 
     base.OnSourceInitialized(e); 

     // Adds the windows message processing hook and registers USB device add/removal notification. 
     HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle); 
     if (source != null) 
     { 
      windowHandle = source.Handle; 
      source.AddHook(HwndHandler); 
      UsbNotification.RegisterUsbDeviceNotification(windowHandle); 
     } 
    } 

    /// <summary> 
    /// Method that receives window messages. 
    /// </summary> 
    private IntPtr HwndHandler(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled) 
    { 
     if (msg == UsbNotification.WmDevicechange) 
     { 
      switch ((int)wparam) 
      { 
       case UsbNotification.DbtDeviceremovecomplete: 
        Usb_DeviceRemoved(); // this is where you do your magic 
        break; 
       case UsbNotification.DbtDevicearrival: 
        Usb_DeviceAdded(); // this is where you do your magic 
        break; 
      } 
     } 

     handled = false; 
     return IntPtr.Zero; 
    } 

Windowsフォームの使用例(さらに簡単です):

public Form1() 
{ 
    InitializeComponent(); 
    UsbNotification.RegisterUsbDeviceNotification(this.Handle); 
} 

protected override void WndProc(ref Message m) 
{ 
    base.WndProc(ref m); 
     if (m.Msg == UsbNotification.WmDevicechange) 
    { 
     switch ((int)m.WParam) 
     { 
      case UsbNotification.DbtDeviceremovecomplete: 
       Usb_DeviceRemoved(); // this is where you do your magic 
       break; 
      case UsbNotification.DbtDevicearrival: 
       Usb_DeviceAdded(); // this is where you do your magic 
       break; 
     } 
    } 
} 
+3

ウィンドウがない場合は、ウィンドウを作成する必要があります。 [メッセージのみのウィンドウ](http://msdn.microsoft.com/en-us/library/windows/desktop/ms632599.aspx#message_only)は完全にうまく動作します。 WinFormsの場合は、['NativeWindow'クラス](http://msdn.microsoft.com/en-us/library/system.windows.forms.nativewindow.aspx)を使用できます。 –

+0

私には窓があります。しかし、私はちょっとあなたが持っているコードの第2部分で混乱しています。 OnSourceInitializedは、オブジェクトが定義されていないというエラーを表示します。また、WindowInteropHelperはディレクティブを使用していないと言っています。しかし、 "using System.Windows.Interop"はエラーです。最後に、HwndSourceは「現状では存在しない」と思われます。 –

+0

FYI、私はこのような "mainForm = new MainForm();のような私のウィンドウのフォームを作成しています –

2

受け入れられる回答は優れていますが、ただし、USBデバイスでのみ動作します。

、それはすべてのデバイス(および、必要に応じてフィルターUSB)で動作するよう、以下のわずかに変更されたクラスを使用するには:

static class DeviceNotification { 
    //https://msdn.microsoft.com/en-us/library/aa363480(v=vs.85).aspx 
    public const int DbtDeviceArrival = 0x8000; // system detected a new device   
    public const int DbtDeviceRemoveComplete = 0x8004; // device is gone  
    public const int DbtDevNodesChanged = 0x0007; //A device has been added to or removed from the system. 

    public const int WmDevicechange = 0x0219; // device change event  
    private const int DbtDevtypDeviceinterface = 5; 
    //https://msdn.microsoft.com/en-us/library/aa363431(v=vs.85).aspx 
    private const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 4; 
    private static readonly Guid GuidDevinterfaceUSBDevice = new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED"); // USB devices 
    private static IntPtr notificationHandle; 

    /// <summary> 
    /// Registers a window to receive notifications when devices are plugged or unplugged. 
    /// </summary> 
    /// <param name="windowHandle">Handle to the window receiving notifications.</param> 
    /// <param name="usbOnly">true to filter to USB devices only, false to be notified for all devices.</param> 
    public static void RegisterDeviceNotification(IntPtr windowHandle, bool usbOnly = false) { 
     var dbi = new DevBroadcastDeviceinterface { 
      DeviceType = DbtDevtypDeviceinterface, 
      Reserved = 0, 
      ClassGuid = GuidDevinterfaceUSBDevice, 
      Name = 0 
     }; 

     dbi.Size = Marshal.SizeOf(dbi); 
     IntPtr buffer = Marshal.AllocHGlobal(dbi.Size); 
     Marshal.StructureToPtr(dbi, buffer, true); 

     notificationHandle = RegisterDeviceNotification(windowHandle, buffer, usbOnly ? 0 : DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); 
    } 

    /// <summary> 
    /// Unregisters the window for device notifications 
    /// </summary> 
    public static void UnregisterDeviceNotification() { 
     UnregisterDeviceNotification(notificationHandle); 
    } 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags); 

    [DllImport("user32.dll")] 
    private static extern bool UnregisterDeviceNotification(IntPtr handle); 

    [StructLayout(LayoutKind.Sequential)] 
    private struct DevBroadcastDeviceinterface { 
     internal int Size; 
     internal int DeviceType; 
     internal int Reserved; 
     internal Guid ClassGuid; 
     internal short Name; 
    } 
} 

RegisterDeviceNotificationを呼び出すときに、キーの変更がFlagsパラメータである(https://msdn.microsoft.com/en-us/library/aa363431(v=vs.85).aspxを参照)、設定された場合0の代わりに4に変更すると、ClassGuidパラメータは無視され、すべてのデバイスに登録されます。

+0

私はこのコードを、検出されたオーディオデバイスが削除されたことの根拠として使用しました。しかし、私は、ハンドラが削除されたデバイスのクラス内のすべてのデバイスに対して呼び出されていることに気づいた。だから私は11のオーディオデバイスを持って、私は1つのデバイスのプラグを抜くと、これは11回呼び出される原因になります。それは期待された行動ですか? – Jammer

+0

受け入れられた答えはどうですか? –

関連する問題