Getting Bluetooth incoming/outgoing serial ports in Delphi

2.7k Views Asked by At

I am looking for a way, programmatically, to first enumerate all Bluetooth serial ports a system has with friendly names and port number and then sort them by either incoming or outgoing ports. From what I have seen, Windows normally assigns the outgoing port first and the next port is usually the incoming port, but this is not always the case. Is there a way to determine from either the registry or other methods such as a Windows API call to determine which ports are incoming or outgoing, and which ones are only for Bluetooth? Under the Bluetooth Radio Properties, it shows port, direction, and name, so this data must be available somewhere (I would hope).

My current code just grabs all active COM ports and places them in a combo box with friendly names and port numbers. Eg: Communications Port (COM1) Bluetooth Communications Port (COM9) Bluetooth Communications Port (COM10)

procedure Form1.RefreshButtonClick(Sender: TObject);
var
    strsCOMPorts : TStringList;
    GotDev:  LongBool;
    Handle1, Devn, idx, maxwidth, tmpwidth: integer;
    dinst, itsname, text: string;
    PluggedIn: ulong;
    DeviceInfo: SP_DEVINFO_DATA;
    PnPHandle: HDEVINFO;
    DeviceInstanceId : array [0..255] of char;
    RequiredSize: DWORD;

    qSetupDiGetDeviceRegistryPropertyA : TSetupDiGetDeviceRegistryPropertyA;
    qSetupDiGetClassDevsA : tSetupDiGetClassDevsA;
    qSetupDiEnumDeviceInfo : tSetupDiEnumDeviceInfo;
    qSetupDiGetDeviceInstanceIdA : tSetupDiGetDeviceInstanceIdA;
    qSetupDiDestroyDeviceInfoList : tSetupDiDestroyDeviceInfoList;

  function get_driver_property(RegProperty:Cardinal):string;
  var lval : string[255];
    RequiredSize : DWORD;
    PropertyRegDataType:      DWord;
    DeviceInfo1: SP_DEVINFO_DATA;
  begin
    DeviceInfo1:=DeviceInfo;
    RegProperty:=RegProperty;
    lval:='                                        ';
    SetLength(lval,255);
    RequiredSize:=255;

    PluggedIn:=PluggedIn or ord(qSetupDiGetDeviceRegistryPropertya(PnPHandle,DeviceInfo1,
                                                 RegProperty,
                                                 PropertyRegDataType,
                                                 @lval[1],RequiredSize,RequiredSize));

    SetLength(lval,RequiredSize-1);
    if RequiredSize=255 then
      lval:=' ';

    result:=lval;
  end;

begin
  Handle1 := LoadLibrary('SetupAPI.dll');

  if Handle1 <> 0 then
  begin
    qSetupDiGetClassDevsA := GetProcAddress(Handle1, 'SetupDiGetClassDevsA');
    qSetupDiEnumDeviceInfo := GetProcAddress(Handle1, 'SetupDiEnumDeviceInfo');
    qSetupDiGetDeviceInstanceIdA := GetProcAddress(Handle1, 'SetupDiGetDeviceInstanceIdA');
    qSetupDiDestroyDeviceInfoList := GetProcAddress(Handle1, 'SetupDiDestroyDeviceInfoList');
    qSetupDiGetDeviceRegistryPropertyA  := GetProcAddress(Handle1,'SetupDiGetDeviceRegistryPropertyA');
  end;

  text := portsCombo.Text;
  strsCOMPorts := TStringList.Create;

  PnPHandle := qSetupDiGetClassDevsa(0, NIL, 0,DIGCF_ALLCLASSES or DIGCF_PRESENT);
  Devn := 0;
  repeat
    DeviceInfo.cbSize:=sizeof(DeviceInfo);
    GotDev:=qSetupDiEnumDeviceInfo(PnPHandle,Devn,DeviceInfo);
    PluggedIn:=0;

    if GotDev then
    begin
      qSetupDiGetDeviceInstanceIdA(PnPHandle,@DeviceInfo,@DeviceInstanceId,255,@RequiredSize);
      dinst:=strpas(@DeviceInstanceId);

      itsname:=get_driver_property(SPDRP_FriendlyName);
      if itsname=' ' then
        itsname:=get_driver_property(SPDRP_DEVICEDESC);

      if (TRIM(itsname) <> '') and (pos('(COM',itsname) > 0) then
        strsCOMPorts.Add(itsname);

      Inc(Devn);
    end;
  until not GotDev;

  qSetupDiDestroyDeviceInfoList(PnPHandle);
  FreeLibrary(Handle1);

  portsCombo.Items.Assign(strsCOMPorts);
  strsCOMPorts.Free;
  idx := portsCombo.Items.IndexOf(text);
  if idx >= 0 then
    portsCombo.ItemIndex := idx
  else
    portsCombo.ItemIndex := 0;

  maxwidth := portsCombo.Width;
  for idx := 0 to portsCombo.Items.Count - 1 do
  begin
    tmpwidth := portsCombo.Canvas.TextWidth(portsCombo.Items[idx]);
    if tmpwidth > maxwidth then
      maxwidth := tmpwidth + 10; // +10 for padding?
  end;
  portsCombo.Perform( CB_SETDROPPEDWIDTH, maxwidth, 0 );
end;
0

There are 0 best solutions below