一、注册表中与U盘相关的键
1. \\HKEY_LOCAL_MACHINESYSTEM\\CurrentControlSet\\Services\\USBSTOR\\Enum ,该键中有本机连接的所有U盘的设备路径,Count为U盘的数量,数字键对应的值为U盘的设备路径,形如:USB\VID_1E3D&PID_2096\CCBB123456EE012B;
2. \\HKEY_LOCAL_MACHINESYSTEM\\CurrentControlSet\\Services\\disk\\Enum,该键中存储有物理磁盘设备的路径;count为磁盘数量,数字键对应的值为设备路径,形如:USBSTOR\Disk&Ven_2.0&Prod_Flash_Disk&Rev_2.61\CCBB123456EE012B&1;
3. \\HKEY_LOCAL_MACHINESYSTEM\\CurrentControlSet\\Services\\cdrom\\Enum,该键中存储有光驱的设备路径,Count为数量,数字键名对应的键值为设备路径,形如:USBSTOR\CdRom&Ven_2.0&Prod_Flash_Disk&Rev_2.60\CCBB123456EE012B&0;
4. \\HKEY_LOCAL_MACHINESYSTEM\\MountedDevices,该键中有\DosDevices\X:的键名,X为盘符,其值为对应设备的路径,如:“\DosDevices\E:”的键值为:\??\USBSTOR#CdRom&Ven_2.0&Prod_Flash_Disk&Rev_2.60#CCBB123456EE012B&0#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b},“\DosDevices\F:”的键值为:_??_USBSTOR#Disk&Ven_2.0&Prod_Flash_Disk&Rev_2.61#CCBB123456EE012B&1#{53f56307-b6bf-11d0-94f2-00a0c91efb8b};
二、检测U盘的流程
1. 查询上述1-3所有的键值,存储在三个vector<string>中,然后逐个遍历通过关键字找出各自的对应关系,把对应的值存入USBNod中,USBNode定义如下:
struct UsbNod //检索本机U盘节点,通过检索注册表获取
{
LPCTSTR usb; //U盘的对应USB设备
LPCTSTR cdrom; //U盘对应的光驱设备路径
string cdvol; //U盘对应的光驱盘符
LPCTSTR disk; //U盘对应的大容量磁盘设备路径
string diskvol; //U盘对应的盘符
};
遍历对应关系的代码如下:
//构造系统USB设备的节点数组
char* USBSTOR_key = "SYSTEM\\CurrentControlSet\\Services\\USBSTOR\\Enum";
vector<string> USBSTOR_vals;
getRegEnumValues(USBSTOR_key , USBSTOR_vals);
char* USBDISK_key = "SYSTEM\\CurrentControlSet\\Services\\disk\\Enum";
vector<string> USBDISK_vals;
getRegEnumValues(USBDISK_key , USBDISK_vals);
char* USBCDROM_key = "SYSTEM\\CurrentControlSet\\Services\\cdrom\\Enum";
vector<string> USBCDROM_vals;
getRegEnumValues(USBCDROM_key , USBCDROM_vals);
UsbNod usbdisknod[26];
int count = 0;
for (unsigned int i = 0; i < USBCDROM_vals.size(); i++)
{
int pos = USBCDROM_vals.at(i).rfind('\\') + 1;
string serialnum = USBCDROM_vals.at(i).substr(pos, USBCDROM_vals.at(i).size());
serialnum = serialnum.substr(0,serialnum.size() - 2);
for (unsigned int j = 0; j < USBSTOR_vals.size(); j++)
{
if (USBSTOR_vals.at(j).find(serialnum) == -1)
continue;
for (unsigned int k = 0; k < USBDISK_vals.size(); k++)
{
if (USBDISK_vals.at(k).find(serialnum) == -1)
continue;
usbdisknod[count].cdrom = USBCDROM_vals.at(i).data();
usbdisknod[count].disk = USBDISK_vals.at(k).data();
usbdisknod[count].usb = USBSTOR_vals.at(j).data();
usbdisknod[count].diskvol = getVolFromDevicePath(USBDISK_vals.at(k));
usbdisknod[count].cdvol = getVolFromDevicePath(USBCDROM_vals.at(i));
count++;
}
}
}
读取注册表键值构造vector的函数
//检索Emnu类型的USB设备相关的注册表键值,返回获取到的数量,循环读取内容内容保存在 vector<string> &values
int getRegEnumValues(LPCTSTR key, vector<string> &values)
{
values.clear();
CRegKey usbreg;
long rt = usbreg.Open(HKEY_LOCAL_MACHINE, key, KEY_READ | KEY_ALL_ACCESS);
if (rt != ERROR_SUCCESS) return 0;
DWORD count = 0;
usbreg.QueryDWORDValue("Count", count);
if (count == 0) return 0;
DWORD i, j = 0;
for (i = 0; i<count; i++)
{
char vname[2];
sprintf_s(vname, "%d", i);
DWORD len = 256;
char kValue[256];
if (usbreg.QueryStringValue(vname, kValue, &len) == ERROR_SUCCESS)
{
string v(kValue);
if (v.find("USB") != -1)
{
values.push_back(kValue);
//printf("%s\n",kValue);
j++;
}
}
}
usbreg.Close();
return j;
}
2. 获取U盘对应光盘与磁盘盘符的方法
//根据设备路径获取其对应的盘符
string getVolFromDevicePath(string pDPath)
{
string::iterator it = pDPath.begin();
for (; it != pDPath.end(); it++)
if (*it == '\\') *it = '#';
int DeviceNum = 1001;
if (pDPath.find("Disk") != -1) //如果设备路径中有disk字符,则构造如下路径
{
char ph_Path[MAX_PATH];
sprintf_s(ph_Path, "\\\\?\\%s#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}", pDPath.data());
DeviceNum = GetPhysicalDriveFromDevicePath(ph_Path);
//获取磁盘设备地址对应的物理磁盘号
}
string vol; //得到U盘盘符;
LPTSTR lpDrives = new TCHAR[MAX_PATH];
DWORD dwLen = ::GetLogicalDriveStrings(MAX_PATH, lpDrives);
char* sDrives[26] = { "" };
for (DWORD nIndex = 0; nIndex < dwLen / 4; nIndex++)
{
UINT dType = ::GetDriveType(lpDrives + nIndex * 4);
if (dType == DRIVE_REMOVABLE || dType == DRIVE_CDROM)
{
sDrives[nIndex] = (lpDrives + nIndex * 4);
if (sDrives[nIndex] != "A:\\" && sDrives[nIndex] != "B:\\")
{
//获取盘符对应的MountedDevices中对应的键值
string volkey = getVolKey(sDrives[nIndex][0]);
int pnum = 1002;
//该判断增加对XP系统的支持,在XP中U盘盘符对应的MountedDevices
//的键值与以上2中值不同需要通过获取其物理磁盘号进行比较
if (dType == DRIVE_REMOVABLE)
pnum = GetPhysicalDriveFromPartitionLetter(sDrives[nIndex][0]);
if (pnum == DeviceNum || volkey.find(pDPath) != -1)
{
vol = string(sDrives[nIndex]);
}
}
}
}
delete lpDrives;
return vol;
}
以上注册表键值由windows系统服务维持,经使用还是比较可靠的,未尽问题是对于U盘仅检测有一个U盘盘符的情况,多个U盘盘符未做处理,不过根据源码应该很容易写出。
通过CSDN学习了很多,今天终于自己写了一点东西,不对之处欢迎拍砖。