【问题标题】:Serial (COM) ports name or identification串行 (COM) 端口名称或标识
【发布时间】:2013-04-19 08:53:18
【问题描述】:

我有一个使用 cport 访问多个串行端口的程序。

要进行配置,到目前为止,我只是在一个组合框中列出了所有可用的 comports 以进行选择,但是越来越多的带有(虚拟)串行接口的驱动程序使最终用户的配置变得很麻烦。

当前检测适用于 createfile(),但存在的问题是您只能获取存在/不存在并且可能“忙”作为信息。

但是,为了改进,我需要每个 COM 端口一个标识字符串,例如它所连接的硬件设备/驱动程序(设备管理器)。这将使用户更容易缩小范围(因为我们提供有限数量的串行卡)

可能它可以从 WMI 获得,但那是一个丛林,sb 是否有更具体的信息,或者更好的代码?

(Delphi XE3,Win7+,没有需要额外安装或部署的解决方案)

【问题讨论】:

  • also : stackoverflow.com/q/613166/327083 ...有 jedi 等组件提供高级别的功能,但如果你想自己动手,我认为 WMI 或注册表是你唯一的追索权。
  • 您正在寻找的可能是一种枚举 com 端口的方法,包括它们的“友好名称”?
  • 可能重复的答案不是很好,基于注册表的方法存在缺陷。
  • "J:" 似乎上述帖子中的 WMI 代码需要提升,这使得“无设置”有点困难。此外,它没有找到所有端口。它没有显示友好的名称。仍然感谢您的提示,这至少是一个开始。

标签: delphi


【解决方案1】:

如果您想枚举 COM 端口以获得友好名称,您可以使用 SetupAPIGUID_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 库的一部分。

【讨论】:

  • 是的,同时也从其他参考资料中得到了这个工作。虽然不显示所有端口。我一直在玩各种 WMI 示例,但它们要么显示与此相同,要么需要提升(即使这样我也无法让它们看到所有 COM 设备)
  • 您的代码似乎有误,因为它只显示一个设备。您需要在重复循环之外使用您的 try..finally 部分,因为在第一次显示设备后 SetupDiDestroyDeviceInfoList(hdev) 将破坏 hdev 并且下一次调用 SetupDiEnumDeviceInterfaces(hdev, nil, GUID_DEVINTERFACE_COMPORT, idev, did) 将返回错误(6 - 无效句柄)。
  • @AntonBazhal,谢谢。我刚刚编辑了代码,移动了 try finally 块。
【解决方案2】:

您可以使用 HKEY_LOCAL_MACHINE \HARDWARE\DEVICEMAP\SERIALCOMM 作为 COMxx 样式的短名称。请记住指定只读访问权限以避免管理员权限/ UAC 必要性。您可以看到 usb232 适配器和真实的通讯端口。

您也可以检查 HKEY_LOCAL_MACHINE \SYSTEM\CurrentControlSet\Enum\Root\PORTS,但这似乎有点棘手。

【讨论】:

    猜你喜欢
    • 2019-04-03
    • 2012-08-09
    • 1970-01-01
    • 2013-03-29
    • 2021-01-28
    • 2015-11-10
    • 1970-01-01
    • 2014-10-10
    • 1970-01-01
    相关资源
    最近更新 更多