Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Detecting USB Mass Storage Insertion from C#

Posted on 2007-11-28
10
4,812 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
Resolve Critical IT Incidents Fast

If your data, services or processes become compromised, your organization can suffer damage in just minutes and how fast you communicate during a major IT incident is everything. Learn how to immediately identify incidents & best practices to resolve them quickly and effectively.

 
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

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
RegEx with optional part 4 42
Upgrading my SSIS package in VS 2012 6 59
how to double quote a string for an inline sql statement. 8 73
Where is this file? 3 25
We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
This article aims to explain the working of CircularLogArchiver. This tool was designed to solve the buildup of log file in cases where systems do not support circular logging or where circular logging is not enabled
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

856 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