Получить FILE*, указывающий на настроенный COM-порт
От: Аноним  
Дата: 04.02.16 20:45
Оценка:
Добрый день!

Библиотека на 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 в такой же ситуации завершается успешно.

Согласно http://stackoverflow.com/questions/5193579/how-make-file-from-handle-in-winapi и http://stackoverflow.com/questions/3989545/how-do-i-get-the-file-handle-from-the-fopen-file-structure, оба преобразования, которые я пытаюсь выполнить, должны сработать.

COM-порт COM9 получен по Bluetooth и совершенно точно работает (с ним работают любые предназначенные для COM-портов терминалки).
Что я делаю не так? Как добиться от системы FILE* с COM-портом?
serial fopen
Re: Получить FILE*, указывающий на настроенный COM-порт
От: ononim  
Дата: 05.02.16 08:44
Оценка:
А>int qc9200_fd = _open_osfhandle((intptr_t)qc9200_handle, _O_RDWR|_O_BINARY);
я бы написал не _O_RDWR, а _O_APPEND
Как много веселых ребят, и все делают велосипед...
Re[2]: Получить FILE*, указывающий на настроенный COM-порт
От: aitap  
Дата: 05.02.16 12:51
Оценка:
Здравствуйте, ononim, Вы писали:

А>>int qc9200_fd = _open_osfhandle((intptr_t)qc9200_handle, _O_RDWR|_O_BINARY);

O>я бы написал не _O_RDWR, а _O_APPEND

Я пробовал даже указывать только _O_APPEND, потому что это единственный хоть как-то подходящий мне флаг из описанных на https://msdn.microsoft.com/en-us/library/bdts1c9x.aspx, но всё равно получил -1 и errno=22.

Подсмотрел Process Monitor'ом: в течение работы fopen(device, "r+b") процесс только открывает пачку ключей реестра по адресам HKLM\System\CurrentControlSet\Enum\BTHENUM\<здесь GUID>_LOCALMFG<MAC-адреса и другие идентификаторы>. Лог не особо интересен: http://pastebin.com/6zn8XbJg

Лог в формате Process Monitor, со стеками: http://rghost.ru/77rFmrCJm
Отредактировано 05.02.2016 13:24 aitap . Предыдущая версия . Еще …
Отредактировано 05.02.2016 13:03 aitap . Предыдущая версия .
Re[3]: Получить FILE*, указывающий на настроенный COM-порт
От: ononim  
Дата: 05.02.16 16:18
Оценка:
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 еще каких проверок понатыкали
Как много веселых ребят, и все делают велосипед...
Отредактировано 05.02.2016 16:19 ononim . Предыдущая версия .
Re: Получить FILE*, указывающий на настроенный COM-порт
От: Pavel Dvorkin Россия  
Дата: 05.02.16 17:57
Оценка:
Здравствуйте, Аноним, Вы писали:


А>FILE* qc9200 = _tfopen(path, "r+b");


Что передаешь в path ? То же, что и в CreateFile, то есть TEXT("\\\\.\\COM9") ? Если да, то зря — библиотеке С это не нужно.

У меня вот такое работает

FILE * f = fopen("com1", "r+b");
With best regards
Pavel Dvorkin
Re[2]: Получить FILE*, указывающий на настроенный COM-порт
От: ononim  
Дата: 05.02.16 18:03
Оценка:
А>>FILE* qc9200 = _tfopen(path, "r+b");
PD>Что передаешь в path ? То же, что и в CreateFile, то есть TEXT("\\\\.\\COM9") ? Если да, то зря — библиотеке С это не нужно.
PD>У меня вот такое работает
PD> FILE * f = fopen("com1", "r+b");
Такое сработает только для портов с 1го по 4й.
Как много веселых ребят, и все делают велосипед...
Re: Получить FILE*, указывающий на настроенный COM-порт
От: alex_mah Россия www.elsy.ru
Дата: 05.02.16 18:04
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Добрый день!


А>Библиотека на 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-порт
От: alex_mah Россия www.elsy.ru
Дата: 05.02.16 18:12
Оценка: +1
Здравствуйте, 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-порт
От: Pavel Dvorkin Россия  
Дата: 06.02.16 06:51
Оценка:
Здравствуйте, ononim, Вы писали:

PD>> FILE * f = fopen("com1", "r+b");

O>Такое сработает только для портов с 1го по 4й.

