《Windows via C/C++》学习笔记 —— 设备I/O之“设备的打开和关闭”
设备的输入输出,即设备I/O,可以分为“同步”和“异步”两种方式。同步的设备I/O,调用的API函数总是等到设备I/O完成才返回。而异步的设备I/O,可以通过多种方法来实现,但是其根本原理是得到“设备I/O的完成通知”。
本篇主要讨论如何打开和关闭一个设备。注意,这里的设备,不是指像键盘、显示器那种实体。而是一种抽象的概念,指一种与外界通信的对象,可以接受外界的输入,也可以对外界的请求作出响应,称之为设备I/O。这个概念比较抽象,这些设备往往和某个内核对象关联。要打开这些设备,就要创建相关的内核对象。
这些设备包括文件、目录、逻辑磁盘驱动、物理磁盘驱动、串行端口、并行端口、邮槽、管道、套接字、控制台(如下表):
设备 |
主要用途 |
---|---|
文件 |
保存数据 |
目录 |
属性和文件压缩设置 |
逻辑磁盘驱动 |
磁盘格式化 |
物理磁盘驱动 |
访问分区表 |
串行端口 |
串行传输数据 |
并行端口 |
多位数据同时传输,主要是将数据传输给打印机 |
邮槽 |
一对多传输数据,往往适用于一个网络中的一台计算机向其他机器发送数据 |
命名管道 |
一对一传输数据,往往适用于一个网络中的一台计算机向其他机器发送数据 |
匿名管道 |
一对一传输数据,适用于简单的数据传输,不适用于网络 |
套接字 |
以流或数据报的形式发送数据,适用于一个网络中的通信 |
控制台 |
一个文字窗口显示缓冲区 |
要使用这些设备,你首先应该打开这些设备。
Windows努力隐藏这些设备的差异,所以,很多设备的打开的I/O工作可以通过同一个API函数完成,如下表:
设备 |
经常用来打开设备的API函数和用法 |
---|---|
文件 |
CreateFile —— 打开设备的函数。 将参数pszName是一个文件路径名。 |
目录 |
CreateFile —— 打开设备的函数。 将参数pszName是一个目录名。Windows允许你打开一个目录,通过使用参数FILE_ FLAG_BACKUP_SEMANTICS旗标来呼叫CreateFile函数。打开目录之后,就可以这是目录属性,即文件夹属性,比如正常、隐藏、系统、只读等。 |
逻辑磁盘驱动 |
CreateFile —— 打开设备的函数。 将参数pszName设置为字符串“\\.\x:”。 比如要打开C盘,就将其设置为“\\.\C:”。 |
物理磁盘驱动 |
CreateFile —— 打开设备的函数。 将参数pszName设置为“\\.\PHYSICALDRIVEx”。比如打开第一个物理硬盘扇区:可以这么调用CreateFile函数: CreateFile(TEXT("\\.\PHYSICALDRIVE0"), ...); 这样就可以打开一个物理磁盘驱动,并且可以直接访问硬盘分区表。 但是打开物理磁盘驱动是存在潜在危险的,特别是当错误的写入,会造成物理磁盘内容的破坏。 |
串行端口 |
CreateFile —— 打开设备的函数。 将参数pszName设置为“COMx”,比如打开COM1串口设备,只要将其设置为“COM1”。 |
并行端口 |
CreateFile —— 打开设备的函数。 将参数pszName设置为“LPTx”,比如打开LPT1并行端口,将其设置为“LPT1”。 |
邮槽(服务器端) |
CreateMailslot —— 打开设备的函数。 将参数pszName设置为“\\.\mailslot\mailslotname”,其中,“mailsoltname”是为邮槽取的名字,可以任意,前面的字符串是固定的。 |
邮槽(客户端) |
CreateFile —— 打开设备的函数。 将参数pszName设置为“\\servername\mailslot\mailslotname”,其中,“mailsoltname”是为邮槽取的名字,可以任意,前面的字符串是固定的。 |
命名管道 (服务器端) |
CreateFile —— 打开设备的函数。 将参数pszName设置为“\\.\pipe\pipename”,其中,“pipename”是为命名管道取的名字,可以任意,前面的字符串是固定的。 |
命名管道 (客户端) |
CreateFile —— 打开设备的函数。 将参数pszName设置为“\\servername\pipe\pipename”,其中,“pipename”是为命名管道取的名字,可以任意,前面的字符串是固定的。 |
匿名管道 |
CreatePipe —— 打开设备的函数。 无论是客户端还是服务器端都以该函数创建或打开匿名管道。 |
套接字 |
socket —— 创建一个套接字描述符accept, or AcceptEx. |
控制台 Console |
CreateConsoleScreenBuffer,GetStdHandle —— 打开设备的函数 |
从上表可以发现,很多设备都以CreateFile函数来创建和打开。这个函数以后会讲。
打开了设备,你得到了一个设备的句柄,你就可以通过该句柄使用其他函数,来对相关设备进行设置。
比如,现在打开了一个串行端口,然后要设置它的传输波特率:
HANDLE hCommDev,
LPCOMMCONFIG pCC,
DWORD dwSize);
或者,你获得了一个邮槽句柄,可以设置读取数据的等待时间:
HANDLE hMailslot,
DWORD dwReadTimeout);
最后,不要忘记关闭句柄,从而正确地关闭设备:
如果你有了一个设备句柄,你可以调查它的设备类型,通过使用GetFileType函数,该函数的返回值表明了它是一个什么类型的设备,可以参考MSDN。
好了,现在让我们来讨论一下CreateFile函数:
PCTSTR pszName, //指明设备类型或一个特定的设备实体
DWORD dwDesiredAccess, //访问限制
DWORD dwShareMode, //共享方式
PSECURITY_ATTRIBUTES psa, //安全描述结构
DWORD dwCreationDisposition, //创建和打开方式
DWORD dwFlagsAndAttributes, //属性旗标,与缓冲区和文件操作属性有关
HANDLE hFileTemplate); //设备模版,一个设备句柄
该函数成功,返回句柄,失败返回INVALID_HANDLE_VALUE(值为-1)。
如果设置了最后一个参数hFileTemplate,那么就照着这个参数所代表的设备,创建一个属性相同的设备,当然,这个参数所表示的设备要具有“可读”的权限,即有GENERIC_READ访问权限。
至于该函数的具体用法,可以参看本书或MSDN。