Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Detect available serial ports on Windows PC?

1,054 views
Skip to first unread message

Jeff Godfrey

unread,
Aug 25, 2010, 11:06:10 AM8/25/10
to
I have the need to enumerate all available serial ports (COM1, COM2, etc
- not USB ports) on a Windows-based PC. What's the best way to do this?
I had hoped that TWAPI might provide that info, but perusing the docs
hasn't turned up anything in that regard. Perhaps I've just missed it?

I suppose I could somehow brute-force my way through a list of known
device names and attempt to connect to each, but that seems ugly.

Thanks,

Jeff

Robert Heller

unread,
Aug 25, 2010, 12:04:01 PM8/25/10
to

Does MS-Windows even support more than four (COM1, COM2, COM3, and COM4)
hardware RS232 ports? While ugly, it might be that hitting each of
these 4 device names might be the simplest way to go.

This is what I have done under Linux:

proc GetAllSerialPorts {} {
set portlist [eval [concat exec /bin/setserial -gb \
[glob -nocomplain /dev/ttyS*] 2>/dev/null]]
set result {}
foreach line [split $portlist "\n"] {
if {[regexp {^(.*) at } "$line" => port] > 0} {
lappend result [string trim "$port"]
}
}
return $result
}

Note: '/bin/setserial -gb' is more or less much the same as this
cross-platform code (the code above pre-dates Tcl's serial port
support):

proc setserial {dev} {
if {[catch {open $dev r} chan]} {return {}}
if {[catch {fconfigure $chan -mode} mode]} {
close $chan
return {}
} else {
close $chan
return [list $dev -mode $mode]
}
}

What my code is doing is just gathering all of the serial port device names in
/dev/ (/dev/ttyS*), and then attempting to get their port settings.
setserial is 'mute' for device names that are not connected to an actual
port. I then strip off the first 'word' (the device name) of each line
that setserial writes out. setserial is basically just doing a
'brute-force' open of each of its command line arguments and returning
some info about those arguments that it successfully opens.

>
> Thanks,
>
> Jeff
>

--
Robert Heller -- 978-544-6933
Deepwoods Software -- Download the Model Railroad System
http://www.deepsoft.com/ -- Binaries for Linux and MS-Windows
hel...@deepsoft.com -- http://www.deepsoft.com/ModelRailroadSystem/

Jeff Godfrey

unread,
Aug 25, 2010, 1:55:32 PM8/25/10
to
On 8/25/2010 11:04 AM, Robert Heller wrote:
> At Wed, 25 Aug 2010 10:06:10 -0500 Jeff Godfrey<jeff_g...@pobox.com> wrote:
>
>>
>> I have the need to enumerate all available serial ports (COM1, COM2, etc
>> - not USB ports) on a Windows-based PC. What's the best way to do this?
>> I had hoped that TWAPI might provide that info, but perusing the docs
>> hasn't turned up anything in that regard. Perhaps I've just missed it?
>>
>> I suppose I could somehow brute-force my way through a list of known
>> device names and attempt to connect to each, but that seems ugly.
>
> Does MS-Windows even support more than four (COM1, COM2, COM3, and COM4)
> hardware RS232 ports? While ugly, it might be that hitting each of
> these 4 device names might be the simplest way to go.

Robert,

Thanks for the input and the code. Unless someone has a cleaner, more
Windows-centric way of accomplishing this, I may end up using a
brute-force method.

Jeff

Pat Thoyts

unread,
Aug 25, 2010, 2:08:22 PM8/25/10
to
Jeff Godfrey <jeff_g...@pobox.com> writes:

See http://paste.tclers.tk/164

--
Pat Thoyts http://www.patthoyts.tk/
PGP fingerprint 2C 6E 98 07 2C 59 C8 97 10 CE 11 E6 04 E0 B9 DD

Jeff Godfrey

unread,
Aug 25, 2010, 4:55:55 PM8/25/10
to
On 8/25/2010 1:08 PM, Pat Thoyts wrote:
> Jeff Godfrey<jeff_g...@pobox.com> writes:
>
>> I have the need to enumerate all available serial ports (COM1, COM2,
>> etc - not USB ports) on a Windows-based PC. What's the best way to do
>> this? I had hoped that TWAPI might provide that info, but perusing the
>> docs hasn't turned up anything in that regard. Perhaps I've just
>> missed it?
>>
>> I suppose I could somehow brute-force my way through a list of known
>> device names and attempt to connect to each, but that seems ugly.
>
> See http://paste.tclers.tk/164

