Как получить список com портов в windows

Обновлено: 04.07.2024

Как мне просмотреть список используемых COM-портов без использования диспетчера устройств ?

Я также не хочу устанавливать какое-либо программное обеспечение. Есть ли способ сделать это через командную строку?

Пожалуйста, лучше определите «Используется». установлено как устройство? К нему подключено устройство? Активно ли передаются данные? @ Ƭᴇcʜιᴇ007 извините, при использовании было бы подключено к нему устройство. У меня есть кабель TTL UART подключен к USB. Я полагаю, вы можете сделать это с помощью сценария PowerShell. Почему вы не можете использовать диспетчер устройств? Ваше нежелание использовать что-то вроде Putty странно. @Ramhound Использование университетского ПК с заблокированным диспетчером устройств, чтобы люди, подобные мне, не играли. Я вижу, что устройство COM3 на моем ноутбуке. Я хочу использовать Putty, но не знаю, какой COM-порт использовать. @Marmstrong В командной строке используйте mode . При использовании без параметров mode отображаются все управляемые атрибуты CON (консоли) и доступных COM устройств (и LPT также)

В командной строке используйте

Используется без параметров, mode отображает все контролируемые атрибуты CON (консоли) и доступных COM устройств ( LPT а также).

Принимает /? переключатель для базовой помощи:

Используя mode большую часть времени я не вижу устройств, которые не связаны, как указано в ответе @GM «s.

В командной строке используйте:

Надеюсь это поможет.

Если устройства Com-порта не обнаружены, выдается команда «Экземпляры недоступны». Проверьте свой «Диспетчер устройств» и убедитесь, что ваша машина обнаружила Com-порты в «Диспетчере устройств» ОП сказал: «Использование университетского ПК, на котором заблокирован диспетчер устройств» @vembutech - Похоже, вам нужно будет привлечь ИТ в этом случае. @vembutech Я проверил устройство на своем ноутбуке, и оно отображается как COM3 в диспетчере устройств, но командная строка все еще показывает тот же результат.

Я знаю, что на вопрос ответили, но это другой метод.

В командной строке используйте:
chgport
в Windows Vista и выше. Перечисляет ваши порты и какое устройство они.

Windows 7 «chgport» не распознается как внутренняя или внешняя команда, работающая программа или командный файл ». У меня работает chgport / QUERY в Win7 pro. В нем перечислено имя \ Device \ для текущего выбранного com-порта, а не полный список. Дальше интереснее, chgport /? показывает: (форматирование не выполняется) CHANGE PORT [portx = porty | / D portx | / QUERY] portx = porty Подключить порт x к порту y. / D portx Удалить сопоставление для порта x. / QUERY Показать текущие порты отображения. И chgport COM4 = COM5 позволяет типу COM4: работать!

Используя mode большую часть времени я не вижу устройств, которые не связаны между собой .

Я предпочитаю использовать это решение с Python:

Таким образом, я вижу все, что подключено, даже если соединение закрыто.

serial.tools.list_ports из пакета pyserial .

Если ваш последовательный порт виртуально создан каким-либо драйвером через USB-соединение, используйте этот пример для получения подробной информации об этих последовательных портах.

это производит много информации. get Name вместо того, get /value чтобы помочь. К сожалению, это будет не просто список портов, а такие строки, как «Последовательный порт USB (COM17)». Есть также несколько записей, упоминающих просто «USB Serial Converter» на моей установке.

Вы также можете запустить следующее из командной строки cmd.exe

Фрагмент ниже перечисляет последовательные порты в переменную $ PORTS

echo -n "Программирование (отображение) портов:" для aa в $ PORTS; do echo -n $ aa done echo ""

При программировании COM портов полезно иметь возможность получать список доступных портов на компьютере. Эта задача встречается настолько часто, что я решил затронуть ее в своем блоге.

Существует несколько различных способов решения этой задачи. Их все можно условно разделить на «некрасивые» и «красивые».

