<$BlogRSDUrl$>

Thursday, November 24, 2005

Enumerating COM ports in Delphi for .NET 

I needed to enumerate all the available COM ports in a .NET application I was writing the other day. Because the 1.1 version of the .NET Framework has no inbuilt support for serial communications, this meant it was time to Google a solution. To my surprise there were surprisingly few hits, with the only usable solution described on a web site written in Chinese. Not to be discouraged, I used the AltaVista BabelFish translation service to translate it to English, and below is the end result (after converting it from C# with the help of the Borland BabelCode web service). I customized it slightly so that either all ports on the system would be returned, or only COM ports (which is all that I was interested in at the time). I'm posting this here so an easy solution will be a mere Google away for all those English speaking Delphi programmers out there. :-)


unit AvailablePortsUnit;

interface

uses
System.Runtime.InteropServices, System.Collections.Specialized;

type
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
PORT_INFO_1 = record
pName: string;
end;

function AvailablePorts(const AComPortsOnly: Boolean): StringCollection;

implementation


[DllImport('winspool.drv', CharSet=CharSet.Auto)]
function EnumPorts(AName: string; ALevel: Integer; ABuffer: IntPtr;
ACbBuff: Integer; out ANeeded: Integer; out AReturned: Integer): Boolean; external;

function AvailablePorts(const AComPortsOnly: Boolean): StringCollection;
type
TPortInfoArray = array of PORT_INFO_1;
var
lIndex: Integer;
lComName: string;
i: Integer;
lCurrent: IntPtr;
lPorts: TPortInfoArray;
lBuffer: IntPtr;
lNeeded: Integer;
lReturned: Integer;
begin
Result := StringCollection.Create;
lBuffer := IntPtr.Zero;
EnumPorts(nil, 1, lBuffer, 0, lNeeded, lReturned);
lBuffer := Marshal.AllocHGlobal((lNeeded + 1));
try
EnumPorts(nil, 1, lBuffer, lNeeded, lNeeded, lReturned);
SetLength(lPorts, lReturned);
lCurrent := lBuffer;
for i := 0 to lReturned - 1 do
begin
lPorts[i] := (PORT_INFO_1(Marshal.PtrToStructure(lCurrent, TypeOf(PORT_INFO_1))));
if (not AComPortsOnly) or (lPorts[i].pName.StartsWith(
'COM')) then
begin
if AComPortsOnly then
begin
lIndex := lPorts[i].pName.IndexOf(
':');
if (lIndex <> -1) then
lComName := lPorts[i].pName.Remove(lIndex, 1)
else
lComName := lPorts[i].pName;
end
else
lComName := lPorts[i].pName;
Result.Add(lComName);
end;
lCurrent := IntPtr((Integer(lCurrent) + Marshal.SizeOf(TypeOf(PORT_INFO_1))));
end;
finally
Marshal.FreeHGlobal(lBuffer);
end;
end;
end.


Comments: Post a Comment

This page is powered by Blogger. Isn't yours?