Pat,

Thanks for the link. At this point, I'm really not looking to go the
'C' route, but you never know.

Jeff


Dave Harper

unread,
Aug 25, 2010, 7:46:16 PM8/25/10
to
On 8/25/2010 10:06 AM, Jeff Godfrey wrote:
> I have the need to enumerate all available serial ports (COM1, COM2, etc
> - not USB ports) on a Windows-based PC. What's the best way to do this?
> I had hoped that TWAPI might provide that info, but perusing the docs
> hasn't turned up anything in that regard. Perhaps I've just missed it?

Here's a proc I've used in several scripts. It will interrogate the
registry for a list of COM ports and return it to the calling procedure
(in list form).

proc comList {} {
set keyname "HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM"
set rtn [registry values $keyname]
set coms {}
foreach i $rtn {
lappend coms [registry get $keyname $i]
}
return $coms
}

HTH,
Dave

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Jeff Godfrey

unread,
Aug 25, 2010, 8:40:33 PM8/25/10
to

Dave,

Thanks for the code - that looks interesting. Looking on a few systems
(both XP and Win7), that key seems to contain exactly what I want. The
only exception seems to be if the hardware in question doesn't have any
RS232 ports (such as a modern laptop), in which case the key doesn't
even exist.

That should be get me going.

Thanks,

Jeff

Jeff

Dave Harper

unread,
Aug 25, 2010, 9:06:29 PM8/25/10
to
On 8/25/2010 7:40 PM, Jeff Godfrey wrote:
> The only exception seems to be if the hardware in question doesn't have any
> RS232 ports (such as a modern laptop), in which case the key doesn't
> even exist.

That should be easy enough to detect by using the catch statement to
evaluate the "set rtn [registry values $keyname]" statement. For example:

if [catch {registry values $keyname} rtn] {
<your error processing here>
} else {
<rest of the proc as previously shown>

David Gravereaux

unread,
Aug 26, 2010, 12:33:50 AM8/26/10
to
On 08/25/2010 01:55 PM, Jeff Godfrey wrote:
> On 8/25/2010 1:08 PM, Pat Thoyts wrote:
...

>> See http://paste.tclers.tk/164
>
> Pat,
>
> Thanks for the link. At this point, I'm really not looking to go the
> 'C' route, but you never know.

Jeff,

If you want to try Pat's way:

1) grab Visual Studio Express from
http://www.microsoft.com/express/Downloads/#2008-Visual-CPP and install
it. If it give you the install option named something like 'Use command
prompt tools' allow that.

2) save his code from http://paste.tclers.tk/164 to a text file named
lscomport.c

3) open a command prompt in the same directory as the source file and type:
cl -nologo /MT lscomport.c -link -out:lscomport.exe -subsystem:console

you should have a nice fresh compile of it sitting right there in your
current path after it finishes.

If the command prompt complains about not finding cl.exe, run
vcvars32.bat. info @
http://msdn.microsoft.com/en-us/library/f2ccy3wt(v=VS.90).aspx
this might be your path to it:
"C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vcvars32.bat"

--


signature.asc

Jeff Godfrey

unread,
Aug 26, 2010, 10:45:39 AM8/26/10
to

Hi David,

I already have a full VS installation, but the remainder of your above
instructions should be very handy if I decide to go that route. Thanks
for the providing the details.

Jeff

APN

unread,
Aug 26, 2010, 1:04:42 PM8/26/10
to
Jeff, here's how you can do it with twapi -

This retrieves the GUID for the Ports class
(bin) 76 % set guid [lindex [device_setup_class_name_to_guids Ports]
0]
{4D36E978-E325-11CE-BFC1-08002BE10318}

Collect a devinfoset containing all device elements for that guid.
Returns a handle
(bin) 77 % set h [update_devinfoset -guid $guid]
_80b11600_HDEVINFO

