【发布时间】:2016-05-15 17:08:39
【问题描述】:
我使用的 C 库需要打开到 COM 端口的 FILE* 才能使用它,但我必须在将其传递给库之前设置端口(连接速度等)。在 Windows 上,这是使用 SetCommState(HANDLE, DCB*) 完成的。
HANDLE 和 FILE* 之间的转换是一个已解决的问题(How make FILE* from HANDLE in WinApi? 和 How do I get the file HANDLE from the fopen FILE structure?),但令人惊讶的是,当应用于通过蓝牙 (RFCOMM/SPP) 获得的 COM 端口时,它会以不同的方式失败。
如果我首先打开一个 HANDLE 并设置 COM 端口参数,_open_osfhandle 对我来说总是失败:
HANDLE qc9200_handle = CreateFile(T("\\\\.\\COM9"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
/* this returns a valid value like 0x30 */
SetCommState(qc9200_handle, &qc9200_dcb); /* also succeeds */
int qc9200_fd = _open_osfhandle((intptr_t)qc9200_handle, _O_RDWR|_O_BINARY);
/* returns -1 and sets errno=EINVAL (22) */
我尝试将各种标志组合从 _O_APPEND(the docs 中提到且对我的应用程序有意义的唯一一个)设置为 _O_RDWR|_O_BINARY(我最初认为应该有效),但 errno 总是EINVAL。
如果我尝试从 FILE* 或 int file_descriptor 开始以稍后从中生成 HANDLE,无论我请求何种访问模式,_topen(path, _O_RDWR|_O_BINARY) 和 _tfopen(path, "r+b") 都会立即失败并设置 errno=EACCES (13),即使我以管理员权限启动我的应用程序。但是,它们不会立即失败,大约需要一秒钟,并且在失败之前我可以看到我的 USB 加密狗上的灯在闪烁。尝试从 Perl 访问 open(COMPORT, "+<", "\\\\.\\COM9") 端口也会失败,并显示“访问被拒绝”。
令人惊讶的是,使用 ProcessMonitor 捕获事件只会向 HKLM\System\CurrentControlSet\Enum\BTHENUM_LOCALMFG\Device parameters\{Port Name, Authenticated, Encrypted} 和一个 IRP_MJ_READ 提供一堆 RegQueryValue 到 %WINDIR%\system32\ucrtbased .dll 而 fopen 在堆栈上。
有问题的 COM 端口是使用普通的 Windows 7 蓝牙设置获得的,并且每个能够使用 COM 端口的终端程序也可以访问它,即使不是以管理员身份运行。当我对虚拟 COM 端口 (com0com) 执行相同操作时,一切都按预期工作;仅当我使用蓝牙 COM 端口时错误仍然存在。
UPD:正如 GetFileType(HANDLE) 所揭示的,蓝牙 COM 端口的句柄不是文件句柄,也不是 GetFileType 知道的任何东西。这就是 C 运行时库拒绝向句柄返回文件描述符的原因,这可能也是 fopen 拒绝打开端口的原因。我必须实现一个类似 fprintf 的函数,它接受 HANDLE 和 #ifdef 并在 Windows 上使用它。
【问题讨论】:
-
尝试弄乱
_open_osfhandle的标志。也许删除_O_RDWR和/或添加_O_APPEND会有所作为。 legacy_ntp 中有一些代码在串行端口上使用_open_osfhandle,尽管它使用_O_TEXT而不是_O_BINARY。一旦你有了一个有效的文件描述符,你就可以使用_fdopen打开一个FILE*(但你已经知道了)。 -
@Ian,无论我尝试使用
_open_osfhandle的什么标志,它总是-1 和EINVAL。就像_open_osfhandle不喜欢我的手柄一样。但是,当CreateFile成功时,为什么 COM 端口上的fopen会失败 - 这是一个真正的谜。为什么open/fopen在我清楚地可以使用任何终端仿真器访问端口时总是返回 EACCES?
标签: c windows file bluetooth rfcomm