如何检测硬盘是不是通过 USB 连接?

Posted

技术标签:

【中文标题】如何检测硬盘是不是通过 USB 连接?【英文标题】:How do I detected whether a hard drive is connected via USB?如何检测硬盘是否通过 USB 连接? 【发布时间】:2010-09-18 05:17:15 【问题描述】:

我正在尝试为朋友和家人编写一个小备份程序,并希望它尽可能简单易用。我不想问用户将他们的数据备份到哪里,我只想搜索并使用连接到计算机的第一个 USB 硬盘驱动器。获取硬盘驱动器的唯一 ID 可能也是一个好主意,就像在下次运行备份时仔细检查一样。

【问题讨论】:

【参考方案1】:

可以不费吹灰之力地收集几条信息:

使用 GetDriveType 查找第一个可移动驱动器,测试是否存在可写介质(这将在很大程度上排除 CD 驱动器)。当您通过 win32 查询驱动器信息时,可能还想查看更多可用的字符串。 使用 libusb 查看第一个存储类 USB 设备的位置(可能是闪存或硬盘驱动器) 这个C# article 指向您可能能够利用的win32 磁盘驱动器类。

找到答案后在这里发布!

-亚当

【讨论】:

感谢您的快速回复。 GetDriveInfo 为固定硬盘驱动器(驱动器 C)返回与 UDB 硬盘驱动器相同的值; DRIVE_FIXED。我用 U 盘试​​了一下,它报告为 DRIVE_REMOVABLE。【参考方案2】:

我知道你的问题被标记为 Win32,但这对于 .NET 来说非常简单:

foreach (IO.DriveInfo drive in IO.DriveInfo.GetDrives()) 
  if ((drive.DriveType == IO.DriveType.Removable)) 
    // this is a removable drive
  

查看 drive.Name 和 drive.VolumeLabel 以获取标签。您还可以得到大小,并有根据地猜测它是一个 USB 记忆棒(并且足够大)——可移动意味着软盘或 USB,according to the docs。

作为旁注,从 UI 的角度来看,我建议您第一次找到新驱动器时,将其展示给用户并询问“这是您要用于备份的驱动器吗?”。否则,很可能会意外擦除碰巧插入的 USB 密钥上的数据。没有什么比破坏您的数据更能破坏备份程序的可信度的了。 :)

【讨论】:

我假设 IO.DriveInfo 与 win32 api 中的 GetDriveInfo 相同。如果是这样,它会为 USB 硬盘驱动器返回与固定硬盘驱动器相同的值 (DRIVE_FIXED)。【参考方案3】:

您需要使用RegisterDeviceNotification 函数。 Here 是一些关于如何做的指针。还有一个sample code

您可以使用this 示例枚举所有大容量存储设备。通常寻找 SetupDiXXX api。

请注意,考虑到 USB 设备的动态特性,恕我直言,使用通知机制是强制性的。您可能会发现您的自我分析设备已经分离或丢失了刚刚到达的新设备。

【讨论】:

感谢您的指点,但我不想检测驱动器何时连接或断开,我想知道连接的驱动器是否是 USB 驱动器(可以在我的程序启动之前插入) .【参考方案4】:

我花了一点时间环顾四周,发现了一个名为 SetupDiEnumDeviceInfo 的函数,它确实提供了一个解决方案来了解硬盘驱动器是否可移动,但有了这些信息,我仍然无法(还)将我找到的内容映射回盘符!

这是我目前所拥有的(以下代码创建了一个 dll):

#include "stdafx.h"
#include <setupapi.h>
#include <devguid.h>
#include <cfgmgr32.h>
extern "C" __declspec(dllexport) int usb_hard_drives() 
  HDEVINFO hdevinfo = SetupDiGetClassDevs(&GUID_DEVCLASS_DISKDRIVE, NULL, NULL, DIGCF_PRESENT);
  if (hdevinfo == INVALID_HANDLE_VALUE) return -1;
  DWORD MemberIndex = 0;
  SP_DEVINFO_DATA sp_devinfo_data;
  ZeroMemory(&sp_devinfo_data, sizeof(sp_devinfo_data));
  sp_devinfo_data.cbSize = sizeof(sp_devinfo_data);
  int c = 0;
  while (SetupDiEnumDeviceInfo(hdevinfo, MemberIndex, &sp_devinfo_data)) 
    DWORD PropertyRegDataType;
    DWORD RequiredSize;
    DWORD PropertyBuffer;
    if (SetupDiGetDeviceRegistryProperty(hdevinfo, &sp_devinfo_data, SPDRP_CAPABILITIES, &PropertyRegDataType, (PBYTE)&PropertyBuffer, sizeof(PropertyBuffer), &RequiredSize)) 
      if (PropertyBuffer && CM_DEVCAP_REMOVABLE == CM_DEVCAP_REMOVABLE) 
        // do something here to identify the drive letter.
        c++;
      
           
    MemberIndex++;
  
  SetupDiDestroyDeviceInfoList(hdevinfo);
  return c;

【讨论】:

如果您有一个已知文件位于可移动驱动器(根)上的已知位置,那么您可以遍历所有驱动器号以查找该文件。当您找到它时,您就知道驱动器号了。【参考方案5】:

我在 Win32 API 中发现了一个很棒的函数来测试驱动器的类型。

if( 2 == ::getDriveType( <driveletter> ))
  // its removable 

函数的返回值:

DRIVE_UNKNOWN 0:无法确定驱动类型。

DRIVE_NO_ROOT_DIR 1:根路径无效;例如,指定路径上没有安装卷。

DRIVE_REMOVABLE 2:驱动器有可移动介质;例如,软盘驱动器、拇指驱动器或闪存卡读卡器。

DRIVE_FIXED 3:驱动器有固定介质;例如,硬盘驱动器或闪存驱动器。

DRIVE_REMOTE 4:驱动器是远程(网络)驱动器。

DRIVE_CDROM 5:驱动器为光驱。

DRIVE_RAMDISK 6:驱动器为RAM盘。

http://msdn.microsoft.com/en-us/library/windows/desktop/aa364939(v=vs.85).aspx

【讨论】:

以上是关于如何检测硬盘是不是通过 USB 连接?的主要内容,如果未能解决你的问题,请参考以下文章

移动硬盘问题 非ATA设备不支持SMART测试

移动硬盘无法读取,是啥原因?

unraid检测硬盘坏道

C# getdrives 类型固定但没有 USB 硬盘?

Linux下如何检测硬盘和内存(源代码)

如何检测任何特定驱动器是不是是硬盘驱动器?