通過Windows註冊表獲取U盤、移動硬盤和USB讀卡器等設備的PID、VID和序列號

    當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位均有效。

發佈了68 篇原創文章 · 獲贊 368 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章