Visualizzazione post con etichetta USB. Mostra tutti i post
Visualizzazione post con etichetta USB. Mostra tutti i post

giovedì 21 luglio 2011

Detecting USB microphone insertion/removal in C# .Net 4.0 WPF

I'm working on a C# .Net 4.0 WPF project that must detect the insertion or removal of an USB microphone.
The code should be implemented in a C# class library.
Since .Net 4.0 doesn't have classes able to detect the insertion or removal of an USB device, the solution is hooking the message WM_DEVICECHANGE, then find out which device changed in order to be sure that the device is the one desired and not some other device.
The first issue to solve is that we don't have any hWnd handle in a class library, so we need to create a fake window in order to hook his window procedure:


HwndSource hwndSource = new HwndSource(0, 0, 0, 0, 0, "fake", IntPtr.Zero);
if (hwndSource != null)  //Attaching to window procedure
    hwndSource.AddHook(new HwndSourceHook(this.hwndSourceHook));

//the window procedure
IntPtr hwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
{
    if (msg == WM_DEVICECHANGE)   
   {
      if ((int)wParam == DBT_DEVICEARRIVAL)
     {   
        DEV_BROADCAST_DEVICEINTERFACE info = (DEV_BROADCAST_DEVICEINTERFACE)   
Marshal.PtrToStructure(lParam, typeof(DEV_BROADCAST_DEVICEINTERFACE));   
      }   
      else if ((int)wParam == DBT_DEVICEREMOVECOMPLETE)
     {
      }
      else if ((int)wParam == DBT_DEVNODES_CHANGED)
     {
     }
  }  
  return IntPtr.Zero;
}


The second problem is to identify the device by the GUID class.
Several microphones by Philips, Olympus or Dictaphone are multicomposite devices.
It means that when you plugin the microphone you get 5 or 6 WM_DEVICECHANGE messages.
So it is preferable to filter the device class using the RegisterDeviceNotification API.

DEV_BROADCAST_DEVICEINTERFACE notificationFilter = new DEV_BROADCAST_DEVICEINTERFACE();
int size = Marshal.SizeOf(notificationFilter);
notificationFilter.dbcc_size = size;
notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
notificationFilter.dbcc_reserved = 0;
notificationFilter.dbcc_classguid = new Guid(MediaClassID).ToByteArray();
IntPtr buffer = IntPtr.Zero;
buffer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(notificationFilter, buffer, true);
IntPtr result = RegisterDeviceNotification(this._hwndSource.Handle, buffer, (Int32)(DEVICE_NOTIFY.DEVICE_NOTIFY_WINDOW_HANDLE));

The class guid are stored in the registry:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses
If you want find out the class guid of your device, use the parameter DEVICE_NOTIFY_ALL_INTERFACE_CLASSES in RegisterDeviceNotification API, plug in the device into the USB port and read the guid in the DEV_BROADCAST_DEVICEINTERFACE structure.

I found out the following classes used by USB microphones:
KSCATEGORY_CAPTURE = "{65E8773D-8F56-11D0-A3B9-00A0C9223196}"
KSCATEGORY_AUDIO = "{6994AD04-93EF-11D0-A3CC-00A0C9223196}"

Here attached a MVVM project using the USBDetector class