«Некрасивые» решения

Первый вариант заключается в том, чтобы зашить в программу самые распространенные номера портов (обычно COM 1, COM 2, COM 3 и некоторые другие). Недостатком этого подхода является то, что вы не всегда можете охватить все доступные порты. Например, я видел системы, на которых встречается порты COM 22, COM 23, COM 24 (порты были виртуальными, но суть вопроса это не меняет). Не будете же вы зашивать столько номеров. А если завтра встретится COM 100?

Второй вариант заключается в проверке большого количества портов на их доступность. Мы просматриваем порты COM 1, COM 2, …. COM 100 и пытаемся открыть каждый из них. Если это удалось, значит, порт есть. У этого подхода несколько недостатков.

Во-первых, такой перебор занимает время, а регулярные вызовы функции CreateFile напрасно расходуют системные ресурсы.

Во-вторых, у данного метода возможны ложные срабатывания. Предположим, пользователь запустил программу, которая заняла порт COM 3. После этого он запустил вашу программу. Разумеется, при попытке открыть порт COM 3 возникнет ошибка, так как он занят другой программой. В результате чего программа решит, что такого порта нет. А он есть.

В-третьих, он не решает проблему охвата всего многообразия возможных портов.

«Красивое» решение

Красивое решение основывается на том факте, что информация о доступных COM портах (в том числе виртуальных) в системах Windows хранится в реестре. Точнее в ветке HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM\. Там COM порты хранятся в виде строк: « COM 1», « COM 2», « COM 3» и т.д. Отсюда сразу возникает решение – нужно перебрать все строковые параметры в данном разделе реестра.

Ниже приводится полный исходный код примера, демонстрирующего данный метод.

В заключение лишь отмечу, что я использую этот подход во многих своих проектах, и он еще ни разу не подводил меня.

Правильное получение списка COM-портов в Delphi

Задачи работы с железом – частая штука для Delphi разработчиков. Но если почти все знают, как работать с COM-портом – открывать его, отправлять и принимать данные, то практически нигде не описан наиболее корректный вариант получения списка портов. Давайте, для начала рассмотрим несколько наиболее часто встречаемые в интернете варианты и попробуем разобраться в них.

Прежде всего определимся, что среди COM-портов в Windows есть 2 типа устройств – непосредственно COM-порты и модемы:


Их следует разделять, например, когда надо автоматически подключится к какому-то определённому устройству или не выводить модемы. Поэтому было бы неплохо получить не просто список, но и типы устройств и их имена.

Вариант 1. Опрос всех портов по очереди

Решение «в лоб», что называется. Давайте будем открывать по очереди список COM-порты, а какие откроются – выведем в списке. Выглядит как-то так:

Честно говоря, вариант хреноватенький. Из плюсов – разве что очевидная реализация и возможность получить список COM-портов без прав администратора. Минусов тут огромнейшее множество:

  • У пользователя может быть, к примеру, виртуальный порт COM158, следовательно циклом в 32 порта не ограничишься, а опрос большого количества портов занимает немало времени.
  • Всякие «левые» устройства – виртуальные Bluetooth порты (которые встречаются в каждом втором ноутбуке) и прочее железо может неадекватно реагировать на открытие порта – вплоть до зависания системы.
  • Нельзя определить имя устройства в системе и тип устройства (порт или модем)

Как показывает практика (да и здравый смысл тоже), процент зависаний и отказов для такого варианта довольно велик. Так что для коммерческой программы такой вариант вовсе не подойдёт, хотя процент коммерческих программ, опрашивающих таким способом железо, довольно велико.

Вариант 2. Чтение списка из реестра

Оказывается, в ветке HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM хранится список активных портов системы. Можно их просто прочитать и всё будет ок.

