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

186
28 февраля 2018, 09:16

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

Answer 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

Да, разумеется, права на исполнение понадобятся, в зависимости от того, как выставлены разрешения на указанные в скрипте ветки реестра.

READ ALSO
Время выполнения программы

Время выполнения программы

Узнаю время работы так:

193
Обнуление строки string

Обнуление строки string

Для того, что бы сделать строку временно пустой, я использую

198
Помогите настроить проект

Помогите настроить проект

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

180
Создание формы на java

Создание формы на java

Нужно создать форму с 2-мя колонками (лэйбл и поле для ввода)Для пользователя должна быть предусмотрена возможность добавлять поля (например,...

239