According to this , PJ Naughter has implemented 9 methods to emunerate com port in Windows. That code was named . As my using, I found some method would list non-existed com ports. for example: My computer com port be : But the output of PJ Naughte's EnumSerialPorts be : Otherwise, that code are too extrvagen, those is hard to separate into an individual function: it is too much dependency on the other functions. I has reorganized those functions being independent forms in C(instead of C++), those are more portable and useful. I also eliminated some methods which would report unused com ports. My code be : The output be : Note that: EnumerateComPortSetupAPI_GUID_DEVINTERFACE_COMPORT would not list CH340 port, which is on an Arduino UNO board. (But the same function could list other CH340 port, if it is not on this Arduino). Besides, this function could not list Bluetooth virtual com ports. If you would like to use my code, I suggest you use function That is the best one which balances speed and detail; but this one are most complicated in implementation. Otherwise, if you want to implement a function which could list com ports as simple as possible, I recommend use the CreateFilemethod: that is rudimentary, but sufficient.
CreateFile method reportsCOM1COM4COM5COM98COM99QueryDosDevice method reportsCOM5COM1COM98COM99COM4GetDefaultCommConfig method reportsCOM1COM4COM5COM98COM99Device Manager (SetupAPI - GUID_DEVINTERFACE_COMPORT) reportsCOM1 <通訊連接埠> COM4Device Manager (SetupAPI - Ports Device information set) reportsCOM99 通訊連接埠>COM4 COM1 <通訊連接埠> COM98 COM5 通訊連接埠>EnumPorts method reportsCOM1COM2COM4COM7COM8COM10COM6COM5COM98COM99COM9COM11COM12COM13COM14COM16COM17COM18COM19COM20COM21COM22COM23COM24COM25COM26COM27COM28COM29COM30COM31COM32COM3WMI method reportsCOM1 <通訊連接埠 (com1)> ComDB method reportsCOM1COM3COM4COM5COM6COM7COM8COM9COM22COM23COM24COM25COM26COM27COM28COM29COM30COM31COM32COM98COM99Registry method reportsCOM98COM99COM5COM1COM4 通訊連接埠>
/* Enumerating com ports in Windows original by PJ Naughter, 1998 - 2013 http://www.naughter.com/enumser.html (Web: www.naughter.com, Email: pjna@naughter.com) reorganize by Gaiger Chen , Jul, 2015 NO COPYRIGHT, welcome to use for everyone.*/#include#include #include #include #include #define MAX_PORT_NUM (256)#define MAX_STR_LEN (256*sizeof(TCHAR))/*assure portName be double ARRAY , not double point*/BOOL EnumerateComPortByCreateFile(UINT *pNumber, TCHAR *pPortName, int strMaxLen){ UINT i, jj; INT ret; TCHAR *pTempPortName; *pNumber = 0; jj = 0; pTempPortName = (TCHAR*)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY, strMaxLen*sizeof(pTempPortName)); ret = FALSE; for (i = 1; i<= 255; i++){ HANDLE hSerial; _stprintf_s(pTempPortName, strMaxLen, TEXT("\\\\.\\COM%u"), i); hSerial = CreateFile(pTempPortName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); if(INVALID_HANDLE_VALUE == hSerial) continue; _tcsncpy(pPortName + jj*strMaxLen, pTempPortName, _tcsnlen(pTempPortName, strMaxLen)); jj++; }/*for [i MAX_PORT_NUM] */ HeapFree(GetProcessHeap(), 0, pTempPortName); pTempPortName = NULL; *pNumber = jj; if(0 = dwAllocatedSize) continue; //NULL terminate the data if it was not returned NULL terminated because it is not stored null terminated in the registry if (pszPortName[dwReturnedSize/sizeof(TCHAR) - 1] != _T('\0')) pszPortName[dwReturnedSize/sizeof(TCHAR)] = _T('\0'); }/*local varable*/ //If it looks like "COMX" then //add it to the array which will be returned nLen = _tcslen(pszPortName); if (3 < nLen) { if (0 == _tcsnicmp(pszPortName, TEXT("COM"), 3)) { if(FALSE == isdigit(pszPortName[3]) ) continue; //Work out the port number _tcsncpy(pPortName + jj*strMaxLen, pszPortName, _tcsnlen(pszPortName, strMaxLen)); //_stprintf_s(&portName[jj][0], strMaxLen, TEXT("%s"), pszPortName); } else { continue; }/*if 0 == _tcsnicmp(pszPortName, TEXT("COM"), 3)*/ }/*if 3 < nLen*/ LocalFree(pszPortName); isFound = TRUE; //Close the key now that we are finished with it RegCloseKey(hDeviceKey); }/*INVALID_HANDLE_VALUE != hDeviceKey*/ if(FALSE == isFound) continue; //If the port was a serial port, then also try to get its friendly name { TCHAR szFriendlyName[1024]; DWORD dwSize; DWORD dwType; szFriendlyName[0] = _T('\0'); dwSize = sizeof(szFriendlyName); dwType = 0; if( (TRUE == SetupDiGetDeviceRegistryPropertyFunPtr(hDevInfoSet, &devInfo, SPDRP_DEVICEDESC, &dwType, (PBYTE)(szFriendlyName), dwSize, &dwSize) ) && (REG_SZ == dwType) ) { _tcsncpy(pFriendName + jj*strMaxLen, &szFriendlyName[0], _tcsnlen(&szFriendlyName[0], strMaxLen)); } else { _stprintf_s(pFriendName + jj*strMaxLen, strMaxLen, TEXT("")); }/*if SetupDiGetDeviceRegistryPropertyFunPtr */ }/*local variable */ jj++; }while(1); *pNumber = jj; if(0 = dwAllocatedSize) continue; //NULL terminate the data if it was not returned NULL terminated because it is not stored null terminated in the registry if (pszPortName[dwReturnedSize/sizeof(TCHAR) - 1] != _T('\0')) pszPortName[dwReturnedSize/sizeof(TCHAR)] = _T('\0'); }/*local varable*/ //If it looks like "COMX" then //add it to the array which will be returned nLen = _tcslen(pszPortName); if (3 < nLen) { if (0 == _tcsnicmp(pszPortName, TEXT("COM"), 3)) { if(FALSE == isdigit(pszPortName[3]) ) continue; //Work out the port number _tcsncpy(pPortName + jj*strMaxLen, pszPortName, _tcsnlen(pszPortName, strMaxLen)); //_stprintf_s(&portName[jj][0], strMaxLen, TEXT("%s"), pszPortName); } else { continue; }/*if 0 == _tcsnicmp(pszPortName, TEXT("COM"), 3)*/ }/*if 3 < nLen*/ LocalFree(pszPortName); isFound = TRUE; //Close the key now that we are finished with it RegCloseKey(hDeviceKey); }/*INVALID_HANDLE_VALUE != hDeviceKey*/ if(FALSE == isFound) continue; //If the port was a serial port, then also try to get its friendly name { TCHAR szFriendlyName[1024]; DWORD dwSize; DWORD dwType; szFriendlyName[0] = _T('\0'); dwSize = sizeof(szFriendlyName); dwType = 0; if( (TRUE == SetupDiGetDeviceRegistryPropertyFunPtr(hDevInfoSet, &devInfo, SPDRP_DEVICEDESC, &dwType, (PBYTE)(szFriendlyName), dwSize, &dwSize) ) && (REG_SZ == dwType) ) { _tcsncpy(pFriendName + jj*strMaxLen, &szFriendlyName[0], _tcsnlen(&szFriendlyName[0], strMaxLen)); } else { _stprintf_s(pFriendName + jj*strMaxLen, strMaxLen, TEXT("")); }/*if SetupDiGetDeviceRegistryPropertyFunPtr */ }/*local variable */ jj++; }while(1); HeapFree(GetProcessHeap(), 0, pGuid); *pNumber = jj; if(0 \n"), &portName[i][0], &friendlyName[i][0]); setlocale(LC_CTYPE, nativeLocale); for(i = 0; i< MAX_PORT_NUM; i++){ ZeroMemory(&portName[i][0], MAX_STR_LEN); ZeroMemory(&friendlyName[i][0], MAX_STR_LEN); }/*for i[i MAX_PORT_NUM]*/ _tprintf(TEXT("\nSetupAPI SetupDiClassGuidsFromNamePort method : \n")); TIMER_BEGIN(EnumerateComPortSetupAPISetupDiClassGuidsFromNamePort); EnumerateComPortSetupAPISetupDiClassGuidsFromNamePort(&n, &portName[0][0], MAX_STR_LEN, &friendlyName[0][0]);TIMER_END(EnumerateComPortSetupAPISetupDiClassGuidsFromNamePort); _tprintf(TEXT("sought %d:\n"), n); setlocale(LC_CTYPE, "" ); for(i = 0; i< n; i++) _tprintf(TEXT("\t%s <%s> \n"), &portName[i][0], &friendlyName[i][0]); setlocale(LC_CTYPE, nativeLocale); for(i = 0; i< MAX_PORT_NUM; i++) ZeroMemory(&portName[i][0], MAX_STR_LEN); _tprintf(TEXT("\nRegistry method : \n"));TIMER_BEGIN(EnumerateComPortRegistry); EnumerateComPortRegistry(&n, &portName[0][0], MAX_STR_LEN);TIMER_END(EnumerateComPortRegistry); _tprintf(TEXT("sought %d:\n"), n); for(i = 0; i< n; i++) _tprintf(TEXT("\t%s\n"), &portName[i][0]); return 0; }/*main*/
CreateFile method :EnumerateComPortByCreateFile cost time = 35 mssought 5: \\.\COM1 \\.\COM4 \\.\COM5 \\.\COM98 \\.\COM99QueryDosDevice method : EnumerateComPortQueryDosDevice cost time = 7 mssought 5: COM5 COM1 COM98 COM99 COM4GetDefaultCommConfig method :EnumerateComPortByGetDefaultCommConfig cost time = 772 mssought 5: COM1 COM4 COM5 COM98 COM99SetupAPI GUID_DEVINTERFACE_COMPORT method :EnumerateComPortSetupAPI_GUID_DEVINTERFACE_COMPORT cost time = 12 mssought 2: COM1 <通訊連接埠> COM4SetupAPI SetupDiClassGuidsFromNamePort method :EnumerateComPortSetupAPISetupDiClassGuidsFromNamePort cost time = 10 mssought 5: COM99 通訊連接埠>COM4 COM1 <通訊連接埠> COM98 COM5 通訊連接埠>Registry method :EnumerateComPortRegistry cost time = 0 mssought 5: COM98 COM99 COM5 COM1 COM4
BOOL EnumerateComPortSetupAPISetupDiClassGuidsFromNamePort(UINT *pNumber, TCHAR *pPortName, int strMaxLen, TCHAR *pFriendName)