toweroff 0 1 августа, 2016 Опубликовано 1 августа, 2016 · Жалоба Ситуация: есть USB-COM устройство. Определить его можно (прочитав VID и PID всех подключенных к компьютеру USB устройств) Также я могу определить все COM-порты компьютера но что-то никак не соображу, как скрестить это дело В общем нужно получить следующее - при подключении устройства (или при старте программы, когда устройство уже подключено) определить, что подключено именно оно, определить, какой номер порта выделен устройству, открыть порт и работать с ним. При извлечении устройства освободить порт и ждать нового подключения Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 35 1 августа, 2016 Опубликовано 1 августа, 2016 · Жалоба Это зависит от операционной системы, но в любоой из двух можно узнать всю информацию об устройстве (она хранится в системе) и перебором найти нужный VID/PID. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 2 1 августа, 2016 Опубликовано 1 августа, 2016 · Жалоба В общем нужно получить следующее - при подключении устройства (или при старте программы, когда устройство уже подключено) определить, что подключено именно оно, определить, какой номер порта выделен устройству, открыть порт и работать с ним. При извлечении устройства освободить порт и ждать нового подключения Вот полный текст функции определения порта по VID и PID. На вход даем VID, PID и пустой список строк. На выходе получаем заполненный список с перечнем доступных портов и результат в виде индекса искомого порта в списке. unit USB_COM_enumeration; interface uses Windows, Classes, SysUtils, JvSetupApi; function EnumerateUsbCom(VID, PID: Integer; Ports: TStrings): Integer; const PortsGUID: TGUID = '{4D36E978-E325-11CE-BFC1-08002BE10318}'; // ports implementation function EnumerateUsbCom(VID, PID: Integer; Ports: TStrings): Integer; var GUID: TGUID; PnPHandle: HDevInfo; // handle на базу данных драйверов, раздел ports i, j: DWORD; DeviceInfoData: SP_DEVINFO_DATA; Err: Integer; RequiredLength: DWORD; DevicePath: string; RegType: DWORD; Name: string; s: string; DevPID: Word; DevVID: Word; RegKey: HKey; begin Ports.Clear; Result := 0; GUID := PortsGUID; // получаем handle на базу данных портов присутствующих в системе // win7 compat: с флагом DIGCF_DEVICEINTERFACE в некоторых компах с семеркой // перечисляются только нативные ком-порты PnPHandle := SetupDiGetClassDevs(@GUID, nil, 0, DIGCF_PRESENT { or DIGCF_DEVICEINTERFACE } ); if PnPHandle = Pointer(INVALID_HANDLE_VALUE) then // не можем открыть базу raise Exception.Create(SysErrorMessage(GetLastError)); try i := 0; // первый порт DeviceInfoData.cbSize := SizeOf(DeviceInfoData); while SetupDiEnumDeviceInfo(PnPHandle, i, DeviceInfoData) do // получаем последовательно порты, пока они есть. begin DevicePath := ''; Name := ''; // получаем размер строчки HardwareID SetupDiGetDeviceRegistryProperty(PnPHandle, DeviceInfoData, SPDRP_HARDWAREID, RegType, nil, 0, RequiredLength); Err := GetLastError; if Err = ERROR_INSUFFICIENT_BUFFER then // только эта ошибка должна возникнуть - все другое - что-то не так begin if Length(Name) < RequiredLength div SizeOf(Char) then // если буфер маленький, то SetLength(Name, RequiredLength div SizeOf(Char)); // устанавливаем размер буфера if not SetupDiGetDeviceRegistryProperty(PnPHandle, DeviceInfoData, SPDRP_HARDWAREID, RegType, @Name[1], RequiredLength, RequiredLength) then // получаем HardwareID begin inc(i); // если ошибка, то смотрим следущий порт Continue; end; end else raise Exception.Create(SysErrorMessage(Err)); Name := UpperCase(Name); // чтобы сравнивать строки, переводим все в заглавные буквы if Copy(Name, 1, 3) = 'USB' then // если первые три символа HardwareID = 'USB' - то это у нас виртуальный порт begin j := pos('VID_', Name) + 4; // ищем где у нас VID s := ''; while Name[j] <> '&' do // получаем VID begin s := s + Name[j]; inc(j); end; DevVID := StrToInt('$' + s); // OutputDebugString(PChar('vid = ' + IntToHex(DevVID, 4))); j := pos('PID_', Name) + 4; // ищем PID s := ''; while (Name[j] <> '&') and (Name[j] <> #0) do // получаем PID begin s := s + Name[j]; inc(j); end; DevPID := StrToInt('$' + s); // OutputDebugString(PChar('pid = ' + IntToHex(DevPID, 4))); if (DevVID = VID) and (DevPID = PID) then // если VID и PID - наши, то begin SetLength(DevicePath, 10); // 10 символов на название ком-порта - хватит (максимальный COM999999 [последний символ = #0]) RegKey := SetupDiOpenDevRegKey(PnPHandle, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); // получаем Handle на раздел реестра экземпляра устройства if RegKey = INVALID_HANDLE_VALUE then begin inc(i); // если ошибка - следущий порт Continue; end; try RequiredLength := 10 * SizeOf(Char); if RegQueryValueEx(RegKey, 'PortName', nil, @RegType, @DevicePath[1], @RequiredLength) <> ERROR_SUCCESS then // в PortName записано название порта (например - СОМ5) begin inc(i); Continue; end; DevicePath := Copy(DevicePath, 1, RequiredLength div SizeOf(Char) - 1); // в RequiredLength - размер полученной строки, минус 1 - последний ноль нам не нужен Ports.Add(DevicePath); // добавлеяем имя порта inc(Result); // результат функции - количество портов для данного VID&PID finally RegCloseKey(RegKey); // Handle надо закрыть, даже в случае ошибки end; end; end; inc(i); // следущий порт end; finally SetupDiDestroyDeviceInfoList(PnPHandle); // освобождаем занятую память. end; end; end. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 0 1 августа, 2016 Опубликовано 1 августа, 2016 · Жалоба Вот полный текст функции определения порта по VID и PID. Спасибо! буду его под CPP перелопачивать Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
arhiv6 14 1 августа, 2016 Опубликовано 1 августа, 2016 · Жалоба Если пишите на C++ можете попробовать библиотеку Qt. Там в составе есть класс QSerialPortInfo - он позволяет получить список доступных в системе портов + кое-какую информацию о них (vid, pid, description): http://doc.qt.io/qt-5/qserialportinfo.html Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 0 2 августа, 2016 Опубликовано 2 августа, 2016 · Жалоба Вот полный текст функции у меня не срабатывает вот это место: while (SetupDiEnumDeviceInfo(PnPHandle, i, &DeviceInfoData)) нет ни одного вхождения в цикл, хотя порт в системе точно есть предваряет это все такая последовательность действий: const TGUID PortsGUID = {0x4D36E978, 0xE325, 0x11CE, {0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18}}; // ports TGUID GUID; GUID = PortsGUID; PnPHandle = ::SetupDiGetClassDevs(&GUID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); UPD GetLastError() == ERROR_NO_MORE_ITEMS Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 0 2 августа, 2016 Опубликовано 2 августа, 2016 · Жалоба убрал DIGCF_DEVICEINTERFACE, оставил только PnPHandle = ::SetupDiGetClassDevs(&GUID, NULL, NULL, DIGCF_PRESENT) и заработало Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1891ВМ12Я 0 29 октября, 2016 Опубликовано 29 октября, 2016 · Жалоба Если пишите на C++ можете попробовать библиотеку Qt. Там в составе есть класс QSerialPortInfo - он позволяет получить список доступных в системе портов + кое-какую информацию о них (vid, pid, description): http://doc.qt.io/qt-5/qserialportinfo.html Это vendorIdentifier/productIdentifier? Не знал что такое есть... А description что пишет? Интересует, можно ли использовать чужой VID/PID но засовывать свой description? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rudy_b 1 31 октября, 2016 Опубликовано 31 октября, 2016 · Жалоба Самые интересные танцы начинаются когда к компу подключено несколько одинаковых устройств USB. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 0 31 октября, 2016 Опубликовано 31 октября, 2016 · Жалоба Самые интересные танцы начинаются когда к компу подключено несколько одинаковых устройств USB. попробовал открыть - не получилось - берем следующий в списке а вот когда встает задача "схватить" некий конкретный девайс - вот тут да... только в какой-то последовательности подключать одинаковые устройства и ждать события подключения Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться