Windows下USB磁盘开发系列三:枚举系统中U盘、并获取其设备信息

时间:2023-01-17 00:21:16

前面我们介绍了枚举系统中的U盘盘符(见《Windows下USB磁盘开发系列一:枚举系统中U盘的盘符》)、以及获取USB设备的信息(见《Windows下USB磁盘开发系列二:枚举系统中所有USB设备》)。有个时候我们不仅仅需要获取U盘盘符(路径),而且需要获取该U盘的硬件信息,比如厂商、friendly name、描述等等。那么我们可以通过前面两个方法,把U盘盘符和设备信息匹配起来吗?答案是肯定的,下面介绍具体的实现方法。

具体方法如下:

1,获取U盘盘符(路径);

2,对U盘路径调用CreateFile()获取U盘句柄;

3,对U盘句柄调用DeviceIoControl()获取其Device Number;

4,调用SetupDiGetClassDevs()/SetupDiEnumDeviceInfo()枚举系统中所有U盘设备;

5,调用SetupDiEnumDeviceInterfaces()/SetupDiGetDeviceInterfaceDetail()获取设备路径;

6,对U盘设备路径调用CreateFile()获取U盘设备句柄;

7,对U盘设备句柄调用DeviceIoControl()获取其Device Number;

8,判断3和7获得的Device Number,两者一致则表示该U盘盘符和设备为同一设备。

具体实现代码如下:

1,获取U盘设备列表

int get_usb_device_list(usb_device_info *usb_list, int list_size)
{
int usb_device_cnt = 0; char disk_path[5] = {0};
char device_path[10] = {0};
DWORD all_disk = GetLogicalDrives(); int i = 0;
DWORD bytes_returned = 0;
STORAGE_DEVICE_NUMBER device_num;
while (all_disk && usb_device_cnt < list_size)
{
if ((all_disk & 0x1) == 1)
{
sprintf_s(disk_path, "%c:", 'A'+i);
sprintf_s(device_path, "\\\\.\\%s", disk_path);
if (GetDriveTypeA(disk_path) == DRIVE_REMOVABLE)
{
// get this usb device id
HANDLE hDevice = CreateFileA(device_path, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0,
&device_num, sizeof(device_num),
&bytes_returned, (LPOVERLAPPED) NULL))
{
usb_list[usb_device_cnt].volume = 'A' + i;
usb_list[usb_device_cnt].device_num = device_num.DeviceNumber;
usb_device_cnt++;
}
CloseHandle(hDevice);
hDevice = 0;
}
}
all_disk = all_disk >> 1;
i++;
} return usb_device_cnt;
}

2,匹配U盘设备信息

int get_usb_device_friendname(usb_device_info *usb_list, int list_size)
{
int i = 0;
int res = 0;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData = {sizeof(DeviceInfoData)}; // get device class information handle
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK,0, 0, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
res = GetLastError();
return res;
} // enumerute device information
DWORD required_size = 0;
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++)
{
DWORD DataT;
char friendly_name[2046] = {0};
DWORD buffersize = 2046;
DWORD req_bufsize = 2046; // get device friendly name
if (!SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData, SPDRP_FRIENDLYNAME, &DataT, (LPBYTE)friendly_name, buffersize, &req_bufsize))
{
continue;
}
if (strstr(friendly_name, "USB") == 0)
{
continue;
} int index = 0;
SP_DEVICE_INTERFACE_DATA did = {sizeof(did)};
PSP_DEVICE_INTERFACE_DETAIL_DATA pdd = NULL; while(1)
{
// get device interface data
if (!SetupDiEnumDeviceInterfaces(hDevInfo, &DeviceInfoData, &GUID_DEVINTERFACE_DISK, index++, &did))
{
res = GetLastError();
if( ERROR_NO_MORE_DEVICES == res || ERROR_NO_MORE_ITEMS == res)
break;
} // get device interface detail size
if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &did, NULL, 0, &required_size, NULL))
{
res = GetLastError();
if(ERROR_INSUFFICIENT_BUFFER == res)
{
pdd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, required_size);
pdd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
}
else
break;
} // get device interface detail
if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &did, pdd, required_size, NULL, NULL))
{
res = GetLastError();
LocalFree(pdd);
pdd = NULL;
break;
} // get device number
DWORD bytes_returned = 0;
STORAGE_DEVICE_NUMBER device_num;
HANDLE hDevice = CreateFile(pdd->DevicePath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0,
&device_num, sizeof(device_num),
&bytes_returned, (LPOVERLAPPED) NULL))
{
for (int usb_index = 0; usb_index < list_size; usb_index++)
{
if (device_num.DeviceNumber == usb_list[usb_index].device_num)
{
strcpy_s(usb_list[usb_index].friendname, friendly_name);
break;
}
}
}
CloseHandle(hDevice);
LocalFree(pdd);
pdd = NULL;
}
} SetupDiDestroyDeviceInfoList(hDevInfo);
return res;
}

3,调用代码:

typedef struct usb_device_info_t
{
char volume;
char friendname[256];
int device_num;
}usb_device_info;
int _tmain(int argc, _TCHAR* argv[])
{
bool bRes = false; usb_device_info usb_list[8];
memset(usb_list, 0, 8*sizeof(usb_device_info));
int usb_cnt = get_usb_device_list(usb_list, 8);
printf("System has %d USB disk.\n", usb_cnt); if (usb_cnt > 0)
{
get_usb_device_friendname(usb_list, usb_cnt);
{
for (int i = 0; i < usb_cnt; i++)
{
printf("%c: %s\n", usb_list[i].volume, usb_list[i].friendname);
}
}
} getchar();
return 1;
}

