C# USB Detection - winform and WPF

Win From Version:

代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Windows.Forms;
using  System.Management;
using  System.Runtime.InteropServices;


namespace  SyncContactDemo
{
    
class  DriverWindow : NativeWindow, IDisposable
    {
        
//  Contains information about a logical volume.

        [StructLayout(LayoutKind.Sequential)]
        
public   struct  DEV_BROADCAST_VOLUME
        {
            
public   int  dbcv_size;             //  size of the struct
             public   int  dbcv_devicetype;         //  DBT_DEVTYP_VOLUME
             public   int  dbcv_reserved;         //  reserved; do not use
             public   int  dbcv_unitmask;         //  Bit 0=A, bit 1=B, and so on (bitmask)
             public   short  dbcv_flags;         //  DBTF_MEDIA=0x01, DBTF_NET=0x02 (bitmask)
        }


        
private   const   int  WM_DEVICECHANGE  =   0x0219 ;                 //  device state change
         private   const   int  DBT_DEVICEARRIVAL  =   0x8000 ;             //  detected a new device
         private   const   int  DBT_DEVICEQUERYREMOVE  =   0x8001 ;         //  preparing to remove
         private   const   int  DBT_DEVICEREMOVECOMPLETE  =   0x8004 ;     //  removed 
         private   const   int  DBT_DEVTYP_VOLUME  =   0x00000002 ;         //  logical volume


        
public  DriverWindow()
        {
            
//  create a generic window with no class name
             base .CreateHandle( new  CreateParams());
        }


        
public   void  Dispose()
        {
            
base .DestroyHandle();
            GC.SuppressFinalize(
this );
        }

        
protected   override   void  WndProc( ref  Message message)
        {
            
base .WndProc( ref  message);

            
if  ((message.Msg  ==  WM_DEVICECHANGE)  &&  (message.LParam  !=  IntPtr.Zero))
            {
                
switch  (message.WParam.ToInt32())
                {
                    
case  DBT_DEVICEARRIVAL:
                        SignalDeviceChange(UsbStateChange.Added);
                        
break ;

                    
case  DBT_DEVICEQUERYREMOVE:
                        
//  can intercept
                         break ;

                    
case  DBT_DEVICEREMOVECOMPLETE:
                        SignalDeviceChange(UsbStateChange.Removed);
                        
break ;
                }
            }
        }
        
public   event  UsbStateChangedEventHandler StateChanged;

        
private   void  SignalDeviceChange(UsbStateChange state)
        {

            
if  (StateChanged  !=   null )
            {
                StateChanged(
new  UsbStateChangedEventArgs(state));
            }
        }

    }
    
public   delegate   void  UsbStateChangedEventHandler(UsbStateChangedEventArgs e);
    
public   enum  UsbStateChange
    {

        
///   <summary>
        
///  A device has been added and is now available.
        
///   </summary>

        Added,


        
///   <summary>
        
///  A device is about to be removed;
        
///  allows consumers to intercept and deny the action.
        
///   </summary>

        Removing,


        
///   <summary>
        
///  A device has been removed and is no longer available.
        
///   </summary>

        Removed
    }

    
public   class  UsbStateChangedEventArgs : EventArgs
    {

        
///   <summary>
        
///  Initialize a new instance with the specified state and disk.
        
///   </summary>
        
///   <param name="state"> The state change code. </param>
        
///   <param name="disk"> The USB disk description. </param>

        
public  UsbStateChangedEventArgs(UsbStateChange state)
        {
            
this .State  =  state;
        }

        
///   <summary>
        
///  Gets the state change code.
        
///   </summary>

        
public  UsbStateChange State
        {
            
get ;
            
private   set ;
        }
    }
}

 

 

Override the WndProc(ref Message message) method is core code, which need winform support, so it can not be used in console application and WPF application.

in the win from code, we can use it like 

 

  DriverWindow dw  =   new  DriverWindow();
            dw.StateChanged 
+=   new  UsbStateChangedEventHandler(dw_StateChanged);

 

 

The WPF version:

 

代码
using  System.Runtime.InteropServices;
using  System;
namespace  Lenovo.Common.Devices
{
    
public   class  Win32
    {

        
public   const   int  DEVICE_NOTIFY_SERVICE_HANDLE  =   1 ;
        
public   const   int  DEVICE_NOTIFY_WINDOW_HANDLE  =   0 ;
        
public   const   int  DEVICE_NOTIFY_ALL_INTERFACE_CLASSES  =   4 ;

        [Flags]
        
public   enum  DEVICE_NOTIFY :  uint
        {
            DEVICE_NOTIFY_WINDOW_HANDLE 
=   0x00000000 ,
            DEVICE_NOTIFY_SERVICE_HANDLE 
=   0x00000001 ,
            DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 
=   0x00000004
        }


        
public   const   int  SERVICE_CONTROL_STOP  =   0x00000001 ;
        
public   const   int  SERVICE_CONTROL_DEVICEEVENT  =   0x00000011 ;
        
public   const   int  SERVICE_CONTROL_SHUTDOWN  =   0x00000005 ;
   
        
/* DBT_DEVTYP_DEVICEINTERFACE 0x00000005
            Class of devices. This structure is a DEV_BROADCAST_DEVICEINTERFACE structure.
 
            DBT_DEVTYP_HANDLE   0x00000006
            File system handle. This structure is a DEV_BROADCAST_HANDLE structure.
 
            DBT_DEVTYP_OEM  0x00000000
            OEM- or IHV-defined device type. This structure is a DEV_BROADCAST_OEM structure.
 
            DBT_DEVTYP_PORT 0x00000003
            Port device (serial or parallel). This structure is a DEV_BROADCAST_PORT structure.
 
            DBT_DEVTYP_VOLUME 0x00000002
            Logical volume. This structure is a DEV_BROADCAST_VOLUME structure.
 
*/

        
public   const   int  DBT_DEVTYP_DEVICEINTERFACE  =   0x00000005 ;
        
public   const   int  DBT_DEVTYP_HANDLE  =   0x00000006 ;
        
public   const   int  DBT_DEVTYP_OEM  =   0x00000000 ;
        
public   const   int  DBT_DEVTYP_PORT  =   0x00000003 ;
        
public   const   int  DBT_DEVTYP_VOLUME  =   0x00000002 ;


        
public   const   int  WM_DEVICECHANGE  =   0x0219 ;                 //  device state change
         public   const   int  DBT_DEVICEARRIVAL  =   0x8000 ;             //  detected a new device
         public   const   int  DBT_DEVICEQUERYREMOVE  =   0x8001 ;         //  preparing to remove
         public   const   int  DBT_DEVICEREMOVECOMPLETE  =   0x8004 ;     //  removed 
         public   const   int  DBT_DEVNODES_CHANGED  =   0x0007 // A device has been added to or removed from the system.


        [DllImport(
" user32.dll " , SetLastError  =   true )]
        
public   static   extern  IntPtr RegisterDeviceNotification(IntPtr intPtr, IntPtr notificationFilter,  uint  flags);

        [DllImport(
" user32.dll " , CharSet  =  CharSet.Auto)]
        
public   static   extern   uint  UnregisterDeviceNotification(IntPtr hHandle);

        [StructLayout(LayoutKind.Sequential, CharSet 
=  CharSet.Unicode)]
        
public   struct  DEV_BROADCAST_DEVICEINTERFACE
        {
            
public   int  dbcc_size;
            
public   int  dbcc_devicetype;
            
public   int  dbcc_reserved;
            
// public IntPtr dbcc_handle;
            
// public IntPtr dbcc_hdevnotify;
            [MarshalAs(UnmanagedType.ByValArray, ArraySubType  =  UnmanagedType.U1, SizeConst  =   16 )]
            
public   byte [] dbcc_classguid;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst 
=   128 )]
            
public  Char[] dbcc_name;
            
// public byte dbcc_data;
            
// public byte dbcc_data1; 
        
        }

        [StructLayout(LayoutKind.Sequential)]
        
public   struct  DEV_BROADCAST_HDR
        {
            
public   int  dbcc_size;
            
public   int  dbcc_devicetype;
            
public   int  dbcc_reserved;
        }

        [StructLayout(LayoutKind.Sequential)]
        
public   struct  DEV_BROADCAST_HANDLE
        {
            
public   int  dbch_size;
            
public   int  dbch_devicetype;
            
public   int  dbch_reserved;
            
public  IntPtr dbch_handle;
            
public  IntPtr dbch_hdevnotify;
            
public  Guid dbch_eventguid;
            
public   long  dbch_nameoffset;
            
public  Byte dbch_data;
            
public  Byte dbch_data1;
        }
    }
}

 

 

 

代码
using  System.Runtime.InteropServices;
using  System;