Кстати, данный вариант пользуется большой популярностью. Причина тому одна – он быстрый и работал (во времена Windows XP) практически безотказно. Однако и у него есть минусы:

  • Во времена Windows XP всё работало безотказно, но поскольку ветка HKEY_LOCAL_MACHINE в Windows Vista, Windows 7 и Windows 8 закрыта для не-админа (не для пользователей группы «Администраторы», а для пользователя аналога root в Linux), то программу приходится запускать от имени администратора. Можно, конечно, добавить manifest, что решит 99% проблем, но останется тот 1% (например, home-версия Windows) и неприятный осадок.
  • Нельзя определить имя устройства в системе и тип устройства (порт или модем)

Данный вариант вполне приемлемый для коммерческого решения, однако есть приёмчики получше.

Вариант 3. Правильный. Используем Windows Driver Kit

Наиболее сложный, но и наиболее правильный вариант.

Вызываем следующим образом:

Плюс ко всему, необходим pas-файл для библиотеки SETUPAPI.dll

Плюсы очевидны – работает быстро, стабильно, мы получаем всю необходимую информацию об устройстве, не требует прав администратора.

Минус единственный – для новичка непонятен код.

Выводы

Лично я рекомендую последний метод как единственный правильный, однако у вас может быть своё мнение – высказывайте его в комментариях.

Комментарии

Не буду повторно писать свой комментарий, злая капча. @Юрий Галин
У тебя же есть аккаунт. Залогинься и забудь о капче.

@Oleg
Заголовочную библиотеку можно загуглить по названию любой функции.

На днях скину рабочий пример.

Метод 1, однозначно, неприемлем.

Успешно пользуюсь методом 2 под Vista+ x64 без прав администратора. Просто ключ нужно открывать только на чтение (reg.OpenKeyReadOnly)

Метод 3, насколько я понимаю, чуть более продвинут, чем метод 2, т.к. тоже получает данные из реестра, только из других ключей.

Было бы интересно почитать как определить свободен ли COM-порт (с этим вроде как понятно) и, если занят, то каким приложением (это уже интересно).

@Андрей
Я долгое время пользовался методов 2, пока не встретился с нюансами во всяких Home версиях. Главные плюсы метода 3 - он работает безукоризненно и даёт более информативную картину.

Process Explorer показывает открытые файлы (а значит и COM-порты) и их хендлы. Можно покопать в его сторону или поискать решение на MSDN.

А что такое TPortClass и TComPortInfo? Самописные какие-то классы? В сети нет упоминания о таких. И, кстати, под XE5 не компилируется, ругается на несовпадение типов h и значения ф-ции SetupDiGetClassDevs, а также на неверный тип devinfo : SP_DEVICE_INTERFACE_DATA; который он хочет как SP_DEVINFO_DATA. Может, нужен какой-то особенный SetupApi.pas? При попытке компиляции из D2007 получил следующие ошибки:
E2010 Incompatible types: 'Cardinal' and 'Pointer' - строка 26
E2010 Incompatible types: 'Pointer' and 'Cardinal' - строка 42
E2033 Types of actual and formal var parameters must be identical - строка 42
E2010 Incompatible types: 'Pointer' and 'Cardinal' - строка 49
E2010 Incompatible types: 'Pointer' and 'Cardinal' - строка 78
E2010 Incompatible types: 'PByte' and 'Array' - строка 78
E2010 Incompatible types: 'Pointer' and 'Cardinal' - строка 94

@Станислав
Да, класы самописные. На днях вырежу из готового проекта небольшой пример и закину исходник.

SetupApi тоже закину.

Извините, а можно рабочий пример?
вроде как уже месяц прошел ) Добрый день!
Выложите пример реализации вашего функционала! Есть задача, а ваш пример её решает как нельзя лучше !
Заранее благодарен !

Пришлось писать самому (не без помощи данность статьи,конечно)

Выложу, может кому еще надо:
Получилось примерно так:

// Юнит с нашими функциями
unit detectmodems;

uses
Windows, SysUtils, Forms, SETUPAPI;

