如何检测USB驱动器是否已插入?

65
我想构建一个程序,用于检测是否插入了一个(或多个)USB,并将所有内容复制到硬盘上的任何文件夹中。

有什么想法吗?我目前有这个:

using System.Runtime.InteropServices;

但这不是我认为的简单方法。我想要一个简单的东西。

我有另一个想法(如果文件夹存在则复制某些内容)——但是可能会遇到问题,我希望能找到一个好的解决方案。

也许还有一个名为SerialPort的工具;我可以使用它吗?如果可以,如何使用?


3
将其分解为各个单独的部分。检测USB驱动器的代码是一个部分,复制数据的代码是另一个部分。尽可能完成您目前可以完成的部分。 - Lasse V. Karlsen
耶!我现在可以“复制”文件了...使用批处理文件,程序可以在文件不存在时“创建”它。 - angel
相关:https://dev59.com/_nRB5IYBdhLWcg3wcm6d - DuckMaestro
我制作了一个 NuGet 包,可以在 Windows、MacOS 和 Linux 上运行:https://github.com/Jinjinov/Usb.Events - Jinjinov
3个回答

73

检查可移动设备很容易。然而,并不能保证它是USB设备:

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

这将返回当前可访问的所有可移动设备列表。更多信息:


1
你在哪里声明"drive"? - angel
5
@angel:你不需要单独声明“drive”变量:在我用作.Where()扩展方法输入的lambda表达式中,drive已经是输入参数之一了。这是.NET Framework 3.5引入的Linq功能的一部分。有关Linq的更多信息,请访问:http://msdn.microsoft.com/en-us/vbasic/aa904594。 - Elian Ebbing
这样做会不会也给你带来CD-ROM驱动器、存储卡驱动器,有时甚至是硬盘(在我的电脑上,我的SATA硬盘虽然是C盘,但也显示为可移动设备)?此外,你是否需要不断循环检测以便在插入驱动器时检测到它,或者有某种触发器可以使用? - IAmTimCorey
@BiggsTRC:如果您查看DriveType枚举,那么您会发现CD-ROM驱动器有不同的值。我认为您无法区分记忆卡驱动器和USB闪存驱动器,因为记忆卡驱动器通常通过内部USB连接连接到主板上。 - Elian Ebbing
1
@arthurmani - 类DriveInfo定义在命名空间System.IO中,因此您必须包含该命名空间才能使其正常工作。 - Elian Ebbing
显示剩余3条评论

14

这是一段对我有效的代码,它是来自上述网站的一部分,结合了我的早期尝试:

http://www.codeproject.com/KB/system/DriveDetector.aspx

基本上,这使得您的表单侦听Windows消息,过滤USB驱动器和(CD-DVD),获取消息的lparam结构并提取驱动器字母。

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;
    }
不要忘记添加这个:
using System.Runtime.InteropServices;

以及以下常量:

    const int WM_DEVICECHANGE = 0x0219; //see msdn site
    const int DBT_DEVICEARRIVAL = 0x8000;
    const int DBT_DEVICEREMOVALCOMPLETE = 0x8004;
    const int DBT_DEVTYPVOLUME = 0x00000002;  

1
一条注释 - 在 if (m.Msg == WM_DEVICECHANGE) 周围使用 try-catch。 - Onsightfree
这个能检测到带有多个分区的驱动器吗? - newbieguy

3

微软API代码包。 ShellObjectWatcher类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接