Имя или идентификация последовательных (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, но это кажется немного сложным.