1. 程式人生 > >VCMFC根據USB裝置PID、VID自動查詢串列埠號

VCMFC根據USB裝置PID、VID自動查詢串列埠號

VC/MFC環境下有兩種方法來根據PIDVID獲取對應的串列埠號,這樣操作的目的是避免客戶手動設定下拉框的資訊,讓軟體自動識別!當然,前提是有自己的USB PIDVID

下面是C++程式碼示例:

// 第一種方法需要包含此標頭檔案
#include <SetupAPI.h>
#pragma comment(lib, "Setupapi.lib")
 
#define MY_USB_PID_VID	_T("VID_1111&PID_2222")
 
/************************************************************************/
/* 根據USB描述資訊字串中讀取
/************************************************************************/
int MTGetPortFromVidPid(CString strVidPid)
{
	// 獲取當前系統所有使用的裝置
	int					nPort	= -1;
	int					nStart	= -1;
	int					nEnd	= -1;
	int					i		= 0;
	CString				strTemp, strName;
	DWORD				dwFlag = (DIGCF_ALLCLASSES | DIGCF_PRESENT);
	HDEVINFO			hDevInfo = INVALID_HANDLE_VALUE;
	SP_DEVINFO_DATA		sDevInfoData;
	TCHAR				szDis[MAX_PATH] = {0x00};// 儲存裝置例項ID
	TCHAR				szFN[MAX_PATH]  = {0x00};// 儲存裝置例項屬性
	DWORD				nSize = 0 ;
 
	// 準備遍歷所有裝置查詢USB
	hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, dwFlag);
	if( INVALID_HANDLE_VALUE == hDevInfo )
		goto STEP_END;
 
	// 開始遍歷所有裝置
	memset(&sDevInfoData, 0x00, sizeof(SP_DEVICE_INTERFACE_DATA));
	sDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
	for(i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &sDevInfoData); i++ )
	{
		nSize = 0;
		
		// 無效裝置
		if ( !SetupDiGetDeviceInstanceId(hDevInfo, &sDevInfoData, szDis, sizeof(szDis), &nSize) )			
			goto STEP_END;
 
		// 根據裝置資訊尋找VID PID一致的裝置
		strTemp.Format(_T("%s"),szDis);
		strTemp.MakeUpper();
		if ( strTemp.Find(strVidPid, 0) == -1 )
			continue;
 
		// 查詢裝置屬性
		nSize = 0;
		SetupDiGetDeviceRegistryProperty(hDevInfo, &sDevInfoData,
			SPDRP_FRIENDLYNAME,
			0, (PBYTE) szFN,
			sizeof(szFN),
			&nSize);
 
		// "XXX Virtual Com Port (COM7)"
		strName.Format(_T("%s"),szFN);
		if(strName.IsEmpty())
			goto STEP_END;
 
		// 尋找串列埠資訊
		nStart = strName.Find(_T("(COM"), 0);
		nEnd = strName.Find(_T(")"), 0);
		if(nStart == -1 || nEnd == -1)
			goto STEP_END;
 
		strTemp = strName.Mid(nStart + 4, nEnd - nStart - 2);
		nPort = atoi(strTemp);
	}
 
STEP_END:
	// 關閉裝置資訊集控制代碼
	if(hDevInfo != INVALID_HANDLE_VALUE)
	{
		SetupDiDestroyDeviceInfoList(hDevInfo);
		hDevInfo = INVALID_HANDLE_VALUE;
	}
 
	return nPort;
}
 
 
/************************************************************************/
/* 根據登錄檔中的PID、VID資訊讀取
/************************************************************************/
int MTUpdateSerialPort(CString strVidPid)
{
	DWORD	dwIndex = 0;
	HKEY	hKey;
	TCHAR	CommName[_MAX_FNAME] = {0x00};
	DWORD	lcbName = _MAX_FNAME;
	DWORD	lValue = MAX_PATH;
	TCHAR	szValue[MAX_PATH];
	LONG	lRtn = 0;
	CString	strTemp, strKey;
	int		nPort	= -1;
	int		nStart	= -1;
	int		nEnd	= -1;
	
	// 讀取PID對應的埠
	strTemp.Format_T("SYSTEM\\CurrentControlSet\\Enum\\USB\\%s"),strVidPid);
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, strTemp, NULL, KEY_READ, &hKey) == ERROR_SUCCESS) 
	{
		dwIndex = 0;
		while (RegEnumKey(hKey,dwIndex++,CommName,lcbName) == ERROR_SUCCESS) 
		{
			// 讀取PID對應的埠
			strKey.Format(_T("SYSTEM\\CurrentControlSet\\Enum\\USB\\%s\\%s\\Device Parameters"),strVidPid,CommName);
			RegCloseKey(hKey);
			if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,strKey,NULL,KEY_READ,&hKey) == ERROR_SUCCESS) 
			{
				lRtn = RegQueryValueEx(hKey,_T("PortName"),NULL,&lValue,(LPBYTE)szValue,&lValue);
				if ( lRtn == ERROR_SUCCESS) 
				{
					// 尋找串列埠資訊
					strName.Format(_T("%s"),szValue);
					nStart = strName.Find(_T("COM"), 0);
					nEnd = strName.Find(_T(")"), 0);
					if(nStart == -1 || nEnd == -1)
					{
						RegCloseKey(hKey);
						return -1;
					}
 
					strTemp = strName.Mid(nStart + 3, nEnd - nStart);
					nPort = atoi(strTemp);
 
					RegCloseKey(hKey);
					return nPort;
				}
			}
 
			lValue  = MAX_PATH;
			lcbName = MAX_PATH;
		}
 
		RegCloseKey(hKey);
	}
 
	return nPort;
}
 
void main()
{
	int		nPort = -1;
	
	// 第一種方法遍歷USB裝置描述
	nPort = MTGetPortFromVidPid(MY_USB_PID_VID);
	
	// 第二種方法遍歷登錄檔的PID、VID屬性
	nPort = MTUpdateSerialPort(MY_USB_PID_VID);
	if(nPort == -1)
		printf("未找到 %s 相關串列埠號!\n");
	else
		printf("成功找到串列埠號:COM%d \n",nPort);
}