Why can’t I access COM Ports above COM9 on Windows?

Serial ports were used in a verity of applications reliably for a very long time now. Although PCs and Laptops don’t come with built in serial ports anymore, serial port interface emulated over USB is very popular among DIYers/hackers and with certain products. USB specification defines a class (Communication Devices Class) for using USB transport and infrastructure to emulate serial port interface thus legacy applications can continue operate even when the hardware uses USB. This also allows for a range of products such as Numato Lab’s USB GPIO and USB Relay modules to use USB but still have the ease of use Serial interface offers. An example of such a device is in the image below as shown in Windows Device Manager.


In the olden days, PCs and laptops used to be equipped with one or two serial ports. You could have more if you had a PCI or ISA Serial Port expansion card installed. Even then, the chances of having more than nine serial ports on a single machine was slim unless you had a bunch of those cards installed on the same machine. But as USB CDC devices became very popular, it has become very easy to attach a lot of devices to a single machine. Now it is easy to go have a COM port on your machine that goes beyond COM9. The situation has gotten even worse by the fact that Windows tend to reserve port names and that becomes unusable for new devices. The serial ports that are grayed out in the image below represent devices that are not attached to the PC the moment. But since they are reserved by Windows, when a new device is attached to the PC, Windows cannot reuse those names for the new device. It is easy to see how fast the COM port numbers can grow beyond COM9.


This poses a challenge when trying to write your own program to control or communicate with these devices. Usually Serial ports can be opened for communication on Windows by passing the device name such as COM2 to the CreateFile() function (or the equivalent method offered by your language/library to open a port). When successful, the CreatFile() function will return a handle to the port that can be used for further interaction with the port. The code below works just fine as long as the port number is COM9 or below.

hComPort = CreateFile("COM9", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);

Given everything else works fine, this code should return the device handle successfully. But as soon as the port name becomes COM10 or larger (it is easy to happen these days as explained above), call to CreateFile() will fail with error INVALID_HANDLE_VALUE. Although the exact reason behind this behavior is not explained, Microsoft has a support article addressing this issue. According to Microsoft, the correct way of specifying port name is \\.\COM10 . This format does work with ports that have smaller port numbers as well. So it is recommended to use this format irrespective of how large or small the port number is. The following code will be able to successfully open a port in all cases.

hComPort = CreateFile("\\\\.\\COM9", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);

Please note the additional back slashes here. C/C++ requires back slashes to be escaped with additional back slash. This solution should work with any language that you are working with such as VB.Net, C# and so on. Additional back slashes may be optional if the particular language doesn’t require it. If you are using a library or component for accessing Serial Ports, the library may have already taken care of this issue and you may not have worry about this.

Leave A Comment