Detect USB device Insertion/Removal (drive letter)

hi experts exchange;

I found the following code snippet on ee, and it successfully allows me to detect a USB device (storage device in particular):-

      public enum DeviceEvent : int
      {
            Arrival = 0x8000,                  //DBT_DEVICEARRIVAL
            QueryRemove = 0x8001,                   //DBT_DEVICEQUERYREMOVE
            QueryRemoveFailed = 0x8002,      //DBT_DEVICEQUERYREMOVEFAILED
            RemovePending = 0x8003,                   //DBT_DEVICEREMOVEPENDING
            RemoveComplete = 0x8004,             //DBT_DEVICEREMOVECOMPLETE
            Specific = 0x8005,                         //DBT_DEVICEREMOVECOMPLETE
            Custom = 0x8006                               //DBT_CUSTOMEVENT
      }

      protected override void WndProc(ref Message m)
      {
            base.WndProc(ref m);
            const int WM_DEVICECHANGE = 0x0219;
            DeviceEvent lEvent;

            if(m.Msg == WM_DEVICECHANGE)
            {
                  lEvent = (DeviceEvent) m.WParam.ToInt32();
                        
                  if (lEvent == DeviceEvent.Arrival)
                        MessageBox.Show("USB DEVICE DETECTED");
                  else if (lEvent == DeviceEvent.RemoveComplete)
                        MessageBox.Show("USB DEVICE REMOVED");
            }
      }


My question:-
As far as I understand it, the above code detects any device which is detected, is there a way I can only detect USB devices, I need to know the drive letter of the inserted usb device.

Thanks
Programmer_to_beAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

enwhyseeCommented:
This post describes how to do it ...

http://groups.google.com/group/microsoft.public.windowsxp.device_driver.dev/msg/d417a756065e7156?hl=en&lr=lang_en&ie=UTF-8&oe=UTF-8

See the Example code section on this site for actual example code on how to do it in C#:
http://lvr.com/hidpage.htm#MyExampleCode
0
grayeCommented:
...and yet another example here (in VB.Net, but hey... the concepts are the same)

http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/VB_DOT_NET/Q_21599899.html
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Programmer_to_beAuthor Commented:
Hi graye.

I tried your example by directly copying it in a VB.NET application, and it worked great, when I converted it to C#.NET, it fires the event when the USB device is removed, but I can't seem to get the event fired when the USB device is attached, do you notice anything that I'm doing wrong (below):

using System.Management;

