Start a action when a USB device is added [duplicate]

I try to start an application, when a special USB device is added.

In the windows event system I can use the event: Microsoft-Windows-DriverFrameworks-UserMode -> Event ID: 2100

This event is raised, when a new device is added. This works fine, but I will find out which drive was added.

Within the event system I found, that additional information is available, but how I can use this information?

Is it possible to get the information, which drive was added? Or is it possible to hand over the additional data of the event system to a user program (command line parameter)?


Solution 1:

I don't know how you could do this without programming, but I've written applications that do exactly what you want. So here's how to implement it.

When a new device is added to the system (like a USB drive), Windows sends out the WM_DEVICECHANGE message to all top-level application windows. The event to look for is DBT_DEVICEARRIVAL (which is indicated through the wParam of that message).

The lParam of the message should first be treated as a DEV_BROADCAST_HDR. The header will indicate (through it's dbch_devicetype member) if the device is actually a volume (DBT_DEVTYP_VOLUME). If it is a volume, you can reinterpret the lParam of the original message as a DEV_BROADCAST_VOLUME. This structure will then indicate the assigned drive letters through the dbcv_unitmask member.

To make it (hopefully) a bit clearer, here's some working code from an implementation of mine in C#:

private static void MessageEventsMessageReceived( object sender, MessageReceivedEventArgs e ) {
  // Check if this is a notification regarding a new device.);
  if( e.Message.WParam == (IntPtr)NativeMethods.DBT_DEVICEARRIVAL ) {
    Log.Info( "New device has arrived" );

    // Retrieve the device broadcast header
    NativeMethods.DEV_BROADCAST_HDR deviceBroadcastHeader =
      (NativeMethods.DEV_BROADCAST_HDR)
      Marshal.PtrToStructure( e.Message.LParam, typeof( NativeMethods.DEV_BROADCAST_HDR ) );

    if( (int)NativeMethods.DBT_DEVTYP.DBT_DEVTYP_VOLUME == deviceBroadcastHeader.dbch_devicetype ) {
      Log.Info( "Device type is a volume (good)." );

      NativeMethods.DEV_BROADCAST_VOLUME volumeBroadcast =
        (NativeMethods.DEV_BROADCAST_VOLUME)
        Marshal.PtrToStructure( e.Message.LParam, typeof( NativeMethods.DEV_BROADCAST_VOLUME ) );

      Log.InfoFormat( "Unit masked for new device is: {0}", volumeBroadcast.dbcv_unitmask );

      int driveIndex = 1;
      int bitCount = 1;
      while( bitCount <= 0x2000000 ) {
        driveIndex++;
        bitCount *= 2;

        if( ( bitCount & volumeBroadcast.dbcv_unitmask ) != 0 ) {
          Log.InfoFormat( "Drive index {0} is set in unit mask.", driveIndex );
          Log.InfoFormat( "Device provides drive: {0}:", (char)( driveIndex + 64 ) );

          int index = driveIndex;
          char driveLetter = (char)( driveIndex + 64 );
          // Do something with driveLetter

        }
      }

    } else {
      Log.InfoFormat( "Device type is {0} (ignored).", Enum.GetName( typeof( NativeMethods.DBT_DEVTYP ), deviceBroadcastHeader.dbch_devicetype ) );
    }
  }
}