Get the properties "service" and "friendlyname" for each element in
the device set
(bin) 78 % set props [get_devinfoset_registry_properties $h service
friendlyname]
{-deviceelement {{{4D36E978-E325-11CE-BFC1-08002BE10318}} 2640
1486344} 4 {success {sz Parport}} 12 {success {sz {Printer Port
(LPT1)}}}} {-deviceelement {{{4D36E978-E325-11CE-BFC1-08002BE10318}}
2696 1484232} 4 {success {sz Parport}} 12 {success {sz {ECP Printer
Port (LPT1)}}}} {-deviceelement {{{4D36E978-E325-11CE-
BFC1-08002BE10318}} 2752 1483232} 4 {success {sz Serial}} 12 {success
{sz {Communications Port (COM1)}}}}

The above format is a bit complex. Basically, there is one element in
the list for each device. This is element is itself a list. For
example, the 3rd element in the list is

(bin) 79 % lindex $props 2
-deviceelement {{{4D36E978-E325-11CE-BFC1-08002BE10318}} 2752 1483232}
4 {success {sz Serial}} 12 {success {sz {Communications Port (COM1)}}}

This element is itself a list consisting of key, value pairs. The
first key "-devicelement" identifies the device element. Subsequent
pairs are the requested registry values. 4 -> service, and 12 ->
friendlyname. The value associated with each is associated with a
success/fail indicator followed by the actual registry value itself.
So in the above, we can see the service is "Serial" and the
friendlyname is "Communications Port (COM1)".

So you basically need to filter on $props, matching on service being
"Serial".

Unfortunately, this is not documented, being such a horrible
complicated mess that I'm not even sure where to begin documenting it.
You can look in the device.tcl file in the twapi distribution for
more.

Alternatively, you can also use the raw calls that Pat posted directly
from twapi but that would be more involved than the above.

/Ashok

Craig

unread,
Aug 26, 2010, 1:10:26 PM8/26/10
to
On 8/25/2010 9:33 PM, David Gravereaux wrote:

> 1) grab Visual Studio Express from
> http://www.microsoft.com/express/Downloads/#2008-Visual-CPP and install
> it. If it give you the install option named something like 'Use command
> prompt tools' allow that.

David, is there a reason to prefer the 2008 version versus the 2010 version?

craig

APN

unread,
Aug 26, 2010, 1:26:58 PM8/26/10
to
On Aug 26, 10:04 pm, APN <palm...@yahoo.com> wrote:
> Jeff, here's how you can do it with twapi -
>

Sadly, I saw Dave Harper's reply only after I wrote my response using
twapi. Certainly, Dave's method is a hell of a lot easier. As an
aside, where you need more detail, using the WMI interfaces would be
another option.

/Ashok

Jeff Godfrey

unread,
Aug 26, 2010, 1:32:09 PM8/26/10
to

Ashok,

Thanks for providing yet another solution.

Jeff

björn lundin

unread,
Aug 26, 2010, 2:51:28 PM8/26/10
to
> Does MS-Windows even support more than four (COM1, COM2, COM3, and COM4)
> hardware RS232 ports?

Yes it does. In a Warehouse project I lead, we used a windows XP pc to
talk to
7 cranes
1 conveyor
4 scanners
2 scales
all via rs232.

We bought a 'rocket port card' (http://www.comtrol.com/pub/products/
category/cid/67)
with 16 rs232 ports, and counting the motherboard we had 18 serial
ports.

The scanners and scales were controlled via a tcl-script i wrote, that
mapped a tcp-port to a serial port, giving access to the scanners from
a AIX-machine on the LAN.

What I found out was that using names COM1: through COM9: is ok, but
COM10: and above does not work.
see http://support.microsoft.com/kb/115831

use \\.\COM10 (no ':') and I think escape the '\' so it becomes
\\\\.\\COM10

works on less than 10 as well, like \\\\.\\COM3


/Bjöen


David Gravereaux

unread,
Aug 26, 2010, 3:07:44 PM8/26/10
to

no reason, I guess.

Pat's code could also be turned into an extension, too, with just some
slight changes.

--


signature.asc

Eric Boudaillier

unread,
Aug 27, 2010, 3:31:05 AM8/27/10
to
Also note that under Windows XP, the registry HKEY_LOCAL_MACHINE
\HARDWARE\DEVICEMAP\SERIALCOMM lists all serial devices, from which
physical devices [string match "\\Device\\Serial*"].

-eric

0 new messages