type
TGUIDDeviceInfo = record
name: string;
portname: string;
portnumber: integer;
end;

TDevices = array of TGUIDDeviceInfo;

function GetGUIDdevice ():TDevices;

function GetGUIDdevice ():TDevices;
var
Guid : TGUID;
PnPHandle: HDevInfo;
DeviceInfoData : SP_DEVINFO_DATA;
DeviceInterfaceData: SP_DEVICE_INTERFACE_DATA;
i : Cardinal;
Success: LongBool;
DataT, buffersize: Cardinal;
buffer : PByte;
//
hDeviceKey : HKEY;

szData : array[0..255]of Char;
dwType,dwSize : DWORD;
//


PnPHandle:= SetupDiGetClassDevs(@Guid, nil, 0, DIGCF_PRESENT);


Try
i:= 0;
DeviceInfoData.cbSize:= SizeOf(SP_DEVINFO_DATA);
DeviceInterfaceData.cbSize := SizeOf(SP_DEVICE_INTERFACE_DATA);
Repeat
Success:= SetupDiEnumDeviceInfo(PnPHandle, i, DeviceInfoData);

If Success then
begin
buffer:= nil;
buffersize:= 0;

while not SetupDiGetDeviceRegistryProperty(PnPHandle,DeviceInfoData,SPDRP_DEVICEDESC,@DataT,buffer,buffersize,@buffersize)
do begin
if (GetLastError() = ERROR_INSUFFICIENT_BUFFER) then
begin
if (buffer <> nil) then FreeMem(buffer);
buffer:= AllocMem(buffersize);
end
else
begin
break;
end;
end;

//ListBox1.Items.Add(Format('%d: %s',[i, StrPas(PChar(buffer))]));
SetLength(Result,i+1);
Result[i].name:=StrPas(PChar(buffer));
if (buffer <> nil) then FreeMem(buffer);
// Ïûòàåìñÿ íîìåð ïîðòà îïðåäåëèòü

hDeviceKey:=SetupDiOpenDevRegKey(PnPHandle,DeviceInfoData, DICS_FLAG_GLOBAL,0,DIREG_DEV,KEY_QUERY_VALUE);
if(hDeviceKey>0)then
begin

// Ïûòàåìñÿ íîìåð ïîðòà îïðåäåëèòü


End;
Inc(i);
Application.ProcessMessages;
until not Success;


Finally
SetupDiDestroyDeviceInfoList(PnPHandle);
End;
end;

Вызов примерно так:

procedure TMain.sBitBtn2Click(Sender: TObject);
var
mas:TDevices;
i:integer;
begin
mas:=GetGUIDdevice();

for i:=0 to Length(mas)-1 do
begin
sListBox1.Items.Add(intToStr(i+1)+' '+mas[i].name+' '+mas[i].portname+' '+IntToStr(mas[i].portnumber));
end;

@Сергей
Спасибо за поддержку .
Я так заработался, что совсем блог забросил. Хотелось бы увидеть TPortClass и TComPortInfo, для полноты картины! с нетерпением ждем TPortClass и TComPortInfo, а также SetupApi!
Модуль то найти можно для setupapi.dll, но они все имеют разные названия переменных и не все функции. Метод оказался неработоспособным в случаях, когда виртуальные COM-порты не отображаются в диспетчере задач.

@Константин
Вы, наверное, имели в виду диспетчер устройств?

Ни разу не видел, чтобы были COM-порты, которых нет в диспетчере устройств.

Да, диспетчер устройств, извиняюсь. А такое бывает. Впервые я столкнулся с таким при использовании преобразователя Ethernet - RS-485. Там ставится утилита, которая создает виртуальные COM-порты, но их не видно в диспетчере задач. Однако они есть и программное обеспечение с ними абсолютно нормально работает. Другой пример - программа Virtual Serial Port Emulator. Я её использую, как эмулятор нуль-модема. Она создает два виртуальных com-порта, и связывает их меж собой. Таким образом между собой общаются два приложения. Так вот, эти порты тоже не видны в диспетчере устройств. Кстати, первые два способа, озвученные Вами, эти порты определяют нормально.

