none
Detecting USB device insertion and removal

    Question

  • Does anyone know how to extract a usb device's "Friendly Name"?

    What I want to do is: I have a usb device, when I plug the device into my computer, I want my program to detect that a new usb device has been inserted and grab the device's "Friendly Name." If the friendly name matches the name of the device, which I have hard coded, call my procedure. Essentially, I do not want to have my procedure called when ANY usb device is inserted, I ONLY want it called when my specific usb device is insterted.

    I pretty much have most of the code done. I am able to detect USB device arivals and removal, by overiding the WndProc procedure but I am stuck on retrieving the freindly name of the device that has been inserted.

    Here is the code I have so far

    using System.Runtime.InteropServices;

    private const int 
    WM_DEVICECHANGE = 0x0219;                 // device change event 
    private const int DBT_DEVICEARRIVAL = 0x8000;               // system detected a new device 
    private const int DBT_DEVICEREMOVEPENDING = 0x8003;         // about to remove, still available 
    private const int DBT_DEVICEREMOVECOMPLETE = 0x8004;        // device is gone 
     
    private const int DBT_DEVTYP_PORT = 0x00000003;      // serial, parallel 
     
    protected override void WndProc(ref Message m) 
        int devType; 
        base.WndProc(ref m); 
     
            switch (m.WParam.ToInt32()) 
        { 
            case DBT_DEVICEARRIVAL: 
     
                devType = Marshal.ReadInt32(m.LParam, 4); 
                      
                if (devType == DBT_DEVTYP_PORT) 
                { 
                // usb device inserted,  
                // get the friendly name of the new device 
                // if the friendly name matches my device name,  
                // call my procedure for new device 
                } 
     
                break; 
     
               case DBT_DEVICEREMOVECOMPLETE: 
     
               devType = Marshal.ReadInt32(m.LParam, 4); 
               if (devType == DBT_DEVTYP_PORT) 
               { 
                // usb device removed,  
                // get the friendly name of the device removed 
                // if the friendly name matches my device name, 
                // call my procedure for removed device 
               } 
               break; 
        } 

    Can anyone offer any suggestions?


    Friday, January 23, 2009 11:31 PM

