Имя или идентификация последовательных (COM) портов

У меня есть программа, которая обращается к нескольким последовательным портам, используя cport.

Чтобы настроить, до сих пор я просто перечислял все доступные в выпадающем списке списки, чтобы сделать выбор, но растущее число драйверов с (виртуальными) последовательными интерфейсами затрудняет настройку для конечных пользователей.

Текущее обнаружение работает с createfile(), но проблема в том, что вы только получаете существует / не существует и, возможно, "занят" как информация.

Однако для улучшения мне нужно для каждого COM-порта идентификационную строку, например, аппаратное устройство / драйвер (диспетчер устройств), к которому оно также подключено. Это упростит пользователю сужение компортов (поскольку мы поставляем конечное число последовательных карт)

Вероятно, это доступно из WMI, но это довольно непросто, есть ли у sb более конкретная информация или, что лучше, код?

(Delphi XE3, Win7 +, нет решения, которое требует дополнительной установки или развертывания, пожалуйста)

2 ответа

Решение

Если вы хотите перечислить COM-порты, получив понятное имя, вы можете использовать SetupAPI и GUID_DEVINTERFACE_COMPORT класс интерфейса устройства.

Попробуйте этот образец

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Windows,
  SysUtils,
  JvSetupApi;

const
  GUID_DEVINTERFACE_COMPORT:TGUID='{86E0D1E0-8089-11D0-9CE4-08003E301F73}';

procedure EnumerateCOMPorts;
var
   cbRequired : DWORD;
   hdev     : HDEVINFO;
   idev     : Integer;
   did      : TSPDeviceInterfaceData;
   pdidd    : PSPDeviceInterfaceDetailData;
   PropertyBuffer : array[0..255] of Char;
   DeviceInfoData: TSPDevInfoData;
   PropertyRegDataType: DWORD;
   RequiredSize: DWORD;
begin
  // enumerate the com ports
  hdev :=  SetupDiGetClassDevs(@GUID_DEVINTERFACE_COMPORT, nil, 0,  DIGCF_PRESENT OR DIGCF_DEVICEINTERFACE);
  if ( INVALID_HANDLE_VALUE <>  THandle(hdev) ) then
  begin
    try
      idev:=0;
      ZeroMemory(@did, SizeOf(did));
      did.cbSize := SizeOf(did);
      repeat
        if (SetupDiEnumDeviceInterfaces(hdev, nil, GUID_DEVINTERFACE_COMPORT, idev, did)) then
        begin
            cbRequired := 0;
            SetupDiGetDeviceInterfaceDetail(hdev, @did, nil, 0, cbRequired, nil);
           if (ERROR_INSUFFICIENT_BUFFER= GetLastError()) then
           begin
              pdidd:=AllocMem(cbRequired);
              try
                pdidd.cbSize := SizeOf(TSPDeviceInterfaceDetailData);
                DeviceInfoData.cbSize:= SizeOf(DeviceInfoData);
                RequiredSize:=0;
                if (SetupDiGetDeviceInterfaceDetail(hdev, @did, pdidd, cbRequired, RequiredSize, @DeviceInfoData)) then
                begin

                 PropertyRegDataType:=0;
                 RequiredSize:=0;
                 if SetupDiGetDeviceRegistryProperty(hdev, DeviceInfoData, SPDRP_FRIENDLYNAME, PropertyRegDataType,  PBYTE(@PropertyBuffer[0]), SizeOf(PropertyBuffer), RequiredSize) then
                  Writeln(Format('Friendly Name - %s',[PropertyBuffer]));

                 if SetupDiGetDeviceRegistryProperty(hdev, DeviceInfoData, SPDRP_DEVICEDESC, PropertyRegDataType,  PBYTE(@PropertyBuffer[0]), SizeOf(PropertyBuffer), RequiredSize) then
                  Writeln(Format('Description   - %s',[PropertyBuffer]));

                 if SetupDiGetDeviceRegistryProperty(hdev, DeviceInfoData, SPDRP_LOCATION_INFORMATION, PropertyRegDataType,  PBYTE(@PropertyBuffer[0]), SizeOf(PropertyBuffer), RequiredSize) then
                  Writeln(Format('Location      - %s',[PropertyBuffer]));
                end
                else
                RaiseLastOSError;
              finally
                FreeMem(pdidd);
              end;
           end;
        end
        else
        Break;
        inc(idev);
      until false;
    finally
      SetupDiDestroyDeviceInfoList(hdev);
    end;
  end;
end;

begin
  try
    if not LoadsetupAPI then exit;
     EnumerateCOMPorts;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  readln;
end.

Это вернет что-то вроде так

введите описание изображения здесь

Обратите внимание JvSetupApi Модуль является частью библиотеки JVCL.

Вы можете использовать HKEY_LOCAL_MACHINE \HARDWARE\DEVICEMAP\SERIALCOMM для коротких имен в стиле COMxx. Не забывайте указывать доступ только для чтения, чтобы избежать прав администратора или необходимости UAC. Вы можете увидеть как адаптеры usb232, так и реальные порты связи.

Вы также можете проверить HKEY_LOCAL_MACHINE \SYSTEM\CurrentControlSet\Enum\Root\PORTS, но это кажется немного сложным.

Другие вопросы по тегам