namespace  Lenovo.Common.Devices
{
    
public   delegate   void  UsbStateChangedEventHandler( bool  arrival);
    
public   class  UsbDetector
    {
        
public   enum  WM_DEVICECHANGE_WPPARAMS
        {
            DBT_DEVICEARRIVAL 
=   0x8000 ,
            DBT_DEVICEQUERYREMOVE 
=   0x8001 ,
            DBT_DEVICEREMOVECOMPLETE 
=   0x8004 ,
            DBT_CONFIGCHANGECANCELED 
=   0x19 ,
            DBT_CONFIGCHANGED 
=   0x18 ,
            DBT_CUSTOMEVENT 
=   0x8006 ,
            DBT_DEVICEQUERYREMOVEFAILED 
=   0x8002 ,
            DBT_DEVICEREMOVEPENDING 
=   0x8003 ,
            DBT_DEVICETYPESPECIFIC 
=   0x8005 ,
            DBT_DEVNODES_CHANGED 
=   0x7 ,
            DBT_QUERYCHANGECONFIG 
=   0x17 ,
            DBT_USERDEFINED 
=   0xFFFF
        }
        
const   int  WM_DEVICECHANGE  =   0x0219 ;

        
public  IntPtr HwndHandler(IntPtr hwnd,  int  msg, IntPtr wParam, IntPtr LParam,  ref   bool  handled)
        {
            ProcessWinMessage(msg, wParam, LParam);
          
//   handled = false;
             return  IntPtr.Zero;
        }

        
public   event  UsbStateChangedEventHandler StateChanged;

        
public   void  ProcessWinMessage( int  msg, IntPtr wParam, IntPtr LParam)
        {
          
//   if ((msg == WM_DEVICECHANGE) && (LParam != IntPtr.Zero))
             if  (msg  ==  WM_DEVICECHANGE) 
            {
                
switch  (wParam.ToInt32())
                {
                    
case  Win32.DBT_DEVICEARRIVAL:
                        
if  (StateChanged  !=   null )
                        {
                            StateChanged(
true );
                        }
                        
break ;
                    
case  Win32.DBT_DEVICEREMOVECOMPLETE:
                        
if  (StateChanged  !=   null )
                        {
                            StateChanged(
false );
                        }
                        
break ;
                    
case  Win32.DBT_DEVNODES_CHANGED:
                        
if  (StateChanged  !=   null )
                        {
                            StateChanged(
false );
                        }
                        
break ;
                    
default :
                        
break ;
                }

            }
        }

       
//  private const string USBClassID = "c671678c-82c1-43f3-d700-0049433e9a4b";
        
// http://msdn.microsoft.com/en-us/library/ff545972.aspx
         private   const   string  USBClassID  =   " A5DCBF10-6530-11D2-901F-00C04FB951ED " ;
        
public  IntPtr RegisterDeviceNotification(IntPtr hwnd)
        {
            Win32.DEV_BROADCAST_DEVICEINTERFACE deviceInterface 
=   new  Win32.DEV_BROADCAST_DEVICEINTERFACE();
            
int  size  =  Marshal.SizeOf(deviceInterface);
            deviceInterface.dbcc_size 
=  size;
        
//     deviceInterface.dbcc_devicetype = Win32.DBT_DEVTYP_VOLUME;
            deviceInterface.dbcc_reserved  =   0 ;
            
// deviceInterface.dbcc_handle = hwnd;
            
// deviceInterface.dbcc_hdevnotify = (IntPtr)0;
            deviceInterface.dbcc_classguid  =   new  Guid(USBClassID).ToByteArray();
            IntPtr buffer 
=  IntPtr.Zero;
            buffer 
=  Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(deviceInterface, buffer, 
true );
            IntPtr r 
=  IntPtr.Zero;
            r 
=  Win32.RegisterDeviceNotification(hwnd, buffer, 
                (Int32)(Win32.DEVICE_NOTIFY.DEVICE_NOTIFY_ALL_INTERFACE_CLASSES  
                        
|  Win32.DEVICE_NOTIFY.DEVICE_NOTIFY_SERVICE_HANDLE  |  
                        Win32.DEVICE_NOTIFY.DEVICE_NOTIFY_WINDOW_HANDLE)
                );
            
            
return  r;
        }
    }
}

 


 In the WPF application, we should register the DeviceNotification after the window is ready, so we should put them in the load event,

in the constructor:

 

代码
  UsbDetector usbDetector;
        
public  MainWindow()
        {
            InitializeComponent();
            usbDetector 
=   new  UsbDetector();
            usbDetector.StateChanged 
+=   new  Lenovo.Common.Devices.UsbStateChangedEventHandler(usbDetector_StateChanged);

            
this .Loaded  +=   new  RoutedEventHandler(MainWindow_Loaded);
           
        }
  
void  MainWindow_Loaded( object  sender, RoutedEventArgs e)
        {
            WindowInteropHelper interop 
=   new  WindowInteropHelper( this );
            HwndSource hwndSource 
=  HwndSource.FromHwnd(interop.Handle);
            HwndSourceHook hool 
=   new  HwndSourceHook(usbDetector.HwndHandler);
            hwndSource.AddHook(hool); ;
            usbDetector.RegisterDeviceNotification(interop.Handle);
        }

 
void  usbDetector_StateChanged( bool  arrival)
        {
            
if  (arrival)
                MessageBox.Show(
" add " );
            
else
                MessageBox.Show(
" removed " );
        }

 

In generally, the wParam should be DBT_DEVICEARRIVAL or DBT_DEVICEREMOVECOMPLETE, but some time , it keep be the wParam =7 (DBT_DEVNODES_CHANGED) and LParam = 0, that is that the usb driver isn't correctly installed.

 

你可能感兴趣的:(C# USB Detection - winform and WPF)