Способ 1: «Диспетчер устройств»
Для просмотра оборудования на компьютерах с Windows традиционно используется оснастка «Диспетчер устройств», однако в случае с COM-портами все нет так просто. Сегодня этот интерфейс считается устаревшим, поэтому в списке оборудования «Диспетчера устройств» он может не отображаться даже при включении опции «Показать скрытые устройства».
- Откройте «Диспетчер устройств» из контекстного меню кнопки «Пуск».
- Посмотрите, имеется ли списке оснастки раздел «Порты (COM и LPT)». Если да, раскройте его – оно будет содержать список имеющихся на компьютере портов с интерфейсами COM и LPT. Если указанный раздел отсутствует, проследуйте дальнейшим указаниям.
- В меню «Действие» открытого «Диспетчера устройств» выберите опцию «Установить старое устройство».
В случае отсутствия опции правой кнопкой мыши кликните тут же в окне оснастки по названию компьютера и выберите «Обновить конфигурацию оборудования». Теперь опция «Установить старое устройство» должна стать доступной. Кликните по ней.
- В открывшемся окне мастера оборудования нажмите «Далее».
- В следующем окне выберите вариант «Установка оборудования, выбранного вручную» и нажмите «Далее».
- В следующем окне в правой части выберите «Стандартные порты», а в левой – «Последовательный порт». Нажмите «Далее».
- Еще раз нажмите «Далее».
- По завершении этих действий в «Диспетчере устройств» должен появиться раздел «Порты (COM и LPT)». Если он не появится сразу, перезапустите оснастку или обновите конфигурацию оборудования, воспользовавшись одноименной опцией в меню «Действие».
Способ 2: «Редактор реестра»
Информация о доступных физических и виртуальных COM-портах хранится в системном реестре, откуда ее можно извлечь средствами самой операционной системы.
- Откройте «Редактор реестра» командой
regedit
, выполненной в вызванной нажатием клавиш Win + R диалоговом окошке быстрого запуска приложений. - Перейдите в раздел реестра
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
и изучите содержимое правой колонки. Доступные COM-порты будут указаны в виде строковых параметров со значениями «COM1», «COM2», «COM3» и так далее.
Следует отметить, что использование COM-портов в современных версиях Windows не столь актуально, как раньше. Они могут понадобится только для подключения специального оборудования, например старых моделей промышленных контроллеров. Маловероятно, что обычному пользователю когда-либо придется иметь дело с подобной аппаратурой.
Наша группа в TelegramПолезные советы и помощь
При программировании COM портов полезно иметь возможность получать список доступных портов на компьютере. Эта задача встречается настолько часто, что я решил затронуть ее в своем блоге.
Существует несколько различных способов решения этой задачи. Их все можно условно разделить на «некрасивые» и «красивые».
«Некрасивые» решения
Первый вариант заключается в том, чтобы зашить в программу самые распространенные номера портов (обычно COM1, COM2, COM3 и некоторые другие). Недостатком этого подхода является то, что вы не всегда можете охватить все доступные порты. Например, я видел системы, на которых встречается порты COM22, COM23, COM24 (порты были виртуальными, но суть вопроса это не меняет). Не будете же вы зашивать столько номеров. А если завтра встретится COM100?
Второй вариант заключается в проверке большого количества портов на их доступность. Мы просматриваем порты COM1, COM2, ….., COM100 и пытаемся открыть каждый из них. Если это удалось, значит, порт есть. У этого подхода несколько недостатков.
Во-первых, такой перебор занимает время, а регулярные вызовы функции CreateFile напрасно расходуют системные ресурсы.
Во-вторых, у данного метода возможны ложные срабатывания. Предположим, пользователь запустил программу, которая заняла порт COM3. После этого он запустил вашу программу. Разумеется, при попытке открыть порт COM3 возникнет ошибка, так как он занят другой программой. В результате чего программа решит, что такого порта нет. А он есть.
В-третьих, он не решает проблему охвата всего многообразия возможных портов.
«Красивое» решение
Красивое решение основывается на том факте, что информация о доступных COM портах (в том числе виртуальных) в системах Windows хранится в реестре. Точнее в ветке HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM\. Там COM порты хранятся в виде строк: «COM1», «COM2», «COM3» и т.д. Отсюда сразу возникает решение – нужно перебрать все строковые параметры в данном разделе реестра.
Ниже приводится полный исходный код примера, демонстрирующего данный метод.
#include <windows.h> #include <tchar.h> void ShowCOMPorts() { int r = 0; HKEY hkey = NULL; //Открываем раздел реестра, в котором хранится иинформация о COM портах r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM\\"), 0, KEY_READ, &hkey); if (r != ERROR_SUCCESS) return; unsigned long CountValues = 0, MaxValueNameLen = 0, MaxValueLen = 0; //Получаем информацию об открытом разделе реестра RegQueryInfoKey(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &CountValues, &MaxValueNameLen, &MaxValueLen, NULL, NULL); ++MaxValueNameLen; //Выделяем память TCHAR *bufferName = NULL, *bufferData = NULL; bufferName = (TCHAR*)malloc(MaxValueNameLen * sizeof(TCHAR)); if (!bufferName) { RegCloseKey(hkey); return; } bufferData = (TCHAR*)malloc((MaxValueLen + 1)*sizeof(TCHAR)); if (!bufferData) { free(bufferName); RegCloseKey(hkey); return; } unsigned long NameLen, type, DataLen; //Цикл перебора параметров раздела реестра for (unsigned int i = 0; i < CountValues; i++) { NameLen = MaxValueNameLen; DataLen = MaxValueLen; r = RegEnumValue(hkey, i, bufferName, &NameLen, NULL, &type, (LPBYTE)bufferData, &DataLen); if ((r != ERROR_SUCCESS) || (type != REG_SZ)) continue; _tprintf(TEXT("%s\n"), bufferData); } //Освобождаем память free(bufferName); free(bufferData); //Закрываем раздел реестра RegCloseKey(hkey); } int main() { ShowCOMPorts(); return 0; }
В заключение лишь отмечу, что я использую этот подход во многих своих проектах, и он еще ни разу не подводил меня.
Example
Getting all serial ports information from Windows is often necessary, you may want to give the user a choice of ports to open, or check if your device is connected.
In addition, some ports just cannot be opened using a «COMx» string and need to be opened using a device name. Some older versions of Windows cannot open ports named ‘COMxx’ when the port number is 10 or higher. So, using the device number is a sensible way to identify your com port with Windows.
Serial port information is held in the registry under the key HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
This example in C shows how to list all the serial ports and how one can get to the device name to use for the call to CreateFile.
The method is quite simple:
- Open the registry at
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
- Enumerate all keys we find there. The device name is the key name, and the ‘display name’ is the key value.
As is often the case with Windows programming, most of the effort is spent on error checking. It may seem a bit silly, but there’s no safe way to avoid it.
#define WIN32_LEAN_AND_MEAN // excludes stuff frokm windows.h that we won't need here.
#include <Windows.h>
#include <string.h>
#include <tchar.h>
#include <malloc.h>
void ShowErrorFromLStatus(LSTATUS lResult)
{
LPTSTR psz;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
lResult,
0,
(LPTSTR)&psz,
1024,
NULL);
_tprintf(_T("Windows reports error: (0x%08X): %s\n"), lResult, (psz) ? psz : _T("(null)"));
if (psz)
{
LocalFree(psz);
}
}
int main()
{
DWORD nValues, nMaxValueNameLen, nMaxValueLen;
HKEY hKey = NULL;
LPTSTR szDeviceName = NULL;
LPTSTR szFriendlyName = NULL;
DWORD dwType = 0;
DWORD nValueNameLen = 0;
DWORD nValueLen = 0;
DWORD dwIndex = 0;
LSTATUS lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ, &hKey);
if (ERROR_SUCCESS != lResult)
{
printf("Failed to open key \'HARDWARE\\DEVICEMAP\\SERIALCOMM\' \n");
ShowErrorFromLStatus(lResult);
return 1;
}
lResult = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
&nValues, &nMaxValueNameLen, &nMaxValueLen, NULL, NULL);
if (ERROR_SUCCESS != lResult)
{
_tprintf(_T("Failed to RegQueryInfoKey()\n"));
ShowErrorFromLStatus(lResult);
RegCloseKey(hKey);
return 2;
}
szDeviceName = (LPTSTR)malloc(nMaxValueNameLen + sizeof(TCHAR));
if (!szDeviceName)
{
_tprintf(_T("malloc() fail\n"));
RegCloseKey(hKey);
return 3;
}
szFriendlyName = (LPTSTR)malloc(nMaxValueLen + sizeof(TCHAR));
if (!szFriendlyName)
{
free(szDeviceName);
_tprintf(_T("malloc() fail\n"));
RegCloseKey(hKey);
return 3;
}
_tprintf(_T("Found %d serial device(s) registered with PnP and active or available at the moment.\n"), nValues);
for (DWORD dwIndex = 0; dwIndex < nValues; ++dwIndex)
{
dwType = 0;
nValueNameLen = nMaxValueNameLen + sizeof(TCHAR);
nValueLen = nMaxValueLen + sizeof(TCHAR);
lResult = RegEnumValueW(hKey, dwIndex,
szDeviceName, &nValueNameLen,
NULL, &dwType,
(LPBYTE)szFriendlyName, &nValueLen);
if (ERROR_SUCCESS != lResult || REG_SZ != dwType)
{
_tprintf(_T("SerialPortEnumerator::Init() : can't process registry value, index: %d\n"), dwIndex);
ShowErrorFromLStatus(lResult);
continue;
}
_tprintf(_T("Found port \'%s\': Device name for CreateFile(): \'\\.%s\'\n"), szFriendlyName, szDeviceName);
}
free(szDeviceName);
free(szFriendlyName);
RegCloseKey(hKey);
return 0;
}
Program output on my laptop:
Found 1 serial device(s) registered with PnP and active or available at the moment.
Found port 'COM23': Device name for CreateFile(): '\.\Device\BthModem0'
Когда вы подключаете к компьютеру новое COM или некоторые USB устройства (например, USB модем, мобильный телефон, Bluetooth адаптер, конвертеров последовательных портов в USB и т.п.), Windows определяет его через механизм Plug-n-Play и назначит ему номер COM порта в диапазоне от 1 до 255 (COM1, COM2, COM3 и т.д.). При повторном подключении этого же устройств, ему назначается номер COM порта (Communication Port, или Serial port), зарезервированный за ним ранее. Новым устройствам выдается первый незанятый номер COM порта. Не редкость, когда внешние устройства при подключении создают сразу несколько COM портов (в моем случае после подключения адаптера Bluetooth, в системе появилось сразу 10
!!!!
новых COM портов).
Ряд приложений (как правило, довольно древних), способны адресовать только двухзначные номера COM портов, и отказываются работать с COM100 и выше. Или видят только COM1-COM9 устройства. Что делать, если подключенное устройство получило высокий номер COM порта? Можно ли сбросить нумерацию для зарезервированных COM портов и удалить назначенные порты?
Содержание:
- Изменить номер COM порта устройства в Windows
- Определяем процесс, который использует COM в Windows
- Сброс назначенных COM портов Windows через реестр
Изменить номер COM порта устройства в Windows
В Windows можно вручную изменить номер COM порта, назначенный устройству. Предположим требуемый COM порт уже занят, и мы хотим его попробовать его освободить. Для этого:
- Откройте диспетчер устройств (Device Manager) командой devmgmt.msc;
- В меню выберите View->Show Hidden Devices;
- Затем разверните Ports (COM & LPT) и найдите в списке устройство;
- Перейдите на вкладку Port Settings и нажмите кнопку Advanced;
- Текущий номер COM порта, назначенный устройству указан в поле COM Port Number;
- Чтобы изменить его, раскройте выпадающий список и выберите номер COMпорта, который хотите задать.
Но чаще всего изменить номер COM порт на другой не получится, так как все «низкие» COM порт уже используются (in use);
- В этом случае нужно попробовать удалить резервацию COM порта за другим устройством. В ветке Ports (COM & LPT) найдите которому назначен нужный вам номер COM порта (бледная иконка означает, что данный COM порт назначен, но в сейчас это устройство не подключено);
- Щелкните по нему ПКМ и выберите Uninstall;
- Теперь вы можете назначить освобожденный COM порт другому устройству. Еще раз откройте свойства вашего устройство, перейдите на вкладку Port Settings -> Advanced. Задайте свободный номер COM порта для вашего устройства.
Однако такой способ позволяет освободить занятый COM порт не во всех случаях.
Вы можете вывести полный список занятых COM портов в Windows с помощью PowerShell:
Get-WMIObject Win32_SerialPort | Select-Object Name,DeviceID,Description
Можно определить номер COM порта для определённого устройства по его имени, например:
Get-WMIObject Win32_SerialPort | Where-Object { $_.Name -like "*Arduino*"}|select name, deviceid
Или
Get-WMIObject Win32_SerialPort | Where-Object { $_.Name -like "*GPS*"}|select name, deviceid
Определяем процесс, который использует COM в Windows
Вы не сможете освободить COM порт устройства, которое используется Windows или запущенной программой, процессом. Сначала вам нужно завершить процесс/программу, которая использует сейчас COM порт. Чтобы определить имя процесса, который использует COM порт понадобится утилита Process Explorer (https://docs.microsoft.com/en-gb/sysinternals/downloads/process-explorer).
Сначала нужно вывести имя службы, которая использует COM порт. Выполните команду PowerShell:
get-pnpdevice -class Ports -ea 0| Select Name, PNPDeviceID, Status, Service
Имя службы данного COM порта указано в столбце Service. Например, для COM2 это Serial. Теперь нужно запустить Process Explorer с правами администратора и выбрать в меню Find -> Find Handle or DLL. В строке Hangde or DLL substring введите значение Service, полученное ранее. В нашем примере это
Serial
.
Process Explorer должен показать процесс, который использует сейчас ваш COM порт. Чтобы освободить COM порт, завершите процесс или программу.
Сброс назначенных COM портов Windows через реестр
Информация об используемых COM портах хранится в ключе реестра CommDB в разделе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\COM Name Arbiter
- Откройте редактор реестра (regedit.exe) и перейдите в указанную ветку.
Важно! Настоятельно рекомендуем предварительно создать резервную копию данной ветки реестра (File -> Export). В том случае, если что-то пойдет не так, вы сможете вернуться к первоначальной конфигурации COM портов.
- Значение параметра ComDB в двоичном формате определяет список COM портов, зарезервированных в системе. Каждый бит определяет состояние соответствующего порта (от 1 до 255). К примеру, если нам нужно оставить резервацию только для COM3, hex значение ComDB будет равно 04 (0000 0100);
Важно! Будьте предельно внимательными, ни в коем случае не добавьте в этот параметр дополнительные байт, иначе система может начать падать в BSOD.
- Если нужно полностью сбросить все привязки COM, измените значение ключа ComDB на 0.
Примечание. В разделе HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM можно увидеть полный список COM портов, доступных в Windows.В разделе HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM можно увидеться список COM портов, подключенных к системе.
- В ветке HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports содержится список назначенных COM портов. Все ненужные порты можно удалить (в нашем примере мы оставим только COM3 и удалим остальные);
- Отключите все оборудование и перезагрузите Windows;
- После перезагрузки включите оборудование в нужном порядке (переустановите конверторы USB-to-serial и т.д.). Все обнаруженные COM-порты автоматически определяться системой и им будут последовательно выделены номера COM портов.
Также вы можете использовать следующие две бесплатные утилиты для очистки занятых (In Use) COM портов:
- COM Name Arbiter Tool – утилита для освобождения занятых COM портов. Запустите утилиту с правами администратора, выберите COM порты, которые вы хотите освободить и нажмите Clear unused Reservations и Remove non-present devices;
- Device Cleanup Tool – утилита используется для поиска в реестре информации о ранее подключенных устройств (в ветке HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum) и удаления неиспользуемых устройств и очистки резерваций COM портов.
Стало любопытно как в Винде правильно получить список последовательных портов.
Из интернетов удалось узнать что способов горсть и один хуже другого. Поясню что необходим только список портов, без каких-либо описаний.
upd: склоняюсь к чтению портов из реестра ибо на msdn.microsoft пишут такое:
Используйте метод GetPortNames для запроса списка допустимых имен последовательных портов на текущем компьютере. Например, этот метод позволяет определить, являются ли COM1 и COM2 допустимыми последовательными портами для текущего компьютера.
Имена порта загружаются из системного реестра (например, HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM). Если данные в реестре неточны или устарели, метод GetPortNames возвратит неверные результаты.
upd2: Второй по приоритету способ — это запрос WMI
-
Вопрос задан
-
4984 просмотра
Пригласить эксперта
Самый надежный способ, который не только находит порты, но и определяет их занятость — прямой перебор всех 255 вариантов имен.
-
Показать ещё
Загружается…