4,运行结果如下:

Windows下USB磁盘开发系列三:枚举系统中U盘、并获取其设备信息

Windows下USB磁盘开发系列三:枚举系统中U盘、并获取其设备信息的更多相关文章

  1. Windows下USB磁盘开发系列二:枚举系统中所有USB设备

    上篇 <Windows下USB磁盘开发系列一:枚举系统中U盘的盘符>介绍了很简单的获取系统U盘盘符的办法,现在介绍下如何枚举系统中所有USB设备(不光是U盘). 主要调用的API如下: 1 ...

  2. Windows下USB磁盘开发系列一:枚举系统中U盘的盘符

    个时候我们需要区分系统磁盘中,哪些是U盘,这样我们在访问的时候可以区别对待.具体方法如下: 1,调用GetLogicalDrives()返回系统盘符标记位 API GetLogicalDrives() ...

  3. windows下部署&period;netcore&plus;docker系列三 (unbuntu 18&period;4 下安装ftp)

    // 先更新下系统sudo apt-get update//安装ftpsudo apt-get install vsftpd// 启动 服务sudo service vsftpd start//ftp ...

  4. S5PV210开发系列三&lowbar;简易Bootloader的实现

    S5PV210开发系列三 简易Bootloader的实现 象棋小子          1048272975 Bootloader是嵌入式系统上电后第一段运行的代码.对于功能简单的处理器,可能并没有Bo ...

  5. windows下VC界面 DIY系列1----写给想要写界面的C&plus;&plus;程序猿的话

    非常早就想写关于C++ UI开发的一系列博文,博客专栏刚审核通过,就立即開始刷博文,不能辜负自己的一番热血,我并非写界面的高手,仅仅想通过写博文提高我自己的技术积累,也顺便帮助大家解决界面开发的瓶颈. ...

  6. Windows下C&comma;C&plus;&plus;开发环境搭建指南

    Windows下C,C++开发环境搭建指南 前情提要 基于近一段时间很多网友发邮件反馈,说一些项目编译出现问题,诸如此类的情况. 就觉得很有必要写一篇C,C++开发环境的小指南,统一回复. 1.君欲善 ...

  7. Windows下搭建Git开发环境

    Windows下搭建Git开发环境主要有以下三种方法: 1,VS,vs2013和vs2015中已经集成了git插件了 2,msysGit+TortoiseGit 3,msysGit+SourceTre ...

  8. &lbrack;转&rsqb;windows下安装Object-C开发环境

    本文转自:http://hi.baidu.com/jeremylai/item/f40b9116cb3c5d582b3e22f5 在Windows下搭建Objective C开发环境,需要到GNUst ...

  9. 转&colon;Windows下的PHP开发环境搭建——PHP线程安全与非线程安全、Apache版本选择,及详解五种运行模式。

    原文来自于:http://www.ituring.com.cn/article/128439 Windows下的PHP开发环境搭建——PHP线程安全与非线程安全.Apache版本选择,及详解五种运行模 ...

随机推荐

  1. New Training Table

          2014_8_15 CodeForces 261 DIV2 A. Pashmak and Garden 简单题   B. Pashmak and Flowers    简单题   C. P ...

  2. JavaScript中字符串去掉特殊字符和转义字符

    <pre name="code" class="javascript">/*** * 去掉字符串中的特殊字符 */ var excludeSpeci ...

  3. IO流-文本IO&bsol;读写二进制数据

    文本IO 一.简述 OutputStreamWriter类使用选定的编码方式吧Unicode字符流转换为字节流,InputStreamReader类将包含字节的输入流转为可以产生Unicode字符的读 ...

  4. 快学Java NIO 续篇

    可以先看Java NIO的整体介绍,这篇接着说以下内容,<快学Java NIO>续篇 FileChannel SocketChannel ServerSocketChannel Java ...

  5. 链接,光标,DHTML,缩放

    18.1css中链接的使用超链接伪类属性:a:link 表示该链接文字尚未被点选a:visited 表示该链接文字已被点选过a:active 表示该链接文字正被点选,但未被放开a:hover 表示当鼠 ...

  6. js程序设计03——面向对象

    ECMAScript中有2中属性:数据属性.访问器属性. 数据属性是为了指定某对象的指定key上的一些行为,比如value是否可删除.修改.key可循环遍历等特点.而访问器属性不包含数据值,包含一堆g ...

  7. Tinkphp定时发布文章的教程

    第一步:在文章表中加一个字段,用来保存定时发布的时间 假定我把这个字段设为 push_time 默认为 0 第二步:写一个方法来检查文章列表,把文章列表到时间的文章改为发布状态 //定时发布文章 pu ...

  8. &lpar;转&rpar;iOS Wow体验 - 第五章 - 利用iOS技术特性打造最佳体验

    本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第五章译文精选,其余章节将陆续放出.上一篇:Wow ...

  9. 关于Java String 类型转换时null的问题

    开发中经常遇到从集合类List.Map中取出数据转换为String的问题,这里如果处理不好,经常会遇到空指针异常java.lang.NullPointerException,在此总结一下常用转换为St ...

  10. vue v-for循环的用法

    1.v-for循环普通数组 ①创建vue对象 ② 循环数据 结果: 2.v-for循环对象数组 ① 创建vue实例对象 ② 循环对象数组 结果: 3.v-for循环对象 ①创建vue对象实例 ②循环对 ...