Using GetCommPorts should mean you don't have to try each one - it should give you the available port numbers.
Other than that, since you're using MFC, your code could be a little simpler if you just stick to using CString. Use its Format method to create the port number string, and there's no need to have lpFileName - it already has a cast method, so your code looks cleaner.
BEtter solution to retrieve serial COM ports and fill a ComboBox (with MFC)
Hi,
Despite the lack of any function to retrieve a list of serial COM ports in MFC, I wrote my own. It's working but I'm a bit confuse with all those Windows data types and I had to do some tricks to convert strings.
I use CreatefileW() to iterate over COM ports and I store the file name in a ComboBox if the port's handle is valid.
Both elements use a LPCTSTR , but I did not find any way to concatenate this data type.
To stay in adequation with MFC, I tried to use CFile instead of CreateFileW but it's more "file" oriented.
I found GetCommPorts(), a Win32 function (winbase.h) but I haven't found any sample code.
Is my code on the right way or I need to take another approach ?
int CMFCArduinoDlg::ListComPorts()
{
HANDLE hComm; // Handle for COM port
CString tempFileName; // Temporary filename
// Iterate 20 times to find any existing COM port
for (int i = 1; i < 20; i++)
{
std::string commonBaseName = "\\\\.\\COM"; // Common base for the filename
commonBaseName += std::to_string(i); // Add port number at the end
// Store the full filename into a CString
tempFileName = commonBaseName.c_str();
// Cstring to LPCTSTR conversion
LPCTSTR lpFileName = tempFileName;
// Scan current port (COM+i)
hComm = CreateFileW(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hComm != INVALID_HANDLE_VALUE)
{
// If hComm exists, add the COM port to ComboBox
comboBoxControl.AddString(lpFileName);
CloseHandle(hComm);
}
}
return 0;
}
Thanks and sorry for the headache.
Windows development | Windows API - Win32
3 answers
Sort by: Most helpful
-
David Lowndes 2,640 Reputation points MVP
2023-10-20T15:59:35.8966667+00:00 -
SG 35 Reputation points
2023-10-21T13:37:01.11+00:00 OK found it in Naughter's code:
I replacedCString portList[20];
by
std::vector<CString> portList{ puPortNumbersFound, std::allocator<CString>{} };
Now the function returns a std::vector<CString>
I never used this before, it makes the code cleaner and can save lot of memory.
Thanks very much for your help
-
SG 35 Reputation points
2023-10-21T09:04:51.41+00:00 OK, this GetCommPort function is a bit hard to tame.
I found a piece of code I re-adapted:CString* CMFCArduinoDlg::ListCommPorts() { std::vector<ULONG> lpPortNumbers; // Array to store port numbers lpPortNumbers.resize(255); ULONG puPortNumbersFound = 0; ULONG nReturn = GetCommPorts(&(lpPortNumbers[0]), static_cast<ULONG>(lpPortNumbers.size()), &puPortNumbersFound); if (nReturn != ERROR_SUCCESS) { SetLastError(nReturn); return false; } CString portList[20]; // Pre-allocated CString array for (int i = 0; i < puPortNumbersFound; i++) { portList[i].Format(L"\\\\.\\COM%d", lpPortNumbers[i]); // Port number full string (COMx) } return portList; }
This code is working but my problem is I don't know (anymore) how to pre-allocate the CString array to store the formatted strings.
I left C++ for almost 25 years, things come back little by little. (With my old book: Ivor Horton Visual C++ 6.0 of 1999).