65

I want to build a program that detects if a usb (or two or more) are plugged in (and copy all contents to any folder on a hard disk)

Any ideas? I have this,

using System.Runtime.InteropServices;

But it is not the easy way (that I believe). I want something easy.

I have another idea (if (folder exist) then copy) something -- but there may be a problem with that, and I want a good solution.

There may also be a tool called SerialPort; can I use it? If so, how do I use it?

Jon
  • 7,848
  • 1
  • 40
  • 41
angel
  • 4,474
  • 12
  • 57
  • 89
  • 3
    Break it down into individual pieces. The code that detects the USB drive is one piece, the code that copies data from is another. Do the pieces you can at the moment. – Lasse V. Karlsen May 14 '11 at 18:08
  • yeah! i can "copy" file now.. with a batch file the program can "create" it file if not exist – angel May 14 '11 at 18:10
  • Related: http://stackoverflow.com/questions/620144/detecting-usb-drive-insertion-and-removal-using-windows-service-and-c-sharp – DuckMaestro Jul 01 '16 at 18:33
  • I made a NuGet packet that works on Windows, MacOS and Linux: https://github.com/Jinjinov/Usb.Events – Jinjinov Apr 28 '20 at 06:32

3 Answers3

72

It is easy to check for removable devices. However, there's no guarantee that it is a USB device:

var drives = DriveInfo.GetDrives()
    .Where(drive => drive.IsReady && drive.DriveType == DriveType.Removable);

This will return a list of all removable devices that are currently accessible. More information:

InteXX
  • 6,135
  • 6
  • 43
  • 80
Elian Ebbing
  • 18,779
  • 5
  • 48
  • 56
  • 1
    where do you declare "drive"?? – angel May 14 '11 at 18:21
  • 5
    @angel: You don't have to separately declare `drive`: `drive` is the input parameter for the lamba expression that I use as input for the `.Where()` extension method. It's part of the Linq features that were intruduced with the .NET framework 3.5. More info on Linq: http://msdn.microsoft.com/en-us/vbasic/aa904594. – Elian Ebbing May 14 '11 at 18:25
  • Won't that also give you CD-ROM drives, memory card drives, and sometimes even hard drives (in my PC, my SATA drive shows up as removable even though it is the C drive)? Also, would you have to loop through this detection continually in order to detect when a drive is plugged in or is there some sort of trigger? – IAmTimCorey May 14 '11 at 22:26
  • @BiggsTRC: If you look at the `DriveType` enumeration, then you would see that there is a different value for CD-ROM drives. I don't think you can distinguish between memorycard drives and USB sticks, because memorycard drives are often connected to the motherboard via an internal USB connection anyway. – Elian Ebbing May 15 '11 at 00:40
  • @ElianEbbing I have pasted the code in my static void Main method butthe `DriveInfo` is underlined with `does not exist in current context` error, what is wrong? – Arthur Mamou-Mani Aug 14 '12 at 13:02
  • 1
    @arthurmani - The class `DriveInfo` is defined in the namespace `System.IO`, so you have to include that namespace to make it work. – Elian Ebbing Aug 15 '12 at 22:03
  • what is the type of drives? how to list the names of drives? – Ali.Rashidi Jul 08 '16 at 17:59
  • result is = "Enumeration yielded no results" – Ali.Rashidi Jul 08 '16 at 18:01
14

Here is a code that works for me, which is a part from the website above combined with my early trials: http://www.codeproject.com/KB/system/DriveDetector.aspx

This basically makes your form listen to windows messages, filters for usb drives and (cd-dvds), grabs the lparam structure of the message and extracts the drive letter.

protected override void WndProc(ref Message m)
    {

        if (m.Msg == WM_DEVICECHANGE)
        {
            DEV_BROADCAST_VOLUME vol = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
            if ((m.WParam.ToInt32() == DBT_DEVICEARRIVAL) &&  (vol.dbcv_devicetype == DBT_DEVTYPVOLUME) )
            {
                MessageBox.Show(DriveMaskToLetter(vol.dbcv_unitmask).ToString());
            }
            if ((m.WParam.ToInt32() == DBT_DEVICEREMOVALCOMPLETE) && (vol.dbcv_devicetype == DBT_DEVTYPVOLUME))
            {
                MessageBox.Show("usb out");
            }
        }
        base.WndProc(ref m);
    }

    [StructLayout(LayoutKind.Sequential)] //Same layout in mem
    public struct DEV_BROADCAST_VOLUME
    {
        public int dbcv_size;
        public int dbcv_devicetype;
        public int dbcv_reserved;
        public int dbcv_unitmask;
    }

    private static char DriveMaskToLetter(int mask)
    {
        char letter;
        string drives = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //1 = A, 2 = B, 3 = C
        int cnt = 0;
        int pom = mask / 2;
        while (pom != 0)    // while there is any bit set in the mask shift it right        
        {        
            pom = pom / 2;
            cnt++;
        }
        if (cnt < drives.Length)
            letter = drives[cnt];
        else
            letter = '?';
        return letter;
    }

Do not forget to add this:

using System.Runtime.InteropServices;

and the following constants:

    const int WM_DEVICECHANGE = 0x0219; //see msdn site
    const int DBT_DEVICEARRIVAL = 0x8000;
    const int DBT_DEVICEREMOVALCOMPLETE = 0x8004;
    const int DBT_DEVTYPVOLUME = 0x00000002;  
John Conde
  • 217,595
  • 99
  • 455
  • 496
Onsightfree
  • 307
  • 3
  • 11
2

Microsoft API Code Pack. ShellObjectWatcher class.

Mark
  • 436
  • 4
  • 18