Solved

Detecting USB Mass Storage Insertion from C#

Posted on 2007-11-28
10
4,798 Views
Last Modified: 2013-11-07
I need to detect the insertion and removal of USB Mass Storage Devices from C#. I have found some code (http://www.codeproject.com/dotnet/devicevolumemonitor.asp) which solves most of my problem however it also triggers when a user maps a network drive. Can someone suggest modifications or an alternative method.
/// <summary>
        /// WndProc method that traps all messages sent to the Handle
        /// </summary>
        /// <param name="aMessage">A Windows message</param>
        protected override void WndProc(ref Message aMessage)
        {
            BroadcastHeader lBroadcastHeader;
            Volume          lVolume;
            DeviceEvent     lEvent;
 
            base.WndProc(ref aMessage);
            if(aMessage.Msg==WM_DEVICECHANGE && fMonitor.Enabled)
            {
                lEvent = (DeviceEvent)aMessage.WParam.ToInt32();
                if (lEvent==DeviceEvent.Arrival || lEvent==DeviceEvent.RemoveComplete)
                {
                    lBroadcastHeader = (BroadcastHeader)Marshal.PtrToStructure(aMessage.LParam,typeof(BroadcastHeader));
                    if(lBroadcastHeader.Type==DeviceType.Volume)
                    {
                        lVolume = (Volume)Marshal.PtrToStructure(aMessage.LParam,typeof(Volume));
                        if((lVolume.Flags & (int)VolumeFlags.Media) == 0)
                        { 
                            fMonitor.TriggerEvents(lEvent==DeviceEvent.Arrival,lVolume.Mask);
                        }
                    }
                }
            }
        }

Open in new window

0
Comment
Question by:S31B1
  • 6
  • 3
10 Comments
 
LVL 7

Expert Comment

by:prosh0t
ID: 20367268
it looks like somebody else had the same problem, maybe this can help:

http://www.thescripts.com/forum/thread264280.html

also look at:
http://www.codeproject.com/dotnet/devicevolumemonitor.asp?df=100&forumid=15152&exp=0&fr=26

see the flags DBTF_MEDIA and DBTF_NET
0
 
LVL 96

Accepted Solution

by:
Bob Learned earned 500 total points
ID: 20367723
Both the Volume and BroadcastHeader structures have a DeviceType.

Bob
0
 
LVL 4

Author Comment

by:S31B1
ID: 20368251
@The Learned One
On my system The Device Type returned for Network shares and Mass Storage devices are both Volume (0x00000002).

@prosh0t
So I'm looking at the VolumeFlags now, it seems that, in my limited testing:-

NET Share: Volume.Flags = 2
USB: Volume.Flags = 0
CDROM: Volume.Flags = 2002452481

Could you expalin any more about the Flags?

If I just test for Volume.Flags == 0 will this detect only the USB in all cases?
0
Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

 
LVL 4

Author Comment

by:S31B1
ID: 20368263
as I understand it the Code above is calling into non-managed code, is there something in the framework I should be using in preference?

What is the "ManagementEventWatcher" all about?
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 20368623
If you want to go the WMI route, here is a class that will function as a USB device watcher.

Bob
// Add a reference to System.Management.dll to the project.
 
using System;
using System.Management;
 
public class Win32_UsbDriveWatcher
{
  private ManagementEventWatcher m_watcher;
 
  public delegate void DeviceInsertedEventHandler(object sender, Win32_UsbDriveInsertEventArgs e);
 
  public event DeviceInsertedEventHandler DeviceInserted;
  public event EventHandler DeviceRemoved;
 
  public void Start(int pollingInterval)
  {
    string queryString =
      "SELECT * " +
      " FROM __InstanceOperationEvent" +
      " WITHIN " + pollingInterval +
      " WHERE TargetInstance ISA 'Win32_DiskDrive'";
 
    EventQuery processQuery = new EventQuery(queryString);
 
    m_watcher = new ManagementEventWatcher(processQuery);
    m_watcher.EventArrived += new System.Management.EventArrivedEventHandler(EventArrived);
    m_watcher.Start();
  }
 
