第三十二篇 -- CreateFile、ReadFile、WriteFile
这是一个多功能的函数,可打开或创建文件或者I/O设备,并返回可访问的句柄:控制台,通信资源,目录(只读打开),磁盘驱动器,文件,邮槽,管道。
函数原型:
HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);
返回值:
Long,如执行成功,则返回文件句柄。INVALID_HANDLE_VALUE表示出错,会设置GetLastError。即使函数成功,但若文件存在,且指定了CREATE_ALWAYS 或 OPEN_ALWAYS,GetLastError也会设为ERROR_ALREADY_EXISTS
函数声明:
HANDLE CreateFile(LPCTSTR lpFileName, //普通文件名或者设备文件名 DWORD dwDesiredAccess, //访问模式(写/读) DWORD dwShareMode, //共享模式 LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全属性的指针 DWORD dwCreationDisposition, //如何创建 DWORD dwFlagsAndAttributes, //文件属性 HANDLE hTemplateFile //用于复制文件句柄 );
参数说明:
lpFileName String:要打开的文件的名或设备名。
dwDesiredAccess:指定类型的访问对象。GENERIC_READ 表示允许对设备进行读访问,GENERIC_WRITE 表示允许对设备进行写访问(可组合使用);如果为零,表示只允许获取与一个设备有关的信息 。
dwShareMode:Long, 如果是零表示不共享; 如果是FILE_SHARE_DELETE表示随后打开操作对象会成功,但只有删除访问请求的权限;如果是FILE_SHARE_READ随后打开操作对象会成功只有请求读访问的权限;如果是FILE_SHARE_WRITE 随后打开操作对象会成功,但只有请求写访问的权限。
lpSecurityAttributes:SECURITY_ATTRIBUTES, 指向一个SECURITY_ATTRIBUTES结构的指针,定义了文件的安全特性(如果操作系统支持的话)。
dwCreationDisposition:Long,下述常数之一:
CREATE_NEW —— 创建文件;如文件存在则会出错
CREATE_ALWAYS —— 创建文件,会改写前一个文件
OPEN_EXISTING ——文件必须已经存在。由设备提出要求
OPEN_ALWAYS —— 如文件不存在则创建它
TRUNCATE_EXISTING ——将现有文件缩短为零长度
dwFlagsAndAttributes:Long, 一个或多个下述常数:
FILE_ATTRIBUTE_ARCHIVE —— 标记归档属性
FILE_ATTRIBUTE_COMPRESSED —— 将文件标记为已压缩,或者标记为文件在目录中的默认压缩方式
FILE_ATTRIBUTE_NORMAL —— 默认属性
FILE_ATTRIBUTE_HIDDEN —— 隐藏文件或目录
FILE_ATTRIBUTE_READONLY —— 文件为只读
FILE_ATTRIBUTE_SYSTEM —— 文件为系统文件
FILE_FLAG_WRITE_THROUGH —— 操作系统不得推迟对文件的写操作
FILE_FLAG_OVERLAPPED —— 允许对文件进行重叠操作
FILE_FLAG_NO_BUFFERING —— 禁止对文件进行缓冲处理。文件只能写入磁盘卷的扇区块
FILE_FLAG_RANDOM_ACCESS —— 针对随机访问对文件缓冲进行优化
FILE_FLAG_SEQUENTIAL_SCAN —— 针对连续访问对文件缓冲进行优化
FILE_FLAG_DELETE_ON_CLOSE —— 关闭了上一次打开的句柄后,将文件删除。特别适合临时文件
hTemplateFile:hTemplateFile为一个文件或设备句柄,表示按这个参数给出的句柄为模板创建文件(就是将该句柄文件拷贝到lpFileName指定的路径,然后再打开)。它将指定该文件的属性扩展到新创建的文件上面,这个参数可用于将某个新文件的属性设置成与现有文件一样,并且这样会忽略dwAttrsAndFlags。通常这个参数设置为NULL,为空表示不使用模板,一般为空。
误区:
CreateFile的涵义是创建File这个内核对象,而不是创建物理磁盘上的“文件”。在Win32 API中有一系列操作内核对象的函数,创建内核对象的函数大多命名为CreateXxxx型。
举个例子:
CreateFile(TEXT("\\\\.\\NDISUIO"),//设备名称是NDISUIO,跟网络有关的设备 GENERIC_READ | GENERIC_WRITE,//表示可以读写 0,//不共享 NULL,//空指针 OPEN_EXISTING,//文件必须已经存在。由设备提出要求 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,//默认属性或者允许对文件进行重叠操作 NULL);//不使用模板
BOOL DeviceIoControl(HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped );
Parameters(参数)
- hDevice (CreateFile返回的设备句柄)
- [in] Handle to the device that is to perform the operation. To obtain a device handle, call the CreateFile function.
- dwIoControlCode (应用程序调用驱动程序的控制命令,就是IOCTL_XXX IOCTLs )
- [in] IOCTL for the operation. This value identifies the specific operation to perform and the type of device on which to perform the operation. There are no specific values defined for the dwIoControlCode parameter. However, you can define custom IOCTL_XXX IOCTLs with the CTL_CODE macro. You can then advertise these IOCTLs and an application can use these IOCTLs with DeviceIoControl to perform the driver-specific functions.
- lpInBuffer (应用程序传递给驱动程序的数据缓冲区地址)
- [in] Long pointer to a buffer that contains the data required to perform the operation. Set to NULL if the dwIoControlCode parameter specifies an operation that does not require input data.
- nInBufferSize (应用程序传递给驱动程序的数据缓冲区大小,字节数)
- [in] Size, in bytes, of the buffer pointed to by lpInBuffer.
- lpOutBuffer (驱动程序返回给应用程序的数据缓冲区地址)
- [out] Long pointer to a buffer that receives the output data for the operation. Set to NULL if the dwIoControlCode parameter specifies an operation that does not produce output data.
- nOutBufferSize (驱动程序返回给应用程序的数据缓冲区大小,字节数)
- [out] Size, in bytes, of the buffer pointed to by lpOutBuffer.
- lpBytesReturned (驱动程序实际返回给应用程序的数据字节数地址)
- [out] Long pointer to a variable that receives the size, in bytes, of the data stored in lpOutBuffer. The DeviceIoControl function may unnecessarily use this parameter. For example, if an operation does not produce data for lpOutBuffer and lpOutBuffer is NULL, the value of lpBytesReturned is meaningless.
- lpOverlapped (重叠操作结构)
- [in] Ignored; set to NULL.
Return Values(返回值)
Nonzero indicates success. Zero indicates failure. To obtain extended error information, call the GetLastError function. (非0成功,0失败)
例子:向设备传递数据
bool SendKeyData(HANDLE handle, BYTE *bData, int iSize) { ULONG nOutput; BYTE bTemp[512]; //将数据放置到发送数组 memset(bTemp,0,sizeof(bTemp)); memcpy(bTemp,&bData[0],iSize); //向设备发送 if (!DeviceIoControl(handle, ATST2004_IOCTL_WRITE, //根据具体的设备有相关的定义 bTemp, //向设备传递的数据地址 iSize, //数据大小,字节数 NULL, //没有返回的数据,置为NULL 0, //没有返回的数据,置为0 &nOutput, NULL) ) { return false; } return true; }
例子:从设备中读取
bool ReviceKeyData(HANDLE handle, BYTE *bData, int iSize) { ULONG nOutput; BYTE bTemp[512]; //数组清零 memset(bTemp,0,sizeof(bTemp)); //向设备发送 if (!DeviceIoControl(handle, ATST2004_IOCTL_READ, //根据具体的设备有相关的定义 NULL, //没有向设备传递的数据,置为NULL 0, //没有向设备传递的数据,置为NULL bTemp, //读取设备的数据返回地址 iSize, //读取数据的字节数 &nOutput, NULL) ) { return false; } //放置到公用数组 memcpy(&bData[0],&bTemp[0],iSize); return true; }
我们在说DeviceIoControl函数时其第二个参数dwIoControlCode就是由CTL_CODE宏定义的,下边我们可以了解一下CTL_CODE的内容。
#define CTL_CODE(DeviceType, Function, Method, Access) ( ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) )
参数:
DeviceTypeDefines the type of device for the given IOCTL.
This parameter can be no bigger than a WORD value.
The values used by Microsoft are in the range 0-32767; the values 32768-65535 are reserved for use by OEMs and IHVs.
The following device types are defined by the system:
- FILE_DEVICE_BEEP
- FILE_DEVICE_CD_ROM
- FILE_DEVICE_CD_ROM_FILE_SYSTEM
- FILE_DEVICE_CONTROLLER
- FILE_DEVICE_DATALINK
- FILE_DEVICE_DFS
- FILE_DEVICE_DISK
- FILE_DEVICE_DISK_FILE_SYSTEM
- FILE_DEVICE_FILE_SYSTEM
- FILE_DEVICE_INPORT_PORT
- FILE_DEVICE_KEYBOARD
- FILE_DEVICE_MAILSLOT
- FILE_DEVICE_MIDI_IN
- FILE_DEVICE_MIDI_OUT
- FILE_DEVICE_MOUSE
- FILE_DEVICE_MULTI_UNC_PROVIDER
- FILE_DEVICE_NAMED_PIPE
- FILE_DEVICE_NETWORK
- FILE_DEVICE_NETWORK_BROWSER
- FILE_DEVICE_NETWORK_FILE_SYSTEM
- FILE_DEVICE_NULL
- FILE_DEVICE_PARALLEL_PORT
- FILE_DEVICE_PHYSICAL_NETCARD
- FILE_DEVICE_PRINTER
- FILE_DEVICE_SCANNER
- FILE_DEVICE_SERIAL_MOUSE_PORT
- FILE_DEVICE_SERIAL_PORT
- FILE_DEVICE_SCREEN
- FILE_DEVICE_SOUND
- FILE_DEVICE_DEVICE_STREAMS
- FILE_DEVICE_TAPE
- FILE_DEVICE_TAPE_FILE_SYSTEM
- FILE_DEVICE_TRANSPORT
- FILE_DEVICE_UNKNOWN
- FILE_DEVICE_VIDEO
- FILE_DEVICE_VIRTUAL_DISK
- FILE_DEVICE_WAVE_IN
- FILE_DEVICE_WAVE_OUT
- FILE_DEVICE_8042_PORT
- FILE_DEVICE_NETWORK_REDIRECTOR
- FILE_DEVICE_BATTERY
- FILE_DEVICE_BUS_EXTENDER
- FILE_DEVICE_MODEM
- FILE_DEVICE_VDM
- FILE_DEVICE_MASS_STORAGE
- FILE_DEVICE_SMB
- FILE_DEVICE_KS
- FILE_DEVICE_CHANGER
- FILE_DEVICE_SMARTCARD
- FILE_DEVICE_ACPI
- FILE_DEVICE_DVD
- FILE_DEVICE_FULLSCREEN_VIDEO
- FILE_DEVICE_DFS_FILE_SYSTEM
- FILE_DEVICE_DFS_VOLUME
The following device types are specific to Windows CE:
- FILE_DEVICE_HAL
- FILE_DEVICE_CONSOLE
- FILE_DEVICE_PSL
- FILE_DEVICE_SERVICE
Function
Defines an action within the device category.
Function codes 0-2047 are reserved for Microsoft; codes 2048-4095 are reserved for OEMs and IHVs.
A function code can be no larger then 4095.
Method
Defines the method codes for how buffers are passed for I/O and file system controls.
The following values are possible for this parameter:
- METHOD_BUFFERED
- METHOD_IN_DIRECT
- METHOD_OUT_DIRECT
- METHOD_NEITHER
This field is ignored by Windows CE. You should always use the METHOD_BUFFERED value unless compatibility with Windows-based desktop platforms is required using a different Method value.
Access
Defines the access check value for any access.
The following table shows the possible flags for this parameter. The FILE_ACCESS_ANY is generally the correct value.
Flag | Description |
---|---|
FILE_ANY_ACCESS | Request all access. |
FILE_READ_ACCESS | Request read access. Can be used with FILE_WRITE_ACCESS. |
FILE_WRITE_ACCESS | Request write access. Can be used with FILE_READ_ACCESS. |
其中CTL_CODE定义中有一个Method域,该域的功能意义是定义用于与在驱动程序中获取应用程序数据缓冲区的地址方式。Method域就是定义了lpInBuffer 和lpOutBuffer 缓冲区在驱动程序中对这两个缓冲区地址的获取和数据的操作方式。我们分别进行描述:
- METHOD_BUFFERED
系统分配一个缓冲区用于输入和输出,该缓冲区的字节数应该为应用程序的输入和输出缓冲区中较大的字节数。驱动程序中通过KIrp::IoctlBuffer获得缓冲区的地址。对于输出,驱动程序必须将输出字节数返回给I.Information(),然后由I/O管理器将数据从系统缓冲区复制到应用程序的缓冲区中。
- METHOD_IN_DIRECT
- METHOD_OUT_DIRECT
在这两种方式下,输入缓冲区数据被复制到一个系统缓冲区中,驱动程序可以用KIrp::IoctlBuffer访问这个缓冲区。输出缓冲区被类KMemory对象映射,驱动程序可以通过KIrp::Mdl来访问这个缓冲区。
- METHOD_NEITHER
这个比较特殊,一般不使用。
关于DeviceIoControl的第二个参数代表什么,目前还没有查出来,应该与NDISUIO.sys有关,后续会继续查看。
以太网类型字段及值ETHER_TYPE ,类型与含义
Ethertype
( 十六进制 )
协议
0x0000 - 0x05DC
IEEE 802.3 长度
0x0101 – 0x01FF
实验
0x0600
XEROX NS IDP
0x0660
0x0661
DLOG
0x0800
网际协议(IP)
0x0801
X.75 Internet
0x0802
NBS Internet
0x0803
ECMA Internet
0x0804
Chaosnet
0x0805
X.25 Level 3
0x0806
地址解析协议(ARP : Address Resolution Protocol)
0x0808
帧中继 ARP (Frame Relay ARP) [RFC1701]
0x6559
原始帧中继(Raw Frame Relay) [RFC1701]
0x8035
动态 DARP (DRARP:Dynamic RARP)
反向地址解析协议(RARP:Reverse Address Resolution Protocol)
0x8037
Novell Netware IPX
0x809B
EtherTalk
0x80D5
IBM SNA Services over Ethernet
0x 80F 3
AppleTalk 地址解析协议(AARP:AppleTalk Address Resolution Protocol)
0x8100
以太网自动保护开关(EAPS:Ethernet Automatic Protection Switching)
0x8137
因特网包交换(IPX:Internet Packet Exchange)
0x 814C
简单网络管理协议(SNMP:Simple Network Management Protocol)
0x86DD
网际协议v6 (IPv6,Internet Protocol version 6)
0x880B
点对点协议(PPP:Point-to-Point Protocol)
0x 880C
通用交换管理协议(GSMP:General Switch Management Protocol)
0x8847
多协议标签交换(单播) MPLS:Multi-Protocol Label Switching )
0x8848
多协议标签交换(组播)(MPLS, Multi-Protocol Label Switching )
0x8863
以太网上的 PPP(发现阶段)(PPPoE:PPP Over Ethernet )
0x8864
以太网上的 PPP(PPP 会话阶段) (PPPoE,PPP Over Ethernet)
0x88BB
轻量级访问点协议(LWAPP:Light Weight Access Point Protocol)
0x88CC
链接层发现协议(LLDP:Link Layer Discovery Protocol)
0x8E88
局域网上的 EAP(EAPOL:EAP over LAN)
0x9000
配置测试协议(Loopback)
0x9100
VLAN 标签协议标识符(VLAN Tag Protocol Identifier)
0x9200
VLAN 标签协议标识符(VLAN Tag Protocol Identifier)
0xFFFF
保留