@Констатнтин
Интересно, буду в курсе.

Третий способ - это и есть, по сути, то, что использует диспетчер устройств.

Весьма странно, что есть устройство, но его нет в диспетчере устройств.

Короче полезность материала без SetupApi.pas который использовал автор вызывает очень большие сомнения, по крайней мере у меня не заработало как бы я ни старался. По поводу кода, который опубликовал Сергей та же ситуация. Прошло столько времени с момента создания топика, а обещания выложить рабочий пример так и остались обещаниями. Так и не понял, почему в статье используется GUID_DEVICEINTERFACE_COMPORT, но при этом на скриншоте обведены устройства из класса ports, имеющего совсем другой GUID =

А если гаджет попал в другую категорию - смотрите GUID класса в диспетчере устройств на вкладке "Сведения".

Ну и касаясь темы статьи - не поминается ещё один способ, минус которого только в отсутствии названий найденных портов. Имеется в виду получение полного списка девайсов через QueryDosDevice и далее вычленение из него строк, начинающихся с COM.

Очень давно с дельфями не работал.
Поэтому приведу маленький пример на билдере, а там и переделать недолго.
Компилируется как в 32, так и в 64 бита.
Единственно что виндовс нужен версии от XP.
Примечателен тем, что крайне прост и находит абсолютно все порты, включая виртуальные не открывая их.

int coms[256]; // Список портов
int comcnt = 0; // Количество портов
int i=0;
int pos;
TCHAR devs[65535];

DWORD dwChars = QueryDosDevice(NULL, devs, 65535);
if(dwChars) while(devs[i]) UnicodeString str = &devs[i];
if((pos = str.Pos("COM"))) str.Delete(1, pos+2);
try coms[comcnt++] = StrToInt(str);
>catch(. )<>
>
while(devs[i++] != _T('\0'));
>
>

А вот пример основанный в том числе и на инфе отсюда, только тоже находит все порты включая виртуальные, для наглядности дополнительная инфа о порте сбрасывается в TMemo *m1;
m1 нужно добавить на форму, если хотите посмотреть что находит пример.
Это разумеется необязательно, и порты ищутся только те, что удовлетворяют неким дополнительным условиям, что тоже можно выключить, как и считывание лишних параметров.

static const UnicodeString DESC = L"Arduino Uno";
static const UnicodeString > static const UnicodeString SERV = L"usbser";
static const UnicodeString >
UnicodeString strPort;
UnicodeString strDesc;
UnicodeString strClass;
UnicodeString strServ;
UnicodeString strId;
UnicodeString strName;

int coms[256]; // Список портов
int comcnt = 0; // Количество портов
int pos;
bool succ;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA devinfo;
HKEY hKey;
Char bBuf[256];
DWORD dwSize;