private ManagementEventWatcher m_MediaConnectWatcher;

            private void button1_Click(object sender, System.EventArgs e)
            {
                  string query = "SELECT * FROM __InstanceOperationEvent WITHIN 10 WHERE TargetInstance ISA \"Win32_DiskDrive\"";
                  this.m_MediaConnectWatcher = new ManagementEventWatcher(query);
                  this.m_MediaConnectWatcher.EventArrived += new EventArrivedEventHandler(m_MediaConnectWatcher_EventArrived);
                  this.m_MediaConnectWatcher.Start();
            }

            private void m_MediaConnectWatcher_EventArrived(object sender, EventArrivedEventArgs e)
            {
                  ManagementBaseObject mbo, obj;

                  mbo = (ManagementBaseObject) e.NewEvent;
                  obj = (ManagementBaseObject) mbo["TargetInstance"];

                  switch (mbo.ClassPath.ClassName)
                  {
                        case "__InstanceCreationEvent":
                              
                              if (obj["InterfaceType"].ToString() == "USB")
                              {
                                    this.listBox1.Items.Add(obj["Caption"].ToString() + " (Drive letter " + this.GetDriveLetterFromDisk(obj["Name"].ToString()) + ") has been plugged in");
                              }
                              break;

                        case "__InstanceDeletionEvent":

                              if (obj["InterfaceType"].ToString() == "USB")
                              {
                                    this.listBox1.Items.Add(obj["Caption"].ToString() + " has been unplugged");
                              }
                              break;
                  }
            }

            private string GetDriveLetterFromDisk(string name)
            {
                  ObjectQuery oq_part, oq_disk;
                  ManagementObjectSearcher mos_part, mos_disk;
                  string ans = string.Empty;

                  name = name.Replace(@"\", "\\");

                  oq_part = new ObjectQuery("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=\"" + name + "\"} WHERE AssocClass = Win32_DiskDriveToDiskPartition");
                  mos_part = new ManagementObjectSearcher(oq_part);

                  foreach (ManagementObject obj_part in mos_part.Get())
                  {
                        oq_disk = new ObjectQuery("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=\"" + obj_part["DeviceID"] + "\"} WHERE AssocClass = Win32_LogicalDiskToPartition");
                        mos_disk = new ManagementObjectSearcher(oq_disk);

                        foreach (ManagementObject obj_disk in mos_disk.Get())
                        {
                              ans += obj_disk["Name"] + ",";
                        }
                  }

                  return ans.Trim('c');
            }

            private void button2_Click(object sender, System.EventArgs e)
            {
                  this.m_MediaConnectWatcher.Stop();
            }
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

Programmer_to_beAuthor Commented:
hi;

I figured it out, it was the the line

name = name.Replace(@"\", "\\");   -- should have been --  name = name.Replace("\\", "\\\\");

Thanks graye, one last thing, I changed the following query string:-

string query = "SELECT * FROM __InstanceOperationEvent WITHIN 10 WHERE TargetInstance ISA \"Win32_DiskDrive\"";

to

 "..WITHIN 2.."

and it seems to detect the usb device faster, was there any reason for you to initially have WITHIN 10? is it ok to lower that ? because it still seems to work ok but faster!

thanks again.
0
grayeCommented:
I see some minor "translation errors"...

               name = name.Replace(@"\", @"\\");
                                                          ^
               return ans.Trim(',');
                                       ^
After those two minor changes, it works for me...
0
grayeCommented:
No particular reason... I was just trying to reduce the "poll time", so that the program wouldn't use as many resources.
0
Programmer_to_beAuthor Commented:
Thanks graye, it works a treat :-)
0
Programmer_to_beAuthor Commented:
Hi graye; I'm sorry to post in a closed question but I couldnt think of any other way to get your attention on a problem that I'm having with the code you provided. I'll open another question to give you further points relating to this question.

When the EventArrived event fires and indicates that a USB device has been attached, I am trying to open another form, the form opens but does not respond at all, it simply changes to the colour white and when I hover the mouse over the opened form, the loading curser appears. To try and convey what I'm trying to do, see below:-

          private void m_MediaConnectWatcher_EventArrived(object sender, EventArrivedEventArgs e)
          {
               ManagementBaseObject mbo, obj;

               mbo = (ManagementBaseObject) e.NewEvent;
               obj = (ManagementBaseObject) mbo["TargetInstance"];

               switch (mbo.ClassPath.ClassName)
               {
                    case "__InstanceCreationEvent":
                         
                         if (obj["InterfaceType"].ToString() == "USB")
                         {
                             Form f2 = new Form();
                             f2.Show(); //Form 2 opens, but does not respond
                         }
                         break;

                    case "__InstanceDeletionEvent":

                         System.Windows.Forms.MessageBox.Show("Device removed");
                         break;
               }
          }



If your able to recreate this problem, would you know why this is happening?
Many thanks.
0
grayeCommented:
Let's start with the basics.... normally you'd create an new instance of a form class by it's full name (but I'm assuming that that's just a typo)

       Form2 f2 = new Form2();

Secondly, this is really a multi-threaded application (even though you didn't really do anything that specifically asked for it to be).  That's just the way that WMI was designed to operate.  So, what's happening, is that the form is shown properly, but control is passed back to the calling routine and the new form never gets focus.  Rather than bore you with all of the reasons why, let's just try this simple fix instead.  

       f2.ShowDialog();
0
Programmer_to_beAuthor Commented:
graye I can't thank you enough for the help you've provided.

Its working great now. What I originally was trying to do was that when a USB device was detected I was raising an event, the main form of my application subscribed to the event and when the event got fired the event handling method would add a new TabPage to a TabControl. The TabPage was added OK, but its background was white and I was unable to remove it at runtime too (I don't know whether this was because of the multi-threading issue you told me about or not because it does have similarities in behaviour to the form problem), if it was, is there any non-simple way to have my first solution (using a TabPage) work? I eventually ended up just showing a new form (which works now) because I couldnt get the TabPage solution to work.

I'll create a new post in the C# TA, if you could post any message there I'll assign the points to you for the additional help you have provided. Thanks.
0
Programmer_to_beAuthor Commented:
Hi graye; a thing which seems to be causing a problem using the ShowDialog method to open the form is that I am unable to close the form when the removal event arrives, my code below may explain this better:

          private Form2 f2;
         
           private void m_MediaConnectWatcher_EventArrived(object sender, EventArrivedEventArgs e)
           {
               ManagementBaseObject mbo, obj;

               mbo = (ManagementBaseObject) e.NewEvent;
               obj = (ManagementBaseObject) mbo["TargetInstance"];

               switch (mbo.ClassPath.ClassName)
               {
                    case "__InstanceCreationEvent":
                         
                         if (obj["InterfaceType"].ToString() == "USB")
                         {
                             f2 = new Form2();
                             f2.ShowDialog();                          
                         }
                         break;

                    case "__InstanceDeletionEvent":

                         if (obj["InterfaceType"].ToString() == "USB")
                         {
                              System.Windows.Forms.MessageBox.Show("Device removed");
                              f2.Close();
                         }
                         break;
               }
          }
 
When Form2 is opened using ShowDialog and I take the USB device out, the deletion event never fires until i manually close Form2, once Form2 is closed the event then fires (giving the message box) and f2.Close(); is then executed... (too late as the form is closed already).

Any ideas?
0
grayeCommented:
I know that nobody likes reading the manual (that's why web sites like this are so popular), but....

Let's start off with some background information on the subject of threading:
http://msdn2.microsoft.com/en-us/library/ms173178.aspx

Then a "how to" article on threading:
http://support.microsoft.com/default.aspx?scid=kb;en-us;815804
0
Programmer_to_beAuthor Commented:
Hi graye; I understand threading to a good level, my understanding of this problem is that the form gets shown on a different thread (created by WMI), and when that event method finishes execution, the thread which the form was created on gets killed too... what I'm having difficulty in implementing is that I don't know how to execute that form creation code (creating a form object and calling .Show) on the current application thread. Can you point me in the right direction on where I need to look?

Thanks.
0
Programmer_to_beAuthor Commented:
Hi again graye, did a bit of reading (should do this more often) and came across the Control.Invoke method, used that and its working fine.

Thanks for the additional help!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.