  private void EventArrived(object sender, System.Management.EventArrivedEventArgs e)
  {
    PropertyData instance = ((PropertyData)(e.NewEvent.Properties["TargetInstance"]));
    ManagementBaseObject obj = (ManagementBaseObject)instance.Value;
    Win32_UsbDriveInsertEventArgs args = new Win32_UsbDriveInsertEventArgs();
    if ((string)obj["InterfaceType"] == "USB")
    {
      args.IsCreated = (obj.ClassPath.ClassName == "__InstanceCreationEvent");
      args.DriveName = this.GetDriveLetterFromDisk((string)obj["Name"]);
      if (args.IsCreated)
      {
        if (DeviceInserted != null)
        {
          DeviceInserted(this, args);
        }
      }
      else
      {
        if (DeviceRemoved != null)
        {
          DeviceRemoved(this, EventArgs.Empty);
        }
      }
    }
  }
 
  private string GetDriveLetterFromDisk(string name)
  {
    name = name.Replace("\\", "\\\\");
 
    string query = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + name + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition";
    ObjectQuery queryDrive = new ObjectQuery(query);
    ManagementObjectSearcher searcherDrive = new ManagementObjectSearcher(queryDrive);
    foreach (ManagementObject drive in searcherDrive.Get())
    {
      query = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" +
        drive["DeviceID"] +
        "'} WHERE AssocClass = Win32_LogicalDiskToPartition";
      ObjectQuery queryPartition = new ObjectQuery(query);
      ManagementObjectSearcher searcherPartition = new ManagementObjectSearcher(queryPartition);
      foreach (ManagementObject disk in searcherPartition.Get())
      {
        return (string)disk["Name"];
      }
    }
    return string.Empty;
  }
 
}
 
public class Win32_UsbDriveInsertEventArgs : EventArgs
{
  public bool IsCreated;
  public string DriveName;
}

Open in new window

0
 
LVL 96

Assisted Solution

by:Bob Learned
Bob Learned earned 500 total points
ID: 20368649
Example:

Win32_UsbDriveWatcher watcher = new Win32_UsbDriveWatcher();
watcher.DeviceInserted += OnUsbDeviceInserted;
watcher.DeviceRemoved += OnUsbDeviceRemoved;
watcher.Start(5);

...

private void OnUsbDeviceInserted(object sender, Win32_UsbDriveInsertEventArgs e)
{
}

private void OnUsbDeviceRemoved(object sender, EventArgs e)
{
}

Bob
0
 
LVL 4

Author Comment

by:S31B1
ID: 20372285
Thanks, for the code I'm having a look at it now. A couple of issues. When I close the test program I have written I get an InvalidComObjectException. "Com object has been seperated from its underlying RCW cannot be used"

And it never seems to trigger!

It gets into the GetDriveLetterFromDisk function, attempts to itterate over the searcherDrive.Get() fails and drops right out, I don't get any errors either.

not sure if the two problems are related?
0
 
LVL 4

Author Comment

by:S31B1
ID: 20372289
Another thing, all things equal, If I get this new code working which is the preferred way of trapping this event in my c# winform?
0
 
LVL 4

Author Comment

by:S31B1
ID: 20372367
So, I've commented out the call to this.GetDriveLetterFromDisk and I now get my event raised. however it is always a Device Removed Event regardless of action.
0
 
LVL 4

Author Comment

by:S31B1
ID: 20372404
Sorry!

Next Question.

I notice there is a poling interval (as a parameter of the constructor) and in the query is this a value in seconds? Does this mean I could be waiting up to 5 seconds before i get a notification?

If so what is the smallest window of time I can sample and what would be the effect on system performance?
0

Featured Post

Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question