One of the posts that keeps reappearing in the programming newsgroups is how
to enumerate all the serial ports installed. The code uses a number of different
methods to enumerate the ports.
Features
- Simple C++ class interface.
- The code is fully Unicode compliant and include Unicode built options in
the workspace file.
- Internally the code provides 10 different ways (yes you read that right:
Ten) of enumerating serial ports: Using CreateFile, QueryDosDevice, GetDefaultCommConfig,
two ways using the Setup API, EnumPorts, WMI, Com Database, enumerating
the values under the registry key HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
& GetCommPorts.
- All of the configuration of the code is controlled by the following preprocessor
values: NO_CENUMERATESERIAL_USING_CREATEFILE,
NO_CENUMERATESERIAL_USING_QUERYDOSDEVICE, NO_CENUMERATESERIAL_USING_GETDEFAULTCOMMCONFIG,
NO_CENUMERATESERIAL_USING_SETUPAPI1, NO_CENUMERATESERIAL_USING_SETUPAPI2, NO_CENUMERATESERIAL_USING_ENUMPORTS,
NO_CENUMERATESERIAL_USING_WMI, NO_CENUMERATESERIAL_USING_COMDB & NO_CENUMERATESERIAL_USING_REGISTRY.
The enclosed zip file contains the
EnumSerialPorts source code and a simple VC 2017 console based application which exercises the functions.
Copyright
- You are allowed to include the source code in any product (commercial, shareware,
freeware or otherwise) when your product is released in binary form.
- You are allowed to modify the source code in any way you want except you
cannot modify the copyright details at the top of each module.
- If you want to distribute source code with your application, then you are
only allowed to distribute versions released by the author. This is to maintain
a single distribution point for the source code.
Updates
v1.43 (16 May 2023)
- Updated copyright details
- Updated modules to indicate that it needs to be compiled using
/std:c++17. Thanks to Martin Richter for reporting this issue.
v1.42 (5 March 2022)
- Updated copyright details.
- Updated the code to use C++ uniform initialization for all variable
declarations.
v1.41 (6 February 2021)
- Fixed a bug in CEnumerateSerial::QueryDeviceDescription where it would
leave a trailing null in the sFriendlyName output parameter. Thanks to
"Thorsten" for reporting this bug.
- Updated copyright details.
- Updated the code to use std::vector::data method throughout. This means
that the code must now be compiled using /std:c++17.
v1.40 (17 March 2020)
- Updated copyright details.
- Fixed more Clang-Tidy static code analysis warnings in the code.
v1.39 (6 November 2019)
- Updated initialization of various structs to use C++ 11 list
initialization
v1.38 (22 June 2019)
- Updated the code to clean compile on VC 2019
v1.37 (15 January 2019)
- Updated copyright details.
- Updated the sample app to log the time each method call takes
- Fixed a compilation error "unknown identifier 'HDEVINFO'" in enumser.h.
Thanks to Drew Freer for reporting this issue.
v1.36 (16 September 2018)
- Fixed a number of compiler warnings when using VS 2017 15.8.4
v1.35 (8 July 2018)
- Updated copyright details.
- Fixed a number of C++ core guidelines compiler warnings. These changes
mean that the code will now only compile on VC 2017 or later.
- Remove the code path which supported CENUMERATESERIAL_MFC_EXTENSIONS
v1.34 (19 May 2018)
- Updated copyright details.
- Addition of a tenth and hopefully final method to enumerate serial
ports. The function is called "UsingGetCommPorts" and enumerates the ports
by calling the Win32 GetCommPorts API which is available on Windows 10 1803
or later.
v1.33 (15 November 2017)
- Updated the code to compile cleanly when _ATL_NO_AUTOMATIC_NAMESPACE is
defined.
v1.32 (25 September 2017)
- Updated copyright details.
- Replaced NULL throughout the codebase with nullptr. This means that the
minimum requirement for the framework is now VC 2010.
- Replaced CString::operator LPC*STR() calls throughout the codebase with
CString::GetString calls
- Removed the CENUMERATESERIAL_USE_STL define and instead introduced a new
CENUMERATESERIAL_MFC_EXTENSIONS define which by default is not defined.
v1.31 (2 July 2016)
- Updated the SAL annotations in the code
v1.30 (28 May 2016)
- The sample app previously excluded support for CEnumerateSerial::UsingComDB
for versions of Visual C 2010 or earlier. Now this check has been changed to
be based on the version of the Windows SDK which the code is being compiled
against. This check is now performed by checking the value of the VER_PRODUCTBUILD
preprocessor value from the ntverp.h SDK header file. The sample app now excludes
support for CEnumerateSerial::UsingComDB on the Windows SDK 7.1 or earlier.
This is because the msports.h header file is only available with the Windows
SDK 8 or later. Thanks to "scott" for reporting this issue.
v1.29 (28 March 2016)
- Updated copyright details.
- Updated CEnumerateSerial::RegQueryValueString to ensure that non null terminated
data returned from the registry API is null terminated before it is treated
as such in the code.
- Reworked CEnumerateSerial::UsingRegistry to internally use CEnumerateSerial::RegQueryValueString.
This ensures that non null terminated data returned from the registry API is
null terminated before it is treated as such in the code.
v1.28 (20 December 2015)
- Updated copyright details.
- Updated the code to compile cleanly on VC 2015.
- Reworked CEnumerateSerial::UsingComDB method to statically link to msports.dll.
- Reworked CEnumerateSerial::UsingSetupAPI1 method to statically link to setupapi.dll.
- Reworked CEnumerateSerial::UsingSetupAPI2 method to statically link to setupapi.dll.
- Removed now unnecessary CEnumerateSerial::LoadLibraryFromSystem32 method.
- Added SAL annotations to all the code.
- Removed call to VerifyVersionInfo from CEnumerateSerial::UsingQueryDosDevice.
- CEnumerateSerial::UsingCreateFile now use ATL::CHandle instead of CAutoHandle.
- CEnumerateSerial::UsingQueryDosDevice now uses ATL::CHeapPtr instead of
CAutoHeapAlloc.
- CEnumerateSerial::UsingSetupAPI2 now uses ATL::CHeapPtr instead of CAutoHeapAlloc.
- CEnumerateSerial::UsingEnumPorts now uses ATL::CHeapPtr instead of CAutoHeapAlloc.
- CEnumerateSerial::UsingWMI now uses ATL::CW2A instead of CAutoHeapAlloc.
- CEnumerateSerial::UsingComDB now uses ATL::CHeapPtr instead of CAutoHeapAlloc.
- CEnumerateSerial::UsingWMI now uses ATL::CComPtr & ATL::CComVariant.
- Removed AutoHandle.h, AutoHeapAlloc.h & AutoHModule.h from distribution
as these modules are no longer required by enumser.
- CEnumerateSerial::UsingSetupAPI1 now uses ATL::CRegKey.
- CEnumerateSerial::UsingSetupAPI2 now uses ATL::CRegKey.
- CEnumerateSerial::UsingRegistry now uses ATL::CRegKey.
- CEnumerateSerial::RegQueryValueString now uses ATL::CRegKey.
- The return value from CEnumerateSerial::UsingWMI is now a HRESULT instead
of a BOOL.
- CEnumerateSerial::UsingEnumPorts now returns the friendly name of the port.
- Fixed an issue calling EnumPorts the first time in CEnumerateSerial::UsingEnumPorts.
- Simplified the declaration of parameters to the various methods of the class.
- CEnumerateSerial::UsingSetupAPI1 and CEnumerateSerial::UsingSetupAPI2 have
been refactored to use a new internal method called "QueryUsingSetupAPI".
- CEnumerateSerial::UsingSetupAPI2 now uses GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR
define.
- Renamed all the NO_ENUMSERIAL_* defines to NO_CENUMERATESERIAL_*.
v1.27 (1 December 2013)
- Updated the code to compile cleanly on VC 2013
v1.26 (3 August 2013)
- Fixed a bug where the return value from "SetupDiOpenDevRegKey"
in UsingSetupAPI1 and UsingSetupAPI2 were not being checked correctly. Thanks
to Ilya Tsybulsky for reporting this bug.
- Tested code to make sure everything compiles cleanly when CENUMERATESERIAL_USE_STL
is not defined and MFC is not included. Please note that if you do not use STL
or MFC then you MUST use ATL.
- Updated code to make sure everything compiles cleanly when CENUMERATESERIAL_USE_STL
is defined and MFC and ATL are not included. This means that this particular
scenario should now work on Express SKU's of Visual Studio.
- Reworked the CEnumerateSerial::UsingWMI method to not require ATL. This
means that this method should now work on Express SKU's of Visual Studio.
v1.25 (28 July 2013)
- Did some very light cleanup of the code to reduce dependencies when #defining
out parts of the code. Thanks to Jay Beavers for providing this update.
v1.24 (10 January 2013)
- Updated copyright details
- Spun off CAutoHModule class into its own header file
- Spun off CAutoHandle class into its own header file
- Addition of a new CAutoHeapAlloc class which encapsulates HeapAlloc / HeapFree
calls in a C++ class.
- Removed ATL usage completely from UsingQueryDevice, UsingSetupAPI2 and UsingEnumPorts.
This should allow these methods to support compilers which do not have support
for ATL such as VC Express SKUs.
v1.23 (15 October 2012)
- Updated copyright details.
- Code no longer uses LoadLibrary without an absolute path when loading SETUPAPI
and MSPORTS dlls. This avoids DLL planting security issues.
- Added a new internal CAutoHandle and CAutoHModule classes which makes the
implementation for CEnumerateSerial simpler
- Code now uses an internal RegQueryValueString method to ensure that data
returned from raw Win32 API call RegQueryValueEx is null terminated before it
is treated as such in the code. Thanks to Jeffrey Walton for reporting this
security issue.
- Updated the code to clean compile on VC 2012
v1.22 (28 March 2011)
- Updated copyright details.
- Updated the UsingComDB method to fix an off by one issue. This resulting
in the list of ports this function reported being incorrect. Thanks to "Jar,
Min, Jeong" for reporting this issue.
- Updated sample app to compile cleanly on VC 2010
v1.21 (27 March 2010)
- Updated copyright details.
- Code can now optionally use STL instead of MFC or ATL in the API. To use
STL containers instead of MFC or ATL versions, please define CENUMERATESERIAL_USE_STL
before you include enumser in your project. Please note that the code still
internally uses ATL in the UsingWMI method, but the other functions do not.
This means that the class should now be partly compilable on VC Express (2005,
2008 or 2010) as none of these have support for ATL or MFC. I do not personally
have VC Express installed so people's feedback on this would be appreciated.
Thanks to Bill Adair for providing this update.
v1.20 (30 April 2009)
- Updated copyright details.
- Updated the sample app's project settings to more modern default values.
- Updated the sample app to log the time taken for the various methods.
v1.19 (29 November 2008)
- Addition of a ninth and hopefully final method to enumerate serial ports.
The function is called "UsingRegistry" and enumerates the ports by
examining the registry location at HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM.
Thanks to Martin Oberhuber for prompting this update.
- Fixed a bug where the last error value was not being preserved in CEnumerateSerial::UsingComDB.
v1.18 (23 November 2008)
- Updated code to compile correctly using _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
define
- The code now only supports VC 2005 or later.
- Code now compiles cleanly using Code Analysis (/analyze)
- Yes, Addition of a another method called "UsingComDB" to enumerate
serial ports!. This function uses the so called "COM Database" functions
which are part of the Windows DDK which device drivers can use to support claiming
an unused port number when the device driver is being installed. Please note
that the list returning from this function will only report used port numbers.
The device may or may not be actually present, just that the associated port
number is currently "claimed". Thanks to Dmitry Nikitin for prompting
this very nice addition. The code now supports a total of 8 different ways to
enumerate serial ports!
v1.17 (20 March 2008)
- Updated copyright details
- Updates to preprocessor logic to correctly include UsingSetupAPI1 and UsingSetupAPI2
functionality
- Updated sample app to clean compile on VC 2008
v1.16 (5 July 2007)
- Updated the code to work if the code does not include MFC. In this case,
CUIntArray parameters becomes the ATL class CSimpleArray<UINT> and CStringArray
parameters become the ATL class CSimpleArray<CString>. Please note that
this support requires a recentish copy of Visual Studio and will not support
Visual C++ 6.0 as the code makes use of the ATL CString class. Thanks to Michael
Venus for prompting this update.
- CEnumerateSerial::UsingWMI method now uses ATL smart pointers to improve
robustness of the code.
v1.15 (9 June 2007)
- Following feedback from John Miles, it looks like my previous change of
the 29 January 2007 to use GUID_DEVINTERFACE_COMPORT in the UsingSetupAPI method
had the unintended consequence of causing this method not to work on any versions
of Windows prior to Windows 2000. What I have now done is reinstate the old
mechanism using the name UsingSetupAPI2 so that you can continue to use this
approach if you need to support NT 4 and Windows 9x. The new approach of using
GUID_DEVINTERFACE_COMPORT has been renamed to UsingSetupAPI1.
v1.14 (29 January 2007)
- Updated copyright details.
- UsingSetupAPI code now uses the GUID_DEVINTERFACE_COMPORT guid to enumerate
COM ports. Thanks to David McMinn for reporting this nice addition.
- Detection code which uses CreateFile call, now treats the error code of
ERROR_SEM_TIMEOUT as indication that a port is present.
v1.13 (8 November 2006)
- Extended CEnumerateSerial::UsingWMI to now also return the friendly name
of the port. Thanks to Giovanni Bajo for providing this update.
- Fixed a bug where CEnumerateSerial::UsingSetupAPI forget to empty out the
Friendly name array on start.
- VariantInit is now called for the 2 VARIANT structs used in the UsingWMI
method code.
v1.12 (9 July 2006)
- Updated copyright details.
- Addition of a CENUMERATESERIAL_EXT_CLASS macro to allow the code to be easily
added to an extension dll.
- Code now uses newer C++ style casts instead of C style casts.
- Updated the code to clean compile on VC 2005.
- Updated the documentation to use the same style as the web site.
v1.11 (13 May 2004)
- Extended CEnumerateSerial::UsingSetupAPI to now also return the friendly
name of the port. Thanks to Jay C. Howard for prompting this update.
v1.10 (12 December 2003)
- Updated the sample app to VC 6.
- Addition of a "EnumerateSerialPorts6" (See Note 4 below) which
uses WMI.
- You can now optionally exclude each function using preprocessor defines
of the form "NO_ENUMSERIAL_USING_XYX".
- Made the functions members of a C++ class and renamed them to using more
meaningful names
v1.09 (20 September 2003)
v1.08 (22 May 2003)
v1.07 (13 August 2001)
v1.06 (11 August 2001)
v1.05 (25 June 2001)
-
Guess what, You now have the choice of using the GetDefaultCommConfig
thro the use of three versions of the function. You take your pick.
-
Fixed problem where port fails to be reported thro the CreateFile
mechanism when the error code is ERROR_SHARING_VIOLATION i.e. someone has the
port already open.
v1.04 (29 March 2001)
- Reverted code to use CreateFile or QueryDosDevice as it is much faster than
using the GetDefaultCommConfig method.
- Updated copyright message.
v1.03 (17 May 2000)
- Code now uses GetDefaultCommConfig in all cases to detect the ports.
v1.02 (12 December 1999)
- Fixed a problem in the Win9x code path when trying to detect deactivated
IRDA-ports. When trying to open those, you will get the error-code ERROR_GEN_FAILURE.
v1.01 (23 February 1999)
- Code now uses QueryDosDevice if running on NT to determine which serial
ports are available. This avoids having to open the ports at all. It should
operate a lot faster in addition
v1.0 (3 November 1998)