if((hDevInfo = SetupDiGetClassDevs(NULL, NULL, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES)) != INVALID_HANDLE_VALUE) devinfo.cbSize = sizeof(devinfo);
try for(DWORD nDev = 0; SetupDiEnumDeviceInfo(hDevInfo, nDev, &devinfo); nDev++) if((hKey = SetupDiOpenDevRegKey(hDevInfo, &devinfo, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) bBuf[0] = L'\0';
dwSize = sizeof(bBuf);
if(!RegQueryValueEx(hKey, L"PortName", NULL, NULL, (LPBYTE)bBuf, &dwSize)) strPort = bBuf;
if((pos = strPort.Pos(L"COM"))) m1->Lines->Add(strPort);
strPort.Delete(1, pos+2);
bool ok = true;
if((succ = SetupDiGetDeviceRegistryProperty(hDevInfo, &devinfo, SPDRP_DEVICEDESC, NULL, (LPBYTE)bBuf, sizeof(bBuf), NULL))) strDesc = bBuf;
m1->Lines->Add(bBuf);
>
ok &= succ;
if((succ = SetupDiGetDeviceRegistryProperty(hDevInfo, &devinfo, SPDRP_FRIENDLYNAME, NULL, (LPBYTE)bBuf, sizeof(bBuf), NULL))) strName = bBuf;
m1->Lines->Add(bBuf);
>
if((succ = SetupDiGetDeviceRegistryProperty(hDevInfo, &devinfo, SPDRP_CLASS, NULL, (LPBYTE)bBuf, sizeof(bBuf), NULL))) strClass = bBuf;
m1->Lines->Add(bBuf);
>
ok &= succ;
if((succ = SetupDiGetDeviceRegistryProperty(hDevInfo, &devinfo, SPDRP_SERVICE, NULL, (LPBYTE)bBuf, sizeof(bBuf), NULL))) strServ = bBuf;
m1->Lines->Add(bBuf);
>
ok &= succ;
if((succ = SetupDiGetDeviceRegistryProperty(hDevInfo, &devinfo, SPDRP_HARDWAREID, NULL, (LPBYTE)bBuf, sizeof(bBuf), NULL))) strId = bBuf;
m1->Lines->Add(bBuf);
>
ok &= succ;
if(ok && strDesc == DESC && strClass == CLASS && strServ == SERV && strId == ID)
try coms[comcnt++] = StrToInt(strPort);
m1->Lines->Add(UnicodeString(L"Это наш порт № ") + coms[comcnt-1]);
>catch(. )<>
else
m1->Lines->Add(L"Это не наш порт");
m1->Lines->Add(L"");
>
RegCloseKey(hKey);
>
>
>
>__finally SetupDiDestroyDeviceInfoList(hDevInfo);
>
>

m1->Lines->Add(UnicodeString(L"Всего найдено наших портов: ") + comcnt);

Лень было оформлять в виде функций, так, что всё свалено в кучу, и глобальные с локальными переменными и собственно код.
Но там раскидать что куда недолго, зато ничего самописного и не приведённого в примере нет, есть всё необходимое для запуска, даже заголовочный файл.

Чё-то я зарапортовался, оставил кое-что лишнее в первом примере, так что он на самом деле ещё проще:

int coms[256]; // Список портов
int comcnt = 0; // Количество портов
int i=0;
TCHAR devs[65535];

Стало любопытно как в Винде правильно получить список последовательных портов.
Из интернетов удалось узнать что способов горсть и один хуже другого. Поясню что необходим только список портов, без каких-либо описаний.
upd: склоняюсь к чтению портов из реестра ибо на msdn.microsoft пишут такое:

Используйте метод GetPortNames для запроса списка допустимых имен последовательных портов на текущем компьютере. Например, этот метод позволяет определить, являются ли COM1 и COM2 допустимыми последовательными портами для текущего компьютера.
Имена порта загружаются из системного реестра (например, HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM). Если данные в реестре неточны или устарели, метод GetPortNames возвратит неверные результаты.

gbg

Самый надежный способ, который не только находит порты, но и определяет их занятость - прямой перебор всех 255 вариантов имен.

shpaker

Всмысле перебор? Открывать каждый порт и тут же закрывать? Дык на мой взгляд самый не оптимальный вариант.

gbg

A. Shpak: Да, открывать и закрывать. Вся процедура займет пару десятков миллисекунд. С WMI могут возникнуть определенные затруднения (больно много прав от пользователя требует, причем совсем неочевидных)

shpaker

Армянское Радио: ну дык теоретически некоторые устроиства при открытии соединения могут производить какие-либо действия. Имхо реестр практичнее.

gbg

A. Shpak: Никаких действий они не произведут, если с правильными флагами открывать и не трогать состояния управляющих линий.

Читайте также: