Библиотека на C требует предоставить ей FILE* от настроенного COM-порта. Для настройки я, естественно, пользуюсь SetCommState, соответственно, мне нужно получить HANDLE. Если я начинаю с HANDLE, попытка получить файловый дескриптор из handle завершается неудачно с errno=22: http://pastebin.com/c1RcVh7D
int qc9200_fd = _open_osfhandle((intptr_t)qc9200_handle, _O_RDWR|_O_BINARY);
Если я начинаю с получения файлового дескриптора:
int qc9200_fd = _topen(path, _O_RDWR|_O_BINARY);
или с FILE*:
FILE* qc9200 = _tfopen(path, "r+b");
они оба с небольшой задержкой возвращают ошибку (-1 и NULL соответственно) и устанавливают errno=13, даже если запускать программу от администратора, хотя CreateFile в такой же ситуации завершается успешно.
COM-порт COM9 получен по Bluetooth и совершенно точно работает (с ним работают любые предназначенные для COM-портов терминалки).
Что я делаю не так? Как добиться от системы FILE* с COM-портом?
Здравствуйте, ononim, Вы писали:
А>>int qc9200_fd = _open_osfhandle((intptr_t)qc9200_handle, _O_RDWR|_O_BINARY); O>я бы написал не _O_RDWR, а _O_APPEND
Подсмотрел Process Monitor'ом: в течение работы fopen(device, "r+b") процесс только открывает пачку ключей реестра по адресам HKLM\System\CurrentControlSet\Enum\BTHENUM\<здесь GUID>_LOCALMFG<MAC-адреса и другие идентификаторы>. Лог не особо интересен: http://pastebin.com/6zn8XbJg
A>Я пробовал даже указывать только _O_APPEND, потому что это единственный хоть как-то подходящий мне флаг из описанных на https://msdn.microsoft.com/en-us/library/bdts1c9x.aspx, но всё равно получил -1 и errno=22. A>Подсмотрел Process Monitor'ом: в течение работы fopen(device, "r+b") процесс только открывает пачку ключей реестра по адресам HKLM\System\CurrentControlSet\Enum\BTHENUM\<здесь GUID>_LOCALMFG<MAC-адреса и другие идентификаторы>. Лог не особо интересен: http://pastebin.com/6zn8XbJg A>Лог в формате Process Monitor, со стеками: http://rghost.ru/77rFmrCJm
Тут подебажить надо бы. Посмотреть что там внутри _open_osfhandle фэйлится. С большего она вроде ничего кроме GetFileType не вызывает для переданного ей хэндла. Но может в новых CRT еще каких проверок понатыкали
Как много веселых ребят, и все делают велосипед...
А>>FILE* qc9200 = _tfopen(path, "r+b"); PD>Что передаешь в path ? То же, что и в CreateFile, то есть TEXT("\\\\.\\COM9") ? Если да, то зря — библиотеке С это не нужно. PD>У меня вот такое работает PD> FILE * f = fopen("com1", "r+b");
Такое сработает только для портов с 1го по 4й.
Как много веселых ребят, и все делают велосипед...
Re: Получить FILE*, указывающий на настроенный COM-порт
Здравствуйте, Аноним, Вы писали:
А>Добрый день!
А>Библиотека на C требует предоставить ей FILE* от настроенного COM-порта. Для настройки я, естественно, пользуюсь SetCommState, соответственно, мне нужно получить HANDLE. Если я начинаю с HANDLE, попытка получить файловый дескриптор из handle завершается неудачно с errno=22: http://pastebin.com/c1RcVh7D
А>int qc9200_fd = _open_osfhandle((intptr_t)qc9200_handle, _O_RDWR|_O_BINARY);
По мнению MSDN в _open_osfhandle можно использовать только флаги
_O_APPEND
Positions a file pointer to the end of the file before every write operation.
_O_RDONLY
Opens the file for reading only.
_O_TEXT
Opens the file in text (translated) mode.
_O_WTEXT
Opens the file in Unicode (translated UTF-16) mode.
Твоих флагов в этом списке нет.
При этом товарищ вот тут пишет что после переоткрытия дескриптора через _fdopen с нужными флагами, будет работать и запись.
Re[3]: Получить FILE*, указывающий на настроенный COM-порт
Здравствуйте, ononim, Вы писали:
А>>>FILE* qc9200 = _tfopen(path, "r+b"); PD>>Что передаешь в path ? То же, что и в CreateFile, то есть TEXT("\\\\.\\COM9") ? Если да, то зря — библиотеке С это не нужно. PD>>У меня вот такое работает PD>> FILE * f = fopen("com1", "r+b"); O>Такое сработает только для портов с 1го по 4й.
Вообще-то по 9-й включительно
Re[3]: Получить FILE*, указывающий на настроенный COM-порт
PD>>> FILE * f = fopen("com1", "r+b"); O>>Такое сработает только для портов с 1го по 4й. PD>Почему ? Вроде symbolic link во всех случаях.
не, дело в том что все эти COM1..9 (как правильно поправил alex_mah, мне почемуто думалось что там только до 4го COMа перечислено), LPT и прочие там NUL — они захардкожены в ntdll!RtlIsDosDeviceName_U, и согласно этому хардкоду kernel32/ntdll преобразуют COM1 в \\.\COM1. Симлинком является последнее, а "COM1" — это просто вот такой вот кейс для компатибилити.
Как много веселых ребят, и все делают велосипед...
Re[2]: Получить FILE*, указывающий на настроенный COM-порт
Здравствуйте, alex_mah, Вы писали: _>По мнению MSDN в _open_osfhandle можно использовать только флаги _>Твоих флагов в этом списке нет. _>При этом товарищ вот тут пишет что после переоткрытия дескриптора через _fdopen с нужными флагами, будет работать и запись.
Не спасает. Перепробовал очень много разных комбинаций флагов, но всегда получаю -1 и EINVAL. Как будто ему в моей HANDLE что-то не нравится.
Тем временем, порт приобрёл номер 11 вместо номера 9, так что пользоваться я могу только его полным именем \\.\COM11.
Но почему fopen должен возвращать EACCES? У меня же есть права на доступ к порту, это подтверждают все терминалки, которые я перепробовал.
Re: Получить FILE*, указывающий на настроенный COM-порт
A>Провёл опыты с виртуальным COM-портом com0com, и он прекрасно открывается любым из опробованных мной способов. A>Что не так с Bluetooth-COM-портами?
Есть подозрение что они в душе сокеты. Что говорит GetFileType() на хэндл на такой порт?
Как много веселых ребят, и все делают велосипед...
Re[3]: Получить FILE*, указывающий на настроенный COM-порт
Здравствуйте, ononim, Вы писали:
A>>Провёл опыты с виртуальным COM-портом com0com, и он прекрасно открывается любым из опробованных мной способов. A>>Что не так с Bluetooth-COM-портами? O>Есть подозрение что они в душе сокеты. Что говорит GetFileType() на хэндл на такой порт?
A>handle=36 A>GetFileType=0
A>GetLastError возвращает 0.
A>
A>FILE_TYPE_UNKNOWN
A>0x0000
A>Either the type of the specified file is unknown, or the function failed.
A>Что происходит?
Происходит то, что тип файл не является ни одним из тех значений, которые умеет выдавать GetFileType. Что вызывает бурное отторжение у CRT, которая так же проверяет тип переданного хэндла при помощи GetFileType. GetFileType использует NtQueryVolumeInformationFile(FileFsDeviceInformation) и что та вернет — определяется драйвером, который файл заимплементил.
Самое правильное решение тут было бы отказаться от идеи использования FILE *. Но возможны и другие, костыльные и геморройные варианты.
Как много веселых ребят, и все делают велосипед...
Re[5]: Получить FILE*, указывающий на настроенный COM-порт
Здравствуйте, ononim, Вы писали: O>Самое правильное решение тут было бы отказаться от идеи использования FILE *. Но возможны и другие, костыльные и геморройные варианты.
Благодарю! FILE* мне был нужен для vfprintf. Я так понимаю, придётся изобретать свой аналог из StringCbVPrintf и WriteFile?
Re[6]: Получить FILE*, указывающий на настроенный COM-порт
A>Здравствуйте, ononim, Вы писали: O>>Самое правильное решение тут было бы отказаться от идеи использования FILE *. Но возможны и другие, костыльные и геморройные варианты. A>Благодарю! FILE* мне был нужен для vfprintf. Я так понимаю, придётся изобретать свой аналог из StringCbVPrintf и WriteFile?
Это был бы самый правильный вариант, да. При возможности конечно и если очень нужен vfprintf
Как много веселых ребят, и все делают велосипед...
Re[3]: Получить FILE*, указывающий на настроенный COM-порт
Здравствуйте, ononim, Вы писали:
А>>>FILE* qc9200 = _tfopen(path, "r+b"); PD>>Что передаешь в path ? То же, что и в CreateFile, то есть TEXT("\\\\.\\COM9") ? Если да, то зря — библиотеке С это не нужно. PD>>У меня вот такое работает PD>> FILE * f = fopen("com1", "r+b"); O>Такое сработает только для портов с 1го по 4й.