Answers

  • I have very little experience overriding WndProc. OK, I've never done it...

    What I would try is to define "OnDeviceArrival" and "OnDeviceRemoval" functions, and BeginInvoke them from WndProc. This will allow WndProc to return quickly after queueing the callback functions.

           -Steve

    Tuesday, January 27, 2009 9:33 PM
  • I set this aside for a bit to work on other things. I finally got back to it and what Stephen Cleary suggested is the solution. Here's the code:

    using System.Management;     
    using System.Management.Instrumentation;     
    using System.Runtime.InteropServices;     
         
    private const int WM_DEVICECHANGE = 0x0219;                 // device change event      
    private const int DBT_DEVICEARRIVAL = 0x8000;               // system detected a new device      
    private const int DBT_DEVICEREMOVEPENDING = 0x8003;         // about to remove, still available      
    private const int DBT_DEVICEREMOVECOMPLETE = 0x8004;        // device is gone      
          
    private const int DBT_DEVTYP_PORT = 0x00000003;      // serial, parallel    
     
    //delegate enables asynchronous call for getting the list of friendly names  
    private getFriendlyNameListDelegate mDeleg;    
          
    protected override void WndProc(ref Message m)      
    {      
        int devType;      
        base.WndProc(ref m);      
          
            switch (m.WParam.ToInt32())      
        {      
            case DBT_DEVICEARRIVAL:      
          
                devType = Marshal.ReadInt32(m.LParam, 4);      
                           
                if (devType == DBT_DEVTYP_PORT)      
                {      
                // usb device inserted, call the query      
                mDeleg = new getFriendlyNameListDelegate(getFriendlyNameList);  
                AsyncCallback callback = new AsyncCallback(getFriendlyNameListCallback);  
     
                  
                // invoke the thread that will handle getting the friendly names  
                mDeleg.BeginInvoke(callback, new object());              
        
                }      
          
                break;      
          
               case DBT_DEVICEREMOVECOMPLETE:      
          
               devType = Marshal.ReadInt32(m.LParam, 4);      
               if (devType == DBT_DEVTYP_PORT)      
               {      
                // usb device removed, call the query  
                  
                mDeleg = new getFriendlyNameListDelegate(getFriendlyNameList);  
                AsyncCallback callback = new AsyncCallback(getFriendlyNameListCallback);  
     
                 
               // invoke the thread that will handle getting the friendly names   
               mDeleg.BeginInvoke(callback, new object());     
               }      
               break;      
        }      
    }     
     
     
    // function queries the system using WMI and gets an arraylist of all com port devices     
    private ArrayList getFriendlyNameList()     
    {     
        ArrayList deviceList = new ArrayList();     
         
                // getting a list of all available com port devices and their friendly names     
                // must add System.Management DLL resource to solution before using this     
                // Project -> Add Reference -> .Net tab, choose System.Management     
         
                // source:     
                // http://www.codeproject.com/KB/system/hardware_properties_c_.aspx     
         
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select Name from Win32_PnpEntity");     
         
                foreach (ManagementObject devices in searcher.Get())     
                {     
                    string name = devices.GetPropertyValue("Name").ToString();     
                 
                    // only add item if the friendly names contains "COM"     
                    // we only want to add COM Ports     
                    if (name.Contains("(COM"))     
                        {     
                                deviceList.Add(name);     
                        }     
                }     
               
            searcher.Dispose();     
            return deviceList;    
    }  
     
    // delegate wrapper function for the getFriendlyNameList function  
    private delegate ArrayList getFriendlyNameListDelegate();  
     
    // callback method when the thread returns  
    private void getFriendlyNameListCallback(IAsyncResult ar)  
    {  
        // got the returned arrayList, now we can do whatever with it  
        ArrayList result = mDeleg.EndInvoke(ar);  

    As Steve suggested, I had to create a delegate to handle the rereshing of the Friendly Name list. Whenever an OnDeviceArrival or OnDeviceRemoval message is trapped, check if the device is a port. If it is, then call the delegated function to invoke a thread to handle getting the updated list if port device friendly names.

    The following site helped me out alot on how to use delegates and callback functions.

    http://progtutorials.tripod.com/C_Sharp.htm#_Toc65227886
    • Marked as answer by wlo413 Wednesday, February 04, 2009 6:34 PM
    Wednesday, February 04, 2009 6:34 PM

All replies

  • hi wlo413 , i was searching how to deal with USB in C# so can you tell me what is your reference in this or you could explain to me how to detect it and deal with it , "Couldn't understand so much of the code above" -- "BEGINNER :D".

     

    Thanks.


    To Be The Best
    Saturday, January 24, 2009 3:42 AM
  • Well, the easiest way would probably be to use WMI, if you know the type of device you're looking for. It is probably possible to do the same with SetupAPI.

    If WMI doesn't work and you don't want to mess with the P/Invoke necessary for SetupAPI, you can check out the FriendlyName values under subkeys of HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum. I don't recommend this practice, but it's the way the famous deveject program works.

            -Steve

    Saturday, January 24, 2009 4:25 AM
  • Salaam Aliakmon

    here a sample code on code project you can use it

    the programmer here detected the usb and get its drive name, and by knowing the drive name ( C:, D: or ... H: ) then you can easily know the caption of this drive.

    Code Project sample code


    Best Regards
    Saturday, January 24, 2009 8:16 AM
  • Hello Monah

    I have taken a look at the code found on code project already. Unfortunately, my application is slightly different. The USB device I'm querying is not a mass storage device, its actually a port device. So when I plug it in, Windows assigns a virtual com port number for the usb device.

    For example, when the usb device is plugged in, and I take a look at the Windows Device Manager. Under Ports(COM & LPT1), I will see the name of the usb device and the com port it is on. It is this name, I believe is called a Friendly Name, that I want my code to get.

    As Stephen Cleary posted earlier, I might have to try using the WMI, although I haven't worked with it before and not quite sure how to go about doing it.

    Monday, January 26, 2009 5:04 PM
  • I have simple source code that uses ManagementObject and friends to query WMI at http://code.msdn.microsoft.com/NitoWMI.

    On my system, the Win32_SerialPort class has Description (a friendly name), DeviceID (the actual com port name which can be passed to CreateFile), and PNPDeviceID (the unique PNP ID) all with useful values.

    However, I just read MSDN on DBT_DEVICEARRIVAL, and it should be giving you the friendly name already. You just have to pull it out of the structure that's passed to WndProc.

           -Steve

    Monday, January 26, 2009 5:30 PM
  • Hello Steve

    I'm just reading the MSDN documentation for DBT_DEVICEARRIVAL, you're right about the structure being passed into WndProc. However, I can't seem to find any further documentation on what the struct contains for fields.

    MSND lists this:

    LRESULT CALLBACK WindowProc(
      HWND hwnd,       // handle to window
      UINT uMsg,       // WM_DEVICECHANGE
      WPARAM wParam,   // device-change event
      LPARAM lParam    // event-specific data
    );

    I am assuming I use the LPARAM, which looks like an IntPtr to a another struct, but I can't seem to find anything on what this struct's fields are. Even if the Friendly Name is stored in this struct, I'm uncertain how to extract it at the moment.

    Gonna keep looking though.

    Monday, January 26, 2009 6:13 PM
  • It looks like I was able to get a list of all the connected port devices, including their friendly names, through WMI.

    I made a separate function that queries the system's connected Com Port devices, then place the results in an arraylist. In my WndProc, whenever a a DBT_DEVICEARRIVAL or DBT_DEVICEREMOVEDCOMPLETE messages are caught, I will call this function that returns an arrayList of conncected Com Port devices.

    The problem I am getting now is a unhandled ManagementException, The Application called an interface that was marshalled for a different thread. This occurs when the query is made within the WndProc.

    Here's my code so far:

    using System.Management;   
    using System.Management.Instrumentation;   
    using System.Runtime.InteropServices;   
       
    private const int WM_DEVICECHANGE = 0x0219;                 // device change event    
    private const int DBT_DEVICEARRIVAL = 0x8000;               // system detected a new device    
    private const int DBT_DEVICEREMOVEPENDING = 0x8003;         // about to remove, still available    
    private const int DBT_DEVICEREMOVECOMPLETE = 0x8004;        // device is gone    
        
    private const int DBT_DEVTYP_PORT = 0x00000003;      // serial, parallel    
        
    protected override void WndProc(ref Message m)    
    {    
        int devType;    
        base.WndProc(ref m);    
        
            switch (m.WParam.ToInt32())    
        {    
            case DBT_DEVICEARRIVAL:    
        
                devType = Marshal.ReadInt32(m.LParam, 4);    
                         
                if (devType == DBT_DEVTYP_PORT)    
                {    
                // usb device inserted, call the query    
                ArrayList myList = getFriendlyNameList();   
                }    
        
                break;    
        
               case DBT_DEVICEREMOVECOMPLETE:    
        
               devType = Marshal.ReadInt32(m.LParam, 4);    
               if (devType == DBT_DEVTYP_PORT)    
               {    
                // usb device removed, call the query
            ArrayList myList = getFriendlyNameList();   
               }    
               break;    
        }    
    }   
       
    private ArrayList getFriendlyNameList()   
    {   
        ArrayList deviceList = new ArrayList();   
       
                // getting a list of all available com port devices and their friendly names   
                // must add System.Management DLL resource to solution before using this   
                // Project -> Add Reference -> .Net tab, choose System.Management   
       
                // source:   
                // http://www.codeproject.com/KB/system/hardware_properties_c_.aspx   
       
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select Name from Win32_PnpEntity");   
       
                foreach (ManagementObject devices in searcher.Get())   
                {   
                    string name = devices.GetPropertyValue("Name").ToString();   
               
                    // only add item if the friendly names contains "COM"   
                    // we only want to add COM Ports   
                    if (name.Contains("(COM"))   
                        {   
                                deviceList.Add(name);   
                        }   
                }   
             
            searcher.Dispose();   
            return deviceList;  
    My getFriendlyName function works when I link it to an a button eventHandler, it only throws the ManagementException when it is called from within WndProc. MSDN also provides very little information on this type of exception.
    Tuesday, January 27, 2009 4:27 PM
  • I have very little experience overriding WndProc. OK, I've never done it...

    What I would try is to define "OnDeviceArrival" and "OnDeviceRemoval" functions, and BeginInvoke them from WndProc. This will allow WndProc to return quickly after queueing the callback functions.

           -Steve

    Tuesday, January 27, 2009 9:33 PM
  • I set this aside for a bit to work on other things. I finally got back to it and what Stephen Cleary suggested is the solution. Here's the code:

    using System.Management;     
    using System.Management.Instrumentation;     
    using System.Runtime.InteropServices;     
         
    private const int WM_DEVICECHANGE = 0x0219;                 // device change event      
    private const int DBT_DEVICEARRIVAL = 0x8000;               // system detected a new device      
    private const int DBT_DEVICEREMOVEPENDING = 0x8003;         // about to remove, still available      
    private const int DBT_DEVICEREMOVECOMPLETE = 0x8004;        // device is gone      
          
    private const int DBT_DEVTYP_PORT = 0x00000003;      // serial, parallel    
     
    //delegate enables asynchronous call for getting the list of friendly names  
    private getFriendlyNameListDelegate mDeleg;    
          
    protected override void WndProc(ref Message m)      
    {      
        int devType;      
        base.WndProc(ref m);      
          
            switch (m.WParam.ToInt32())      
        {      
            case DBT_DEVICEARRIVAL:      
          
                devType = Marshal.ReadInt32(m.LParam, 4);      
                           
                if (devType == DBT_DEVTYP_PORT)      
                {      
                // usb device inserted, call the query      
                mDeleg = new getFriendlyNameListDelegate(getFriendlyNameList);  
                AsyncCallback callback = new AsyncCallback(getFriendlyNameListCallback);  
     
                  
                // invoke the thread that will handle getting the friendly names  
                mDeleg.BeginInvoke(callback, new object());              
        
                }      
          
                break;      
          
               case DBT_DEVICEREMOVECOMPLETE:      
          
               devType = Marshal.ReadInt32(m.LParam, 4);      
               if (devType == DBT_DEVTYP_PORT)      
               {      
                // usb device removed, call the query  
                  
                mDeleg = new getFriendlyNameListDelegate(getFriendlyNameList);  
                AsyncCallback callback = new AsyncCallback(getFriendlyNameListCallback);  
     
                 
               // invoke the thread that will handle getting the friendly names   
               mDeleg.BeginInvoke(callback, new object());     
               }      
               break;      
        }      
    }     
     
     
    // function queries the system using WMI and gets an arraylist of all com port devices     
    private ArrayList getFriendlyNameList()     
    {     
        ArrayList deviceList = new ArrayList();     
         
                // getting a list of all available com port devices and their friendly names     
                // must add System.Management DLL resource to solution before using this     
                // Project -> Add Reference -> .Net tab, choose System.Management     
         
                // source:     
                // http://www.codeproject.com/KB/system/hardware_properties_c_.aspx     
         
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select Name from Win32_PnpEntity");     
         
                foreach (ManagementObject devices in searcher.Get())     
                {     
                    string name = devices.GetPropertyValue("Name").ToString();     
                 
                    // only add item if the friendly names contains "COM"     
                    // we only want to add COM Ports     
                    if (name.Contains("(COM"))     
                        {     
                                deviceList.Add(name);     
                        }     
                }     
               
            searcher.Dispose();     
            return deviceList;    
    }  
     
    // delegate wrapper function for the getFriendlyNameList function  
    private delegate ArrayList getFriendlyNameListDelegate();  
     
    // callback method when the thread returns  
    private void getFriendlyNameListCallback(IAsyncResult ar)  
    {  
        // got the returned arrayList, now we can do whatever with it  
        ArrayList result = mDeleg.EndInvoke(ar);  

    As Steve suggested, I had to create a delegate to handle the rereshing of the Friendly Name list. Whenever an OnDeviceArrival or OnDeviceRemoval message is trapped, check if the device is a port. If it is, then call the delegated function to invoke a thread to handle getting the updated list if port device friendly names.

    The following site helped me out alot on how to use delegates and callback functions.

    http://progtutorials.tripod.com/C_Sharp.htm#_Toc65227886
    • Marked as answer by wlo413 Wednesday, February 04, 2009 6:34 PM
    Wednesday, February 04, 2009 6:34 PM