Delphi 串行(COM)端口名称或标识

Delphi 串行(COM)端口名称或标识,delphi,Delphi,我有一个使用cport访问多个串行端口的程序 为了进行配置,到目前为止,我只是在一个组合框中列出了所有可用的组件以进行选择,但是越来越多的具有(虚拟)串行接口的驱动程序使得为最终用户进行配置变得很麻烦 当前检测使用createfile(),但存在的问题是,您只能获取exists/nonexists和可能的“busy”信息 然而,为了提高性能,我需要每个COM端口都有一个标识字符串,比如它所连接的硬件设备/驱动程序(设备管理器)。这将使用户更容易缩小组件范围(因为我们提供的串行卡数量有限) 也许它

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

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

当前检测使用createfile(),但存在的问题是,您只能获取exists/nonexists和可能的“busy”信息

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

也许它可以从WMI获得,但这是一个相当复杂的问题,sb是否有更具体的信息,或者更好的代码


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

如果要枚举COM端口以获得友好的名称,可以使用
SetupAPI
和设备接口类

试试这个样品

{$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.
{$APPTYPE控制台}
{$R*.res}
使用
窗户,
SysUtils,
JvSetupApi;
常数
GUID_deviceinterface_COMPORT:TGUID='{86E0D1E0-8089-11D0-9CE4-08003E301F73}';
程序组件;
变量
要求:德沃德;
hdev:HDEVINFO;
idev:整数;
did:TSPDeviceInterfaceData;
pdidd:PSPDeviceInterfaceDetailData;
PropertyBuffer:字符的数组[0..255];
DeviceInfo数据:TSPDevInfo数据;
PropertyRegDataType:DWORD;
所需尺寸:DWORD;
开始
//枚举com端口
hdev:=SetupDiGetClassDevs(@GUID\u DEVICEINTERFACE\u COMPORT,nil,0,DIGCF\u PRESENT或DIGCF\u DEVICEINTERFACE);
如果(无效的句柄值THandle(hdev)),则
开始
尝试
idev:=0;
零内存(@did,SizeOf(did));
did.cbSize:=SizeOf(did);
重复
如果(setupDienumDeviceInterface(hdev,nil,GUID\u deviceInterface\u COMPORT,idev,did))那么
开始
cbRequired:=0;
SetupDiGetDeviceInterfaceDetail(hdev、@did、nil、0、cbRequired、nil);
如果(错误\u不足\u缓冲区=GetLastError()),则
开始
pdidd:=AllocMem(需要C);
尝试
pdidd.cbSize:=SizeOf(TSPDeviceInterfaceDetailData);
DeviceInfo.cbSize:=SizeOf(DeviceInfo数据);
所需大小:=0;
如果(SetupDiGetDeviceInterfaceDetail(hdev、@did、pdidd、cbRequired、RequiredSize、@DeviceInfo数据)),则
开始
PropertyRegDataType:=0;
所需大小:=0;
如果SetupDiGetDeviceRegistrProperty(hdev、DeviceInfo数据、SPDRP_FRIENDLYNAME、PropertyRegDataType、PBYTE(@PropertyBuffer[0])、SizeOf(PropertyBuffer)、RequiredSize),则
Writeln(格式('Friendly Name-%s',[PropertyBuffer]);
如果SetupDiGetDeviceRegistrProperty(hdev、DeviceInfo数据、SPDRP_DEVICEDESC、PropertyRegDataType、PBYTE(@PropertyBuffer[0])、SizeOf(PropertyBuffer)、RequiredSize),则
Writeln(格式('Description-%s',[PropertyBuffer]);
如果SetupDiGetDeviceRegistrProperty(hdev、DeviceInfo数据、SPDRP_位置_信息、PropertyRegDataType、PBYTE(@PropertyBuffer[0])、SizeOf(PropertyBuffer)、RequiredSize),则
Writeln(格式('Location-%s',[PropertyBuffer]);
结束
其他的
赖斯·塞罗;
最后
FreeMem(pdidd);
结束;
结束;
结束
其他的
打破
公司(idev),;
直到错误;
最后
SetupDiDestroyDeviceInfo列表(hdev);
结束;
结束;
结束;
开始
尝试
如果未加载设置API,则退出;
列举成分;
除了
关于E:Exception-do
Writeln(E.ClassName,“:”,E.Message);
结束;
readln;
结束。
这将返回类似的结果


注意:
JvSetupApi
单元是JVCL库的一部分。

对于COMxx样式的短名称,您可以使用HKEY\U LOCAL\U MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM。请记住指定只读访问以避免管理员权限/UAC的必要性。您可以看到usb232适配器和真正的通信端口


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

可能与以下内容重复:…有一些绝地等组件在高级别上提供此功能,但是,如果你想推出自己的产品,我认为WMI或注册表是你唯一的求助手段。你正在寻找的可能是枚举com端口的方法,包括它们的“友好名称”?关于可能重复的答案不是很好,基于注册表的方法是有缺陷的。“J:似乎上面文章中的WMI代码需要提升,这使得“无设置”有点困难。此外,它不能找到所有端口。而且它没有显示友好的名称。不过还是要感谢你的提示,这至少是一个开始。是的,从其他参考资料中也可以看出这一点。但并不显示所有端口。我一直在玩各种WMI示例,但它们要么显示与此相同,要么需要提升(即使这样,我也无法让它们看到所有COM设备)。您的代码似乎有错误,因为它只显示一个设备。您需要您的
try..finally
部分在重复循环之外,因为在第一次显示设备
setupDiDestroyDeviceInfo列表(hdev)
后,设备将销毁
hdev
,下一次调用
setupDienumDeviceInterface(hdev,nil,GUID\u deviceInterface\u COMPORT,idev,did)
将返回错误(6-无效句柄)。@Antonbazal,谢谢我刚刚编辑了代码,移动了try finally块。