Почему ? Вроде symbolic link во всех случаях.
With best regards
Pavel Dvorkin
Re[4]: Получить FILE*, указывающий на настроенный COM-порт
От: ononim  
Дата: 06.02.16 09:48
Оценка: +1
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-порт
От: aitap  
Дата: 07.02.16 17:14
Оценка:
Здравствуйте, alex_mah, Вы писали:
_>По мнению MSDN в _open_osfhandle можно использовать только флаги
_>Твоих флагов в этом списке нет.
_>При этом товарищ вот тут пишет что после переоткрытия дескриптора через _fdopen с нужными флагами, будет работать и запись.

Не спасает. Перепробовал очень много разных комбинаций флагов, но всегда получаю -1 и EINVAL. Как будто ему в моей HANDLE что-то не нравится.

Тем временем, порт приобрёл номер 11 вместо номера 9, так что пользоваться я могу только его полным именем \\.\COM11.

Но почему fopen должен возвращать EACCES? У меня же есть права на доступ к порту, это подтверждают все терминалки, которые я перепробовал.
Re: Получить FILE*, указывающий на настроенный COM-порт
От: aitap  
Дата: 10.02.16 18:09
Оценка:
Провёл опыты с виртуальным COM-портом com0com, и он прекрасно открывается любым из опробованных мной способов.

Что не так с Bluetooth-COM-портами?
Re[2]: Получить FILE*, указывающий на настроенный COM-порт
От: ononim  
Дата: 11.02.16 10:43
Оценка:
A>Провёл опыты с виртуальным COM-портом com0com, и он прекрасно открывается любым из опробованных мной способов.
A>Что не так с Bluetooth-COM-портами?
Есть подозрение что они в душе сокеты. Что говорит GetFileType() на хэндл на такой порт?
Как много веселых ребят, и все делают велосипед...
Re[3]: Получить FILE*, указывающий на настроенный COM-порт
От: aitap  
Дата: 11.02.16 20:14
Оценка:
Здравствуйте, ononim, Вы писали:

A>>Провёл опыты с виртуальным COM-портом com0com, и он прекрасно открывается любым из опробованных мной способов.

A>>Что не так с Bluetooth-COM-портами?
O>Есть подозрение что они в душе сокеты. Что говорит GetFileType() на хэндл на такой порт?

Если я только ничего не путаю,

printf("handle=%d\nGetFileType=%lu\n", handle, GetFileType(handle));

handle=36
GetFileType=0


GetLastError возвращает 0.

FILE_TYPE_UNKNOWN
0x0000

Either the type of the specified file is unknown, or the function failed.


Что происходит?
Отредактировано 11.02.2016 20:18 aitap . Предыдущая версия .
Re[4]: Получить FILE*, указывающий на настроенный COM-порт
От: ononim  
Дата: 12.02.16 17:30
Оценка: 2 (1)
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-порт
От: aitap  
Дата: 13.02.16 10:30
Оценка:
Здравствуйте, ononim, Вы писали:
O>Самое правильное решение тут было бы отказаться от идеи использования FILE *. Но возможны и другие, костыльные и геморройные варианты.

Благодарю! FILE* мне был нужен для vfprintf. Я так понимаю, придётся изобретать свой аналог из StringCbVPrintf и WriteFile?
Re[6]: Получить FILE*, указывающий на настроенный COM-порт
От: ononim  
Дата: 13.02.16 11:29
Оценка:
A>Здравствуйте, ononim, Вы писали:
O>>Самое правильное решение тут было бы отказаться от идеи использования FILE *. Но возможны и другие, костыльные и геморройные варианты.
A>Благодарю! FILE* мне был нужен для vfprintf. Я так понимаю, придётся изобретать свой аналог из StringCbVPrintf и WriteFile?
Это был бы самый правильный вариант, да. При возможности конечно и если очень нужен vfprintf
Как много веселых ребят, и все делают велосипед...
Re[3]: Получить FILE*, указывающий на настроенный COM-порт
От: утпутуук  
Дата: 13.02.16 12:50
Оценка:
Здравствуйте, ononim, Вы писали:

А>>>FILE* qc9200 = _tfopen(path, "r+b");

PD>>Что передаешь в path ? То же, что и в CreateFile, то есть TEXT("\\\\.\\COM9") ? Если да, то зря — библиотеке С это не нужно.
PD>>У меня вот такое работает
PD>> FILE * f = fopen("com1", "r+b");
O>Такое сработает только для портов с 1го по 4й.

До 9ого
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.