1. 程式人生 > >通過Windows登錄檔獲取U盤、行動硬碟和USB讀卡器等裝置的PID、VID和序列號

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