Страницы

Поиск по вопросам

суббота, 21 декабря 2019 г.

Изменить COM-порт устройства программно

#cpp #c #windows #cmd #com_порт


У меня подключено устройство (arduino), оно определяется и подключается к какому-нибудь
COM-порту. Номер порта можно изменить через Устройства и принтеры > свойства > изменить.
А возможно ли это сделать с помощью C/C++, или, на крайний случай, через консоль?
    


Ответы

Ответ 1



Как я вижу проблему (могу видеть её не полностью, так как лет двадцать уже не работал с железом на низком уровне): есть два варианта, через которые можно её решать: через Driver SDK или по принципу "нормальные герои всегда идут в обход". Driver SDK никогда не любил, хотя и приходилось, плюс это не интересно и не спортивно :) А вот запросить WMI, поковыряться в реестре и обновить ручками ComDB - гораздо интереснее: Лезем в реестр по адресу HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\COM Name Arbiter. Видим: Я даже не ожидал, что у меня в системе есть хотя бы один COM-порт. А он есть, и именно один. Каждый байт в параметре ComDB отвечает сразу за 8 портов (бит на каждый): "0101 1011" |||| ||||____ Com1 используется |||| |||_____ Com2 используется |||| ||______ Com3 не используется |||| |_______ Com4 используется ||||_________ Com5 используется |||__________ Com6 не используется ||___________ Com7 используется |____________ Com8 не используется Т.е. нам понадобится поменять нужные биты. Это раз. Ну, и второе: залезть в реестр по адресу HKLM:\SYSTEM\CurrentControlSet\Enum\, найти там наш девайс и перепривязать новый порт, меняя при это имя. Где-то в недрах моих архивов лежит почти готовое решение на Delphi. Если надо, постараюсь найти или написать заново, уж перевести на C++ труда не составит :) Ну, либо вот решение для консоли, а именно для powershell. В нём вроде бы всё понятно, можно сразу переводить на C++, я ещё не знаю, как в нём работать с битами. Проверить у себя не могу, т.к. нет ни одного устройства, которое бы работало с COM-портом, а злобная Windows 10 удаляет эмуляторы. $DeviceName = "My Arduino" $ComPort = "COM1" function Change-ComPort { Param ($Name,$NewPort) #Запрашиваем через WMI наш девайс $Query = 'Select * from Win32_PnPEntity where Description = "' + $Name + '"' $Device = Get-WmiObject -Query $Query #Выполняем только, если девайс присутствует в системе if ($Device) { #Берем информацию о нём $DeviceKey = "HKLM:\SYSTEM\CurrentControlSet\Enum\" + $Device.DeviceID $PortKey = "HKLM:\SYSTEM\CurrentControlSet\Enum\" + $Device.DeviceID + "\Device Parameters" $Port = get-itemproperty -path $PortKey -Name PortName $OldPort = [convert]::ToInt32(($Port.PortName).Replace("COM","")) #Выставляем новое значение порта и обновляем имя $FriendlyName = $Name + " (" + $NewPort + ")" New-ItemProperty -Path $PortKey -Name "PortName" -PropertyType String -Value $NewPort -Force New-ItemProperty -Path $DeviceKey -Name "FriendlyName" -PropertyType String -Value $FriendlyName -Force #освобождаем старый порт из ComDB $Byte = ($OldPort - ($OldPort % 8))/8 $Bit = 8 - ($OldPort % 8) if ($Bit -eq 8) { $Bit = 0 $Byte = $Byte - 1 } $ComDB = get-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\COM Name Arbiter" -Name ComDB $ComBinaryArray = ([convert]::ToString($ComDB.ComDB[$Byte],2)).ToCharArray() while ($ComBinaryArray.Length -ne 8) { $ComBinaryArray = ,"0" + $ComBinaryArray } $ComBinaryArray[$Bit] = "0" $ComBinary = [string]::Join("",$ComBinaryArray) $ComDB.ComDB[$Byte] = [convert]::ToInt32($ComBinary,2) Set-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\COM Name Arbiter" -Name ComDB -Value ([byte[]]$ComDB.ComDB) } } Change-ComPort $DeviceName $ComPort Да, разумеется, права на исполнение понадобятся, в зависимости от того, как выставлены разрешения на указанные в скрипте ветки реестра.

Ответ 2



Благодарю Виктора Томилова за ответ, но у меня получилось сделать таким образом: Win32_PnPEntity WHERE ClassGuid="{4d36e978-e325-11ce-bfc1-08002be10318}" Такой запрос возвращает имена всех COM устройств, у которых в названии система прописывает номер COM-порта, остаётся только найти нужное устройство по имени и достать от туда номер порта. Вот регулярка для взятия порта из текста, если кому надо: COM\d{1,}

Комментариев нет:

Отправить комментарий