當U盤、移動硬盤和USB讀卡器等設備插入計算機USB接口,Windows會對其進行解析和相關數據記錄,這也是爲什麼很多設備第一次插入計算機時需要較長的時間識別、安裝驅動後,纔會出現盤符,而第二次插入則識別速度快了很多。這些設備的相關信息記錄在Windows的註冊表中,即使將設備拔出,一些信息仍將遺留在註冊表中。
本文方法通過註冊表可以的獲取當前插入計算機的U盤、移動硬盤和USB讀卡器等設備的PID、VID和序列號,這些信息可以用於標識設備和對設備進行下一步動作,如彈出設備需要PID和VID。從原理上講,USB存儲類設備插入當前系統時,會在Windows註冊表如下目錄中進行登記:KEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\USBSTOR\Enum,在其Count項中記錄當前插入設備的個數,對應的0、1、2、...表項的鍵值就記錄這響應設備的信息,這個序號是根據設備插入系統的先後順序遞增記錄的,具體如下圖:
通過編程代碼可以訪問該數據項,進行解析即可,一般當前插入的設備應該排在序號的最後一位。具體流程如下,代碼測試環境爲VS2010,獲取Windows相關數據,還是用微軟的IDE和接口比較方便一些。
1、 通過消息機制捕獲插入USB端口的存儲設備的事件,可參考博主之前的一篇文章:
http://blog.csdn.net/trustbo/article/details/50053229 點擊打開鏈接
2、訪問註冊表獲取信息,代碼如下:
char lpRegPath[512] = { 0 };
char lpRegValue[256] = { 0 };
sprintf(lpRegPath, "SYSTEM\\CurrentControlSet\\services\\USBSTOR\\Enum");
sprintf(lpRegValue, "Count");
//
DWORD dwDataSize(0);
DWORD dwRegType1(REG_DWORD);
DWORD dwRegType2(REG_SZ);
LPBYTE lpRegDwordData(NULL);
LPBYTE lpRegSzData(NULL);
// 查詢註冊表中映射驅動器的設備信息
HKEY hKey;
long lRet;
try
{
lRet = ::RegOpenKeyEx(
HKEY_LOCAL_MACHINE, // root key
lpRegPath, // 要訪問的鍵的位置
0, //
KEY_READ, // 以查詢的方式訪問註冊表
&hKey); // hKEY保存此函數所打開的鍵的句柄
}
catch(...)
{
return false;
}
if(lRet != ERROR_SUCCESS)
return false;
else
{
try
{
lRet = ::RegQueryValueEx(hKey, // 所打開的鍵的句柄
lpRegValue, // 要查詢的鍵值名
NULL,
&dwRegType1, // 查詢數據的類型
lpRegDwordData, // 保存所查詢的數據
&dwDataSize); // 預設置的數據長度
}
catch(...)
{
return false;
}
if(lRet != ERROR_SUCCESS)
{
::RegCloseKey(hKey);
return false;
}
else
{
lpRegDwordData = new BYTE[dwDataSize];
try
{
lRet = ::RegQueryValueEx(hKey,
lpRegValue,
NULL,
&dwRegType1,
lpRegDwordData,
&dwDataSize);
}
catch(...)
{
return false;
}
if(lRet != ERROR_SUCCESS)
{
delete []lpRegDwordData;
::RegCloseKey(hKey);
return false;
}
}
}
DWORD num_HDD = DWORD(*lpRegDwordData);
if (num_HDD==0)
{
return false;
}
char lpRegValue_HDD[16] = { 0 };
sprintf(lpRegValue_HDD, "%d", num_HDD-1);
delete []lpRegDwordData;
try
{
lRet = ::RegQueryValueEx(hKey, // 所打開的鍵的句柄
lpRegValue_HDD, // 要查詢的鍵值名
NULL,
&dwRegType2, // 查詢數據的類型
lpRegSzData, // 保存所查詢的數據
&dwDataSize); // 預設置的數據長度
}
catch(...)
{
return false;
}
if(lRet != ERROR_SUCCESS)
{
::RegCloseKey(hKey);
return false;
}
else
{
lpRegSzData = new BYTE[dwDataSize];
try
{
lRet = ::RegQueryValueEx(hKey,
lpRegValue_HDD,
NULL,
&dwRegType2,
lpRegSzData,
&dwDataSize);
}
catch(...)
{
return false;
}
if(lRet != ERROR_SUCCESS)
{
delete []lpRegSzData;
::RegCloseKey(hKey);
return false;
}
}
::RegCloseKey(hKey);
memmove(GetUSBInfo->U_VID_PID, lpRegSzData+4, 17);//獲取VID_PID
GetUSBInfo->U_VID_PID[17] = '\0';
char SN_temp[32]= {0};
memmove(SN_temp, lpRegSzData+22, 32);
delete []lpRegSzData;
char *needle="&";
char* buf = strstr( SN_temp, needle);
if (buf != NULL)
{
//char *SN_1 = (char *)malloc(buf-SN_temp);
char *temp = SN_temp;
//buf[0]='\0';
//printf( "%s\n ", haystack);
temp = buf + strlen(needle);
/* Get next token: */
buf = strstr( temp, needle);
if (buf != NULL)
{
int SN_strlen = buf - SN_temp;
memmove(GetUSBInfo->U_SN, SN_temp, SN_strlen);
GetUSBInfo->U_SN[SN_strlen] = '\0';
}
else
{
memmove(GetUSBInfo->U_SN, SN_temp, 32);
}
}
else
{
memmove(GetUSBInfo->U_SN, SN_temp, 32);
}
上述方法對Windows XP、Windows 2000、Windows 7 32位和64位均有效。