Serial port enumeration in Delphi using SetupDiGetClassDevs

tim11g picture tim11g · Feb 15, 2011 · Viewed 14.7k times · Source

I'm trying to enumerate "friendly names" for COM ports. The ports may dynamically change as USB-serial devices are connected and disconnected at runtime.

Based on the possible methods described in this question, I am attempting to use the SetupDiGetClassDevs method.

I found this example code, but it is written for an older version of the setupapi unit (the original link to homepages.borland.com doesn't work of course).

I tried using the setupapi unit from the current JVCL(JVCL340CompleteJCL221-Build3845), but it doesn't seem to be compatible with Delphi 7. I get compiler errors:

if SetupDiGetDeviceRegistryProperty(DevInfoHandle,DeviceInfoData,
    RegProperty,
    @PropertyRegDataType,
    @S1[1],RequiredSize,@RequiredSize) then begin

In the call to function SetupDiGetDeviceRegistryProperty, I get the error "Types of actual and formal parameters must be identical" on the parameters @PropertyRegDataType, and @RequiredSize.

The Delphi3000 site says the code was written in 2004 and is intended for Delphi 7, so I'm not sure why it doesn't work with Delphi 7 now, unless setupapi has changed. Is anyone familiar with the changes to setupapi that could cause these problems?

I'm testing with a simple console program. The uses statement is " windows, sysutils, classes, setupAPI, Registry;"

The main program is:

  begin
  ComPortStringList := SetupEnumAvailableComPorts;
  for Index := 0 to ComPortStringList.Count - 1 do
      writeln(ComPortStringList[Index]);
  end;
  end.

Answer

Grzegorz Skoczylas picture Grzegorz Skoczylas · Feb 28, 2014

The following procedure is working correctly for me (in Windows 8.1). It is important to use the parameter KEY_READ in the TRegistry.Constructor.

procedure  EnumComPorts(const   Ports:  TStringList);

var
  nInd:  Integer;

begin  { EnumComPorts }
  with  TRegistry.Create(KEY_READ)  do
    try
      RootKey := HKEY_LOCAL_MACHINE;
      if  OpenKey('hardware\devicemap\serialcomm', False)  then
        try
          Ports.BeginUpdate();
          try
            GetValueNames(Ports);
            for  nInd := Ports.Count - 1  downto  0  do
              Ports.Strings[nInd] := ReadString(Ports.Strings[nInd]);
            Ports.Sort()
          finally
            Ports.EndUpdate()
          end { try-finally }
        finally
          CloseKey()
        end { try-finally }
      else
        Ports.Clear()
    finally
      Free()
    end { try-finally }